Skip to content

Commit e8b41fe

Browse files
ianhiclaudedcherian
authored
fix: Empty RangeIndex Display (#10594)
Co-authored-by: Claude <[email protected]> Co-authored-by: Deepak Cherian <[email protected]>
1 parent 3c9217e commit e8b41fe

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

xarray/indexes/range_index.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ class RangeCoordinateTransform(CoordinateTransform):
2020

2121
start: float
2222
stop: float
23+
_step: float | None
2324

24-
__slots__ = ("start", "stop")
25+
__slots__ = ("_step", "start", "stop")
2526

2627
def __init__(
2728
self,
@@ -39,6 +40,7 @@ def __init__(
3940

4041
self.start = start
4142
self.stop = stop
43+
self._step = None # Will be calculated by property
4244

4345
@property
4446
def coord_name(self) -> Hashable:
@@ -54,7 +56,13 @@ def size(self) -> int:
5456

5557
@property
5658
def step(self) -> float:
57-
return (self.stop - self.start) / self.size
59+
if self._step is not None:
60+
return self._step
61+
if self.size > 0:
62+
return (self.stop - self.start) / self.size
63+
else:
64+
# For empty arrays, default to 1.0
65+
return 1.0
5866

5967
def forward(self, dim_positions: dict[str, Any]) -> dict[Hashable, Any]:
6068
positions = dim_positions[self.dim]
@@ -81,12 +89,22 @@ def equals(
8189
def slice(self, sl: slice) -> "RangeCoordinateTransform":
8290
new_range = range(self.size)[sl]
8391
new_size = len(new_range)
92+
8493
new_start = self.start + new_range.start * self.step
8594
new_stop = self.start + new_range.stop * self.step
8695

87-
return type(self)(
88-
new_start, new_stop, new_size, self.coord_name, self.dim, dtype=self.dtype
96+
result = type(self)(
97+
new_start,
98+
new_stop,
99+
new_size,
100+
self.coord_name,
101+
self.dim,
102+
dtype=self.dtype,
89103
)
104+
if new_size == 0:
105+
# For empty slices, preserve step from parent
106+
result._step = self.step
107+
return result
90108

91109

92110
class RangeIndex(CoordinateTransformIndex):

xarray/tests/test_range_index.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,62 @@ def test_range_index_isel() -> None:
166166
assert_identical(actual, expected)
167167

168168

169+
def test_range_index_empty_slice() -> None:
170+
"""Test that empty slices of RangeIndex are printable and preserve step.
171+
172+
Regression test for https://github.com/pydata/xarray/issues/10547
173+
"""
174+
# Test with linspace
175+
n = 30
176+
step = 1
177+
da = xr.DataArray(np.zeros(n), dims=["x"])
178+
da = da.assign_coords(
179+
xr.Coordinates.from_xindex(RangeIndex.linspace(0, (n - 1) * step, n, dim="x"))
180+
)
181+
182+
# This should not raise ZeroDivisionError
183+
sub = da.isel(x=slice(0))
184+
assert sub.sizes["x"] == 0
185+
186+
# Test that it's printable
187+
repr_str = repr(sub)
188+
assert "RangeIndex" in repr_str
189+
assert "step=1" in repr_str
190+
191+
# Test with different step values
192+
index = RangeIndex.arange(0, 10, 2.5, dim="y")
193+
da2 = xr.DataArray(np.zeros(4), dims=["y"])
194+
da2 = da2.assign_coords(xr.Coordinates.from_xindex(index))
195+
empty = da2.isel(y=slice(0))
196+
197+
# Should preserve step
198+
assert empty.sizes["y"] == 0
199+
range_index_y = empty._indexes["y"]
200+
assert isinstance(range_index_y, RangeIndex)
201+
assert range_index_y.step == 2.5
202+
203+
# Test that it's printable
204+
repr_str2 = repr(empty)
205+
assert "RangeIndex" in repr_str2
206+
assert "step=2.5" in repr_str2
207+
208+
# Test negative step
209+
index3 = RangeIndex.arange(10, 0, -1, dim="z")
210+
da3 = xr.DataArray(np.zeros(10), dims=["z"])
211+
da3 = da3.assign_coords(xr.Coordinates.from_xindex(index3))
212+
empty3 = da3.isel(z=slice(0))
213+
214+
assert empty3.sizes["z"] == 0
215+
range_index_z = empty3._indexes["z"]
216+
assert isinstance(range_index_z, RangeIndex)
217+
assert range_index_z.step == -1.0
218+
219+
# Test that it's printable
220+
repr_str3 = repr(empty3)
221+
assert "RangeIndex" in repr_str3
222+
assert "step=-1" in repr_str3
223+
224+
169225
def test_range_index_sel() -> None:
170226
ds = create_dataset_arange(0.0, 1.0, 0.1)
171227

0 commit comments

Comments
 (0)