From f0035e805fc091999906996d340b97535443b623 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Mon, 30 Jun 2025 12:42:25 +0200 Subject: [PATCH 1/2] fix RangeIndex slicing --- xarray/indexes/range_index.py | 4 ++-- xarray/tests/test_range_index.py | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/xarray/indexes/range_index.py b/xarray/indexes/range_index.py index 2b9a5e5071a..5e097db9b9e 100644 --- a/xarray/indexes/range_index.py +++ b/xarray/indexes/range_index.py @@ -84,9 +84,9 @@ def slice(self, sl: slice) -> "RangeCoordinateTransform": # TODO: support reverse transform (i.e., start > stop)? assert sl.start < sl.stop - new_size = (sl.stop - sl.start) // sl.step + new_size = (sl.stop - sl.start - 1) // sl.step + 1 new_start = self.start + sl.start * self.step - new_stop = new_start + new_size * sl.step * self.step + new_stop = min(new_start + new_size * sl.step * self.step, self.stop) return type(self)( new_start, new_stop, new_size, self.coord_name, self.dim, dtype=self.dtype diff --git a/xarray/tests/test_range_index.py b/xarray/tests/test_range_index.py index 05bf4b3172e..a999c938300 100644 --- a/xarray/tests/test_range_index.py +++ b/xarray/tests/test_range_index.py @@ -121,6 +121,12 @@ def test_range_index_isel() -> None: expected = create_dataset_arange(0.0, 1.0, 0.2) assert_identical(actual, expected, check_default_indexes=False) + # https://github.com/pydata/xarray/issues/10441 + ds2 = create_dataset_arange(0.0, 3.0, 0.1) + actual = ds2.isel(x=slice(4, None, 3)) + expected = create_dataset_arange(0.4, 3.0, 0.3) + assert_identical(actual, expected, check_default_indexes=False) + # scalar actual = ds.isel(x=0) expected = xr.Dataset(coords={"x": 0.0}) From ea6742cac4cb16f3b1a68f2f01076e5bda6a95a2 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 1 Jul 2025 09:42:04 +0200 Subject: [PATCH 2/2] slicing impl: rely on `range` This also enables support for reverse slicing (added tests) --- xarray/indexes/range_index.py | 14 +++++--------- xarray/tests/test_range_index.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/xarray/indexes/range_index.py b/xarray/indexes/range_index.py index 5e097db9b9e..34e6c2f7c00 100644 --- a/xarray/indexes/range_index.py +++ b/xarray/indexes/range_index.py @@ -9,7 +9,7 @@ from xarray.core.coordinate_transform import CoordinateTransform from xarray.core.dataarray import DataArray from xarray.core.indexes import CoordinateTransformIndex, Index, PandasIndex -from xarray.core.indexing import IndexSelResult, normalize_slice +from xarray.core.indexing import IndexSelResult from xarray.core.variable import Variable @@ -79,14 +79,10 @@ def equals( ) def slice(self, sl: slice) -> "RangeCoordinateTransform": - sl = normalize_slice(sl, self.size) - - # TODO: support reverse transform (i.e., start > stop)? - assert sl.start < sl.stop - - new_size = (sl.stop - sl.start - 1) // sl.step + 1 - new_start = self.start + sl.start * self.step - new_stop = min(new_start + new_size * sl.step * self.step, self.stop) + new_range = range(self.size)[sl] + new_size = len(new_range) + new_start = self.start + new_range.start * self.step + new_stop = self.start + new_range.stop * self.step return type(self)( new_start, new_stop, new_size, self.coord_name, self.dim, dtype=self.dtype diff --git a/xarray/tests/test_range_index.py b/xarray/tests/test_range_index.py index a999c938300..d0644ba73a2 100644 --- a/xarray/tests/test_range_index.py +++ b/xarray/tests/test_range_index.py @@ -121,6 +121,22 @@ def test_range_index_isel() -> None: expected = create_dataset_arange(0.0, 1.0, 0.2) assert_identical(actual, expected, check_default_indexes=False) + actual = ds.isel(x=slice(None, None, -1)) + expected = create_dataset_arange(0.9, -0.1, -0.1) + assert_identical(actual, expected, check_default_indexes=False) + + actual = ds.isel(x=slice(None, 4, -1)) + expected = create_dataset_arange(0.9, 0.4, -0.1) + assert_identical(actual, expected, check_default_indexes=False) + + actual = ds.isel(x=slice(8, 4, -1)) + expected = create_dataset_arange(0.8, 0.4, -0.1) + assert_identical(actual, expected, check_default_indexes=False) + + actual = ds.isel(x=slice(8, None, -1)) + expected = create_dataset_arange(0.8, -0.1, -0.1) + assert_identical(actual, expected, check_default_indexes=False) + # https://github.com/pydata/xarray/issues/10441 ds2 = create_dataset_arange(0.0, 3.0, 0.1) actual = ds2.isel(x=slice(4, None, 3))