Repository: ARM-DOE/ACT

Issue:
Attributes on coordinate variable dropped after applying qcfilter.add_test() to data variable
After applying `ds.qcfilter.add_test()` to a data variable, the attributes on the coordinate variable dimensioning the tested variable are removed. This happens for act-atmos versions 1.0.2 and 1.0.3, but not 0.7.2 and before. 

Steps to reproduce below:

`act-test.py`:
```
import act
import numpy as np
import xarray as xr
import pandas as pd


print(f"{act.__version__ = }")
print(f"{xr.__version__ = }")

ds = xr.Dataset(
    data_vars=dict(dummy_data=(['time'], np.arange(0, 7))),
    coords=dict(time=pd.date_range("2021-07-12 00:00:00", periods=7))
)
ds.time.attrs['units'] = "seconds since 1970-01-01T00:00:00"
ds.time.attrs['standard_name'] = "time"
ds.time.attrs['long_name'] = "time (UTC)"

print(f"Initially ds.time.attrs = {ds.time.attrs = }")

ds.qcfilter.add_test(
    "dummy_data", index=np.full_like(ds.dummy_data.data, True),
    test_number=1,
    test_meaning="Example qc test",
    test_assessment="Bad")

print(f"After qcfilter {ds.time.attrs = }")
```

Console:
```
>>> conda create --name act-test python=3.8
>>> conda activate act-test
>>> (act-test) pip install act-atmos==1.0.3
>>> (act-test) python act-test.py
act.__version__ = '1.0.3'
xr.__version__ = '0.18.2'
Initially ds.time.attrs = {'units': 'seconds since 1970-01-01T00:00:00', 'standard_name': 'time', 'long_name': 'time (UTC)'}
After qcfilter ds.time.attrs = {}
```

Attributes on coordinate variable dropped after applying qcfilter.add_test() to data variable
After applying `ds.qcfilter.add_test()` to a data variable, the attributes on the coordinate variable dimensioning the tested variable are removed. This happens for act-atmos versions 1.0.2 and 1.0.3, but not 0.7.2 and before. 

Steps to reproduce below:

`act-test.py`:
```
import act
import numpy as np
import xarray as xr
import pandas as pd


print(f"{act.__version__ = }")
print(f"{xr.__version__ = }")

ds = xr.Dataset(
    data_vars=dict(dummy_data=(['time'], np.arange(0, 7))),
    coords=dict(time=pd.date_range("2021-07-12 00:00:00", periods=7))
)
ds.time.attrs['units'] = "seconds since 1970-01-01T00:00:00"
ds.time.attrs['standard_name'] = "time"
ds.time.attrs['long_name'] = "time (UTC)"

print(f"Initially ds.time.attrs = {ds.time.attrs = }")

ds.qcfilter.add_test(
    "dummy_data", index=np.full_like(ds.dummy_data.data, True),
    test_number=1,
    test_meaning="Example qc test",
    test_assessment="Bad")

print(f"After qcfilter {ds.time.attrs = }")
```

Console:
```
>>> conda create --name act-test python=3.8
>>> conda activate act-test
>>> (act-test) pip install act-atmos==1.0.3
>>> (act-test) python act-test.py
act.__version__ = '1.0.3'
xr.__version__ = '0.18.2'
Initially ds.time.attrs = {'units': 'seconds since 1970-01-01T00:00:00', 'standard_name': 'time', 'long_name': 'time (UTC)'}
After qcfilter ds.time.attrs = {}
```



Discussion:
Thanks @maxwellevin for reporting this!  We will take a look.  Pinging @kenkehoe as well
@AdamTheisen sure thing – happy to help. We're using `act` pretty heavily over at https://github.com/tsdat/tsdat and discovered this bug after one of our users noted an issue. I've done a bit more digging into this issue since I posted it and I am pretty certain it is occurring in `create_qc_variable()` function in `act.qcfilter`, lines 165-169:
```
self._obj[qc_var_name] = xr.DataArray(
            data=qc_data, dims=self._obj[var_name].dims,
            attrs={"long_name": qc_variable_long_name,
                   "units": '1'}
        )
```

before this block I see that `self._obj.time.attrs` is 
```
{'units': 'seconds since 1970-01-01T00:00:00', 'standard_name': 'time', 'long_name': 'time (UTC)'}
```

and afterwards it is 
```
{}
```

I tried stopping here in the debugger and found that adding any dummy variable dimensioned by `time` to `self._obj` removes the attributes on the `time` variable. Adding a variable with a different coordinate dimension does not affect the attributes of the `time` variable, but it does remove the attributes of the new coordinate variable. 
I'm thinking this is actually an Xarray issue. See below:

xr-test.py
```
import xarray as xr
print(f"{xr.__version__ = }")

ds = xr.Dataset(coords={'a': [1]})
ds['a'].attrs['att'] = 'example attr'
print(ds.a.attrs)

da = xr.DataArray([2], dims=['a'])
ds['b'] = da
print(ds.a.attrs)
```

console:
```
>>> pip install xarray
>>> python3 xr-test.py
xr.__version__ = '0.18.2'
{'att': 'example attr'}
{}
```
Thanks @maxwellevin for reporting this!  We will take a look.  Pinging @kenkehoe as well
@AdamTheisen sure thing – happy to help. We're using `act` pretty heavily over at https://github.com/tsdat/tsdat and discovered this bug after one of our users noted an issue. I've done a bit more digging into this issue since I posted it and I am pretty certain it is occurring in `create_qc_variable()` function in `act.qcfilter`, lines 165-169:
```
self._obj[qc_var_name] = xr.DataArray(
            data=qc_data, dims=self._obj[var_name].dims,
            attrs={"long_name": qc_variable_long_name,
                   "units": '1'}
        )
```

before this block I see that `self._obj.time.attrs` is 
```
{'units': 'seconds since 1970-01-01T00:00:00', 'standard_name': 'time', 'long_name': 'time (UTC)'}
```

and afterwards it is 
```
{}
```

I tried stopping here in the debugger and found that adding any dummy variable dimensioned by `time` to `self._obj` removes the attributes on the `time` variable. Adding a variable with a different coordinate dimension does not affect the attributes of the `time` variable, but it does remove the attributes of the new coordinate variable. 
I'm thinking this is actually an Xarray issue. See below:

xr-test.py
```
import xarray as xr
print(f"{xr.__version__ = }")

ds = xr.Dataset(coords={'a': [1]})
ds['a'].attrs['att'] = 'example attr'
print(ds.a.attrs)

da = xr.DataArray([2], dims=['a'])
ds['b'] = da
print(ds.a.attrs)
```

console:
```
>>> pip install xarray
>>> python3 xr-test.py
xr.__version__ = '0.18.2'
{'att': 'example attr'}
{}
```

Resolving patch:
diff --git a/act/qc/qcfilter.py b/act/qc/qcfilter.py
--- a/act/qc/qcfilter.py
+++ b/act/qc/qcfilter.py
@@ -162,8 +162,10 @@ def create_qc_variable(self, var_name, flag_type=False,
         except AttributeError:
             qc_data = np.zeros_like(self._obj[var_name].values, dtype=np.int32)
 
+        # Updating to use coords instead of dim, which caused a loss of
+        # attribuets as noted in Issue 347
         self._obj[qc_var_name] = xr.DataArray(
-            data=qc_data, dims=self._obj[var_name].dims,
+            data=qc_data, coords=self._obj[var_name].coords,
             attrs={"long_name": qc_variable_long_name,
                    "units": '1'}
         )


Test patch: