ajdawson / eofs

EOF analysis in Python
http://ajdawson.github.io/eofs/
GNU General Public License v3.0
199 stars 60 forks source link

eofs.xarray.Eof behaves unexpectedly when provided a DataArray with a coordinate called 'mode' #126

Open joshdorrington opened 2 years ago

joshdorrington commented 2 years ago

Hi,

I admit that the following issue is a bit pathological, and you may decide it is not worth doing anything about, but I thought I would flag it anyway.

I found myself in the position of wanting to apply PCA to the product space of the principal components of two separate fields:

import xarray as xr
from eofs.xarray import Eof

Z500_pcs=xr.open_dataarray('DJF_Z500_PCs.nc')
MSLP_pcs=xr.open_dataarray('DJF_MSLP_PCs.nc')

combined_pcs=xr.concat([Z500_pcs,MSLP_pcs],'mode')
solver=Eof(combined_pcs)

print(solver.eofs().shape)
print(solver.eofs()[0].shape)
print(solver.eofs()[0][0][0][0][0].shape)
(13, 13)
(13, 13)
(13, 13)
solver.eofs(neofs=3)
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_9504/46481902.py in <module>
----> 1 solver.eofs(neofs=3)

~/miniconda3/lib/python3.9/site-packages/eofs/xarray.py in eofs(self, eofscaling, neofs)
    227         eofs = xr.DataArray(eofs, coords=coords, name='eofs',
    228                             attrs={'long_name': long_name})
--> 229         eofs.coords.update({coord.name: (coord.dims, coord)
    230                             for coord in self._space_ndcoords})
    231         return eofs

~/miniconda3/lib/python3.9/site-packages/xarray/core/coordinates.py in update(self, other)
    164             [self.variables, other_vars], priority_arg=1, indexes=self.xindexes
    165         )
--> 166         self._update_coords(coords, indexes)
    167 
    168     def _merge_raw(self, other, reflexive):

~/miniconda3/lib/python3.9/site-packages/xarray/core/coordinates.py in _update_coords(self, coords, indexes)
    340         coords_plus_data = coords.copy()
    341         coords_plus_data[_THIS_ARRAY] = self._data.variable
--> 342         dims = calculate_dimensions(coords_plus_data)
    343         if not set(dims) <= set(self.dims):
    344             raise ValueError(

~/miniconda3/lib/python3.9/site-packages/xarray/core/dataset.py in calculate_dimensions(variables)
    203                 last_used[dim] = k
    204             elif dims[dim] != size:
--> 205                 raise ValueError(
    206                     f"conflicting sizes for dimension {dim!r}: "
    207                     f"length {size} on {k!r} and length {dims[dim]} on {last_used!r}"

ValueError: conflicting sizes for dimension 'mode': length 3 on <this-array> and length 13 on {'mode': 'mode'}

All these errors vanish when I add the following line:

combined_pcs=combined_pcs.rename({'mode':'original_mode'})

Maybe a warning, or an automatic renaming if an array with a coordinate named 'mode' is passed to Eof would be appropriate?