diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 7b9b3263a3d..2617dee17bf 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -32,12 +32,13 @@ Bug Fixes ~~~~~~~~~ - Fix h5netcdf backend for format=None, use same rule as netcdf4 backend (:pull:`10859`). By `Kai Mühlbauer `_ - - ``netcdf4`` and ``pydap`` backends now use stricter URL detection to avoid incorrectly claiming remote URLs. The ``pydap`` backend now only claims URLs with explicit DAP protocol indicators (``dap2://`` or ``dap4://`` schemes, or ``/dap2/`` or ``/dap4/`` in the URL path). This prevents both backends from claiming remote Zarr stores and other non-DAP URLs without an explicit ``engine=`` argument. (:pull:`10804`). By `Ian Hunt-Isaak `_. +- Fix indexing with empty arrays for scipy & h5netcdf backends which now resolves to empty slices (:issue:`10867`, :pull:`10870`). + By `Kai Mühlbauer `_ Documentation ~~~~~~~~~~~~~ diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index e238599c3f8..e40226793a2 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -1366,7 +1366,7 @@ def _decompose_outer_indexer( gains = [ ( (np.max(k) - np.min(k) + 1.0) / len(np.unique(k)) - if isinstance(k, np.ndarray) + if isinstance(k, np.ndarray) and k.size != 0 else 0 ) for k in indexer_elems @@ -1374,7 +1374,11 @@ def _decompose_outer_indexer( array_index = np.argmax(np.array(gains)) if len(gains) > 0 else None for i, (k, s) in enumerate(zip(indexer_elems, shape, strict=False)): - if isinstance(k, np.ndarray) and i != array_index: + if isinstance(k, np.ndarray) and k.size == 0: + # empty np.ndarray key is converted to empty slice + # see https://github.com/pydata/xarray/issues/10867 + backend_indexer.append(slice(0, 0)) + elif isinstance(k, np.ndarray) and i != array_index: # np.ndarray key is converted to slice that covers the entire # entries of this key. backend_indexer.append(slice(np.min(k), np.max(k) + 1)) diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 133b71927ea..36a1e354d9c 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -986,6 +986,15 @@ def test_isel_dataarray(self) -> None: actual = on_disk.isel(dim2=on_disk["dim2"] < 3) assert_identical(expected, actual) + def test_empty_isel(self) -> None: + # Make sure isel works lazily with empty indexer. + # GH:issue:10867 + in_memory = xr.Dataset({"a": ("x", np.arange(4))}, coords={"x": np.arange(4)}) + with self.roundtrip(in_memory) as on_disk: + expected = in_memory.isel(x=[]) + actual = on_disk.isel(x=[]) + assert_identical(expected, actual) + def validate_array_type(self, ds): # Make sure that only NumpyIndexingAdapter stores a bare np.ndarray. def find_and_validate_array(obj):