pydata / pydata/xarray

TypeError: '_ElementwiseFunctionArray' object does not support item assignment

Open
#6,015 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-backends
Dominant language
Python
Stars
4.2k
Forks
1.4k
Avg merge
2d 15h
Merged PRs (30d)
14

Description

What happened:
I am attempting to mask specific time_bnds coordinate points using loc, but am receiving TypeError: '_ElementwiseFunctionArray' object does not support item assignment.

This happens with datasets that have encoded (raw) time coordinates, then decoding with xr.decode_cf() before attempting to mask the time_bnds.

What you expected to happen:

The time_bnds coordinate points selected using .loc should mask properly

Minimal Complete Verifiable Example:

MVCE 1 -- breaks with encoded time coordinates then decoded using xr.decode_cf()

import numpy as np
import xarray as xr

time_encoded = xr.DataArray(
    name="time",
    data=[675348.5, 675378.0, 675407.5],
    dims=["time"],
    attrs={
        "bounds": "time_bnds",
        "units": "days since 0001-01-01",
        "calendar": "proleptic_gregorian",
        "axis": "T",
        "long_name": "time",
        "standard_name": "time",
    },
)
time_bnds_encoded = xr.DataArray(
    name="time_bnds",
    data=[[675333.0, 675364.0], [675364.0, 675392.0], [675392.0, 675423.0]],
    dims=["time", "bnds"],
)

ds = xr.Dataset(
    coords={"time": time_encoded}, data_vars={"time_bnds": time_bnds_encoded}
)
ds = xr.decode_cf(ds, decode_times=True)
ds["time_bnds"].loc[dict(time="1850-01")] = np.nan

MVCE 2 -- works fine with decoded time coordinates


import cftime
import numpy as np
import xarray as xr

time_decoded = xr.DataArray(
    name="time",
    data=np.array(
        [
            cftime.DatetimeProlepticGregorian(
                1850, 1, 16, 12, 0, 0, 0, has_year_zero=True
            ),
            cftime.DatetimeProlepticGregorian(
                1850, 2, 15, 0, 0, 0, 0, has_year_zero=True
            ),
            cftime.DatetimeProlepticGregorian(
                1850, 3, 16, 12, 0, 0, 0, has_year_zero=True
            ),
        ],
        dtype="object",
    ),
    dims=["time"],
    attrs={
        "bounds": "time_bnds",
        "axis": "T",
        "long_name": "time",
        "standard_name": "time",
    },
)
time_decoded.encoding = {
    "units": "days since 0001-01-01",
    "calendar": "proleptic_gregorian",
}
time_bnds_decoded = xr.DataArray(
    dims=["time", "bnds"],
    data=[
        [np.nan, np.nan],
        [
            cftime.DatetimeProlepticGregorian(
                1850, 2, 1, 0, 0, 0, 0, has_year_zero=True
            ),
            cftime.DatetimeProlepticGregorian(
                1850, 3, 1, 0, 0, 0, 0, has_year_zero=True
            ),
        ],
        [
            cftime.DatetimeProlepticGregorian(
                1850, 3, 1, 0, 0, 0, 0, has_year_zero=True
            ),
            cftime.DatetimeProlepticGregorian(
                1850, 4, 1, 0, 0, 0, 0, has_year_zero=True
            ),
        ],
    ],
)

ds = xr.Dataset(
    coords={"time": time_decoded}, data_vars={"time_bnds": time_bnds_decoded}
)
ds["time_bnds"].loc[dict(time="1850-01")] = np.nan

Anything else we need to know?:

The workaround is to perform .load() after xr.decode_cf()

import numpy as np
import xarray as xr

time_encoded = xr.DataArray(
    name="time",
    data=[675348.5, 675378.0, 675407.5],
    dims=["time"],
    attrs={
        "bounds": "time_bnds",
        "units": "days since 0001-01-01",
        "calendar": "proleptic_gregorian",
        "axis": "T",
        "long_name": "time",
        "standard_name": "time",
    },
)
time_bnds_encoded = xr.DataArray(
    name="time_bnds",
    data=[[675333.0, 675364.0], [675364.0, 675392.0], [675392.0, 675423.0]],
    dims=["time", "bnds"],
)

ds = xr.Dataset(
    coords={"time": time_encoded}, data_vars={"time_bnds": time_bnds_encoded}
)
ds = xr.decode_cf(ds, decode_times=True)
ds.load()
ds["time_bnds"].loc[dict(time="1850-01")] = np.nan

Log Output

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
File /Users/vo13/repositories/xcdat/qa/xr_6015.py:27
     [23](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xcdat/qa/xr_6015.py:23) ds = xr.Dataset(
     [24](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xcdat/qa/xr_6015.py:24)     coords={"time": time_encoded}, data_vars={"time_bnds": time_bnds_encoded}
     [25](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xcdat/qa/xr_6015.py:25) )
     [26](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xcdat/qa/xr_6015.py:26) ds = xr.decode_cf(ds, decode_times=True)
---> [27](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xcdat/qa/xr_6015.py:27) ds["time_bnds"].loc[dict(time="1850-01")] = np.nan

File /opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:246, in _LocIndexer.__setitem__(self, key, value)
    [243](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:243)     key = dict(zip(self.data_array.dims, labels))
    [245](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:245) dim_indexers = map_index_queries(self.data_array, key).dim_indexers
--> [246](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:246) self.data_array[dim_indexers] = value

File /opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:892, in DataArray.__setitem__(self, key, value)
    [887](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:887) # DataArray key -> Variable key
    [888](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:888) key = {
    [889](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:889)     k: v.variable if isinstance(v, DataArray) else v
    [890](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:890)     for k, v in self._item_key_to_dict(key).items()
    [891](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:891) }
--> [892](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/dataarray.py:892) self.variable[key] = value

File /opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/variable.py:866, in Variable.__setitem__(self, key, value)
    [863](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/variable.py:863)     value = np.moveaxis(value, new_order, range(len(new_order)))
    [865](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/variable.py:865) indexable = as_indexable(self._data)
--> [866](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/variable.py:866) indexing.set_with_indexer(indexable, index_tuple, value)

File /opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:1012, in set_with_indexer(indexable, indexer, value)
   [1010](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:1010)     indexable.oindex[indexer] = value
   [1011](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:1011) else:
-> [1012](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:1012)     indexable[indexer] = value

File /opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:660, in LazilyIndexedArray.__setitem__(self, key, value)
    [658](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:658) self._check_and_raise_if_non_basic_indexer(key)
    [659](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:659) full_key = self._updated_key(key)
--> [660](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/xarray/core/indexing.py:660) self.array[full_key] = value

TypeError: '_ElementwiseFunctionArray' object does not support item assignment

Environment:

Output of xr.show_versions()

INSTALLED VERSIONS

commit: None
python: 3.11.9 | packaged by conda-forge | (main, Apr 19 2024, 18:34:54) [Clang 16.0.6 ]
python-bits: 64
OS: Darwin
OS-release: 22.6.0
machine: arm64
processor: arm
byteorder: little
LC_ALL: None
LANG: None
LOCALE: (None, 'UTF-8')
libhdf5: 1.14.3
libnetcdf: 4.9.2

xarray: 2024.3.0
pandas: 2.2.2
numpy: 1.26.4
scipy: 1.13.0
netCDF4: 1.6.5
pydap: None
h5netcdf: None
h5py: None
Nio: None
zarr: None
cftime: 1.6.3
nc_time_axis: 1.4.1
iris: None
bottleneck: None
dask: 2024.4.2
distributed: 2024.4.2
matplotlib: 3.8.4
cartopy: None
seaborn: None
numbagg: None
fsspec: 2024.3.1
cupy: None
pint: None
sparse: 0.15.1
flox: None
numpy_groupies: None
setuptools: 69.5.1
pip: 24.0
conda: None
pytest: 8.2.0
mypy: 1.4.0
IPython: 8.22.2
sphinx: 7.3.7
/opt/miniconda3/envs/xcdat_dev/lib/python3.11/site-packages/_distutils_hack/init.py:26: UserWarning: Setuptools is replacing distutils.
warnings.warn("Setuptools is replacing distutils.")

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the two minimal examples around xr.decode_cf(), DataArray.loc assignment, and the traceback through xarray's indexing path. Confirm that the encoded-time case fails before load() and the decoded case succeeds; done means the encoded-time assignment works without requiring load(), with a regression test for the reported example.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, python
Domain
data
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.