Skip to content

fix: Empty RangeIndex Display #10594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions xarray/indexes/range_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ class RangeCoordinateTransform(CoordinateTransform):

start: float
stop: float
_step: float | None

__slots__ = ("start", "stop")
__slots__ = ("_step", "start", "stop")

def __init__(
self,
Expand All @@ -39,6 +40,7 @@ def __init__(

self.start = start
self.stop = stop
self._step = None # Will be calculated by property

@property
def coord_name(self) -> Hashable:
Expand All @@ -54,7 +56,13 @@ def size(self) -> int:

@property
def step(self) -> float:
return (self.stop - self.start) / self.size
if self._step is not None:
return self._step
if self.size > 0:
return (self.stop - self.start) / self.size
else:
# For empty arrays, default to 1.0
return 1.0

def forward(self, dim_positions: dict[str, Any]) -> dict[Hashable, Any]:
positions = dim_positions[self.dim]
Expand All @@ -81,12 +89,22 @@ def equals(
def slice(self, sl: slice) -> "RangeCoordinateTransform":
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
result = type(self)(
new_start,
new_stop,
new_size,
self.coord_name,
self.dim,
dtype=self.dtype,
)
if new_size == 0:
# For empty slices, preserve step from parent
result._step = self.step
return result


class RangeIndex(CoordinateTransformIndex):
Expand Down
56 changes: 56 additions & 0 deletions xarray/tests/test_range_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,62 @@ def test_range_index_isel() -> None:
assert_identical(actual, expected)


def test_range_index_empty_slice() -> None:
"""Test that empty slices of RangeIndex are printable and preserve step.

Regression test for https://github.com/pydata/xarray/issues/10547
"""
# Test with linspace
n = 30
step = 1
da = xr.DataArray(np.zeros(n), dims=["x"])
da = da.assign_coords(
xr.Coordinates.from_xindex(RangeIndex.linspace(0, (n - 1) * step, n, dim="x"))
)

# This should not raise ZeroDivisionError
sub = da.isel(x=slice(0))
assert sub.sizes["x"] == 0

# Test that it's printable
repr_str = repr(sub)
assert "RangeIndex" in repr_str
assert "step=1" in repr_str

# Test with different step values
index = RangeIndex.arange(0, 10, 2.5, dim="y")
da2 = xr.DataArray(np.zeros(4), dims=["y"])
da2 = da2.assign_coords(xr.Coordinates.from_xindex(index))
empty = da2.isel(y=slice(0))

# Should preserve step
assert empty.sizes["y"] == 0
range_index_y = empty._indexes["y"]
assert isinstance(range_index_y, RangeIndex)
assert range_index_y.step == 2.5

# Test that it's printable
repr_str2 = repr(empty)
assert "RangeIndex" in repr_str2
assert "step=2.5" in repr_str2

# Test negative step
index3 = RangeIndex.arange(10, 0, -1, dim="z")
da3 = xr.DataArray(np.zeros(10), dims=["z"])
da3 = da3.assign_coords(xr.Coordinates.from_xindex(index3))
empty3 = da3.isel(z=slice(0))

assert empty3.sizes["z"] == 0
range_index_z = empty3._indexes["z"]
assert isinstance(range_index_z, RangeIndex)
assert range_index_z.step == -1.0

# Test that it's printable
repr_str3 = repr(empty3)
assert "RangeIndex" in repr_str3
assert "step=-1" in repr_str3


def test_range_index_sel() -> None:
ds = create_dataset_arange(0.0, 1.0, 0.1)

Expand Down
Loading