Skip to content
Merged
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
6 changes: 6 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ Bug Fixes
a ``zarr_format=3`` store with ``use_zarr_fill_value_as_mask=False``, so it is no
longer silently lost on round-trip (:issue:`10269`).
By `Davis Bennett <https://github.com/d-v-b>`_.
- :py:meth:`~xarray.indexes.RangeIndex.arange` now preserves the requested
``step`` instead of silently re-deriving it from ``(stop - start) / size``, so
its values match :py:func:`numpy.arange` when ``step`` does not evenly divide
the interval. Strided slicing of a :py:class:`~xarray.indexes.RangeIndex` now
preserves the step as well (:issue:`11325`).
By `mokashang <https://github.com/mokashang>`_.
- Fix :py:func:`decode_cf` failing on integer-encoded time arrays that contain
NaT when running against numpy 2.5+.
By `Ian Hunt-Isaak <https://github.com/ianhi>`_.
Expand Down
24 changes: 16 additions & 8 deletions xarray/indexes/range_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(
coord_name: Hashable,
dim: str,
dtype: Any = None,
step: float | None = None,
):
if dtype is None:
dtype = np.dtype(np.float64)
Expand All @@ -40,7 +41,7 @@ def __init__(

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

@property
def coord_name(self) -> Hashable:
Expand Down Expand Up @@ -121,21 +122,23 @@ def slice(self, sl: slice) -> "RangeCoordinateTransform":
new_range = range(self.size)[sl]
new_size = len(new_range)

# A slice scales the spacing by its own step, e.g. ``[::2]`` doubles it.
# Preserve the exact resulting step instead of letting it be re-derived
# from ``(stop - start) / size``, which would be wrong whenever the
# spacing does not evenly divide the interval. See GH11325.
new_step = self.step * new_range.step
new_start = self.start + new_range.start * self.step
new_stop = self.start + new_range.stop * self.step
new_stop = new_start + new_size * new_step

result = type(self)(
return type(self)(
new_start,
new_stop,
new_size,
self.coord_name,
self.dim,
dtype=self.dtype,
step=new_step,
)
if new_size == 0:
# For empty slices, preserve step from parent
result._step = self.step
return result


class RangeIndex(CoordinateTransformIndex):
Expand Down Expand Up @@ -278,8 +281,13 @@ def arange(

size = math.ceil((stop - start) / step)

# Snap ``stop`` to ``start + size * step`` and keep the exact ``step`` so
# that the materialized values match ``numpy.arange`` even when ``step``
# does not evenly divide ``stop - start``. See GH11325.
stop = start + size * step
# Snap `stop` to `start + size * step`
transform = RangeCoordinateTransform(
start, stop, size, coord_name, dim, dtype=dtype
start, stop, size, coord_name, dim, dtype=dtype, step=step
)

return cls(transform)
Expand Down
13 changes: 3 additions & 10 deletions xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ def _importorskip(
has_bottleneck, requires_bottleneck = _importorskip("bottleneck")
has_rasterio, requires_rasterio = _importorskip("rasterio")
has_zarr, requires_zarr = _importorskip("zarr")
has_zarr_v3, requires_zarr_v3 = _importorskip("zarr", "3.0.0")
requires_zarr_v3 = requires_zarr
has_zarr_v3_dtypes, requires_zarr_v3_dtypes = _importorskip("zarr", "3.1.0")
has_zarr_v3_async_oindex, requires_zarr_v3_async_oindex = _importorskip("zarr", "3.1.2")
if has_zarr_v3:
if has_zarr:
import zarr

# manual update by checking attrs for now
Expand Down Expand Up @@ -197,14 +197,7 @@ def _importorskip(
"zarr_format",
[
pytest.param(2, id="zarr_format=2"),
pytest.param(
3,
marks=pytest.mark.skipif(
not has_zarr_v3,
reason="zarr-python v2 cannot understand the zarr v3 format",
),
id="zarr_format=3",
),
pytest.param(3, id="zarr_format=3"),
],
)

Expand Down
Loading
Loading