'xArray's to_dataset and global attributes

Suppose I have an xArray dataArray called "mse" with metadata:

<xarray.DataArray 'mse' (time: 248, level: 37, lat: 73, lon: 144)>
array([[[[693757.8 , ...cut...]]]], dtype=float32)
Coordinates:
  * time     (time) datetime64[ns] 1979-01-01 ... 1979-01-31T21:00:00
  * level    (level) float64 1.0 2.0 3.0 5.0 7.0 ... 925.0 950.0 975.0 1e+03
  * lat      (lat) float32 90.0 87.5 85.0 82.5 80.0 ... -82.5 -85.0 -87.5 -90.0
  * lon      (lon) float32 0.0 2.5 5.0 7.5 10.0 ... 350.0 352.5 355.0 357.5
Attributes:
    long_name:                     Moist static energy
    units:                         J/kg

I want to write this dataArray to a netCDF file, but I also want to add a few global attributes to the resulting file. I can write this single dataArray to a netCDF file using mse.to_netCDF(path="./testout.nc", unlimited_dims="time"), but no global attributes appear, as expected. Next, I tried to convert the dataArray to an xArray dataset and then set a new global attribute on that dataset (as follows), but my several attempts all result in errors:

dsMSE = mse.to_dataset
print(dsMSE)  # This results in identical output as above, but with "<bound method DataArray.to_dataset of " prepended to the first line

dsMSE.attrs['test'] = 50          # AttributeError: 'function' object has no attribute 'attrs'
dsMSE.assign_attrs(test='test1')  # AttributeError: 'function' object has no attribute 'attrs'
dsMSE.attrs = {'test': 'test1'}   # AttributeError: 'method' object has no attribute 'attrs'

Stepping back, if I open a separate existing netCDF file, I can easily add to/change its global attributes:

ds = xr.open_dataset(f)
ds.attrs['new'] = 'new1'   # Success, confirmed by printout

Why does dsMSE=mse.to_dataset not result in a viable xArray dataset to which new global attributes can be added (and what does "<bound method..." imply)? I must be missing something. Is there an elegant work-around to this? I'd prefer to avoid having to create a new dataset from scratch (e.g., dsMSE = xr.Dataset(...)) given that I already have the dataArray and its metadata all lined up.



Solution 1:[1]

xr.DataArray.to_dataset is a function, not a property, so you need to call it, e.g.:

dsMSE = mse.to_dataset(name='mse')

The clue is when you print mse.to_dataset you got the title <bound method Array.to_dataset of [dataset repr]> - this is actually telling you that you don't have a dataset; instead you have a method of the DataArray. Essentially, you printed a function :)

dsMSE = mse.to_dataset
print(dsMSE)  # This results in identical output as above, but with "<bound method DataArray.to_dataset of " prepended to the first line

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Michael Delgado