From 368129471ba7975db43f75466ba5acfdbc7b403a Mon Sep 17 00:00:00 2001 From: lavafreak Date: Sun, 26 Apr 2026 16:09:54 -0600 Subject: [PATCH 1/2] Fix idxminmax for interval coordinates --- doc/whats-new.rst | 3 +++ xarray/computation/computation.py | 6 ++++++ xarray/tests/test_dataarray.py | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index effb199f18e..f0b629fb063 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -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 diff --git a/xarray/computation/computation.py b/xarray/computation/computation.py index 3df468f19a9..05baa0c2235 100644 --- a/xarray/computation/computation.py +++ b/xarray/computation/computation.py @@ -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, ) @@ -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)) diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py index 8eb52046a31..d4eaabafc70 100644 --- a/xarray/tests/test_dataarray.py +++ b/xarray/tests/test_dataarray.py @@ -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" ) From d0f22b94394459560e1ec0f44af0f7dbd60d2bc7 Mon Sep 17 00:00:00 2001 From: lavafreak Date: Wed, 29 Apr 2026 18:11:20 -0600 Subject: [PATCH 2/2] Handle extension arrays in to_like_array --- xarray/compat/array_api_compat.py | 3 +++ xarray/computation/computation.py | 6 ------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/xarray/compat/array_api_compat.py b/xarray/compat/array_api_compat.py index e1e5d5c5bdc..52d8506652b 100644 --- a/xarray/compat/array_api_compat.py +++ b/xarray/compat/array_api_compat.py @@ -1,5 +1,6 @@ import numpy as np +from xarray.core.utils import is_allowed_extension_array from xarray.namedarray.pycompat import array_type @@ -78,5 +79,7 @@ def to_like_array(array, like): xp = get_array_namespace(like) if xp is not np: return xp.asarray(array) + if is_allowed_extension_array(array): + return np.asarray(array) # avoid casting things like pint quantities to numpy arrays return array diff --git a/xarray/computation/computation.py b/xarray/computation/computation.py index 05baa0c2235..3df468f19a9 100644 --- a/xarray/computation/computation.py +++ b/xarray/computation/computation.py @@ -24,7 +24,6 @@ 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, ) @@ -1009,11 +1008,6 @@ 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))