Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Bug Fixes
- Fix a major performance regression in :py:meth:`Coordinates.to_index` (and
consequently :py:meth:`Dataset.to_dataframe`) caused by converting the cached
code ndarrays into Python lists (:issue:`11305`).
- Fix :py:meth:`DataArray.idxmax` and :py:meth:`DataArray.idxmin` for interval
coordinates by preserving pandas extension index adapters during label lookup
(:issue:`11300`).


Documentation
Expand Down
6 changes: 6 additions & 0 deletions xarray/computation/computation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from xarray.core.options import OPTIONS, _get_keep_attrs
from xarray.core.types import Dims, T_DataArray
from xarray.core.utils import (
is_allowed_extension_array,
is_scalar,
parse_dims_as_set,
)
Expand Down Expand Up @@ -1008,6 +1009,11 @@ def _calc_idxminmax(
array[dim].data, chunks=((array.sizes[dim],),)
)
coord = coord.copy(data=coord_array)
elif is_allowed_extension_array(array[dim].data):
# Keep pandas-backed extension coordinates on their original indexing
# adapter so scalar lookups return a 0d array rather than a malformed
# ExtensionArray scalar wrapper.
pass
else:
coord = coord.copy(data=to_like_array(array[dim].data, array.data))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i suspect the real solution is to fix to_like_array to handle extension arrays?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I moved the fix into to_like_array() in d0f22b94 instead of keeping the one-off special case in _calc_idxminmax().

For NumPy-backed lookups, to_like_array() now converts allowed pandas extension arrays to a NumPy object array, which fixes the scalar interval selection path while keeping the idxmin/idxmax regression green.

Validation I reran locally:

  • .venv/bin/python -m pytest -o addopts= xarray/tests/test_dataarray.py -k 'test_idxminmax_interval_coords or test_idxmax or test_idxmin'
  • .venv/bin/python -m ruff check xarray/computation/computation.py xarray/compat/array_api_compat.py xarray/tests/test_dataarray.py


Expand Down
24 changes: 24 additions & 0 deletions xarray/tests/test_dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -5530,6 +5530,30 @@ def test_idxmax(
result7 = ar0.idxmax(fill_value=-1j)
assert_identical(result7, expected7)

@pytest.mark.parametrize(
("func_name", "values"),
[
pytest.param("idxmax", [False, True, True], id="idxmax"),
pytest.param("idxmin", [True, False, True], id="idxmin"),
],
)
def test_idxminmax_interval_coords(
self,
x: np.ndarray,
minindex: int | float,
maxindex: int | float,
nanindex: int | None,
func_name: Literal["idxmax", "idxmin"],
values: list[bool],
) -> None:
interval_index = pd.IntervalIndex.from_breaks([0, 1, 2, 3])
array = xr.DataArray(values, dims=["z"], coords={"z": interval_index})

result = getattr(array, func_name)()

expected = xr.DataArray(pd.Interval(1, 2, closed="right"), name="z")
assert_identical(result, expected)

@pytest.mark.filterwarnings(
"ignore:Behaviour of argmin/argmax with neither dim nor :FutureWarning"
)
Expand Down
Loading