Skip to content

Commit d8b34a2

Browse files
committed
Better uv compatibility
`uv sync` now installs dev dependencies automatically. I don't think this should affect other tools negatively, lmk if I'm unaware of something
1 parent bc33fda commit d8b34a2

File tree

3 files changed

+82
-34
lines changed

3 files changed

+82
-34
lines changed

pyproject.toml

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,6 @@ dependencies = ["numpy>=1.24", "packaging>=23.2", "pandas>=2.1"]
3030
[project.optional-dependencies]
3131
accel = ["scipy", "bottleneck", "numbagg", "numba>=0.54", "flox", "opt_einsum"]
3232
complete = ["xarray[accel,etc,io,parallel,viz]"]
33-
dev = [
34-
"hypothesis",
35-
"jinja2",
36-
"mypy",
37-
"pre-commit",
38-
"pytest",
39-
"pytest-cov",
40-
"pytest-env",
41-
"pytest-mypy-plugins",
42-
"pytest-timeout",
43-
"pytest-xdist",
44-
"ruff>=0.8.0",
45-
"sphinx",
46-
"sphinx_autosummary_accessors",
47-
"xarray[complete,types]",
48-
]
4933
io = [
5034
"netCDF4",
5135
"h5netcdf",
@@ -76,6 +60,25 @@ types = [
7660
"types-setuptools",
7761
]
7862

63+
[dependency-groups]
64+
dev = [
65+
"hypothesis",
66+
"jinja2",
67+
"mypy",
68+
"pre-commit",
69+
"pytest",
70+
"pytest-cov",
71+
"pytest-env",
72+
"pytest-mypy-plugins",
73+
"pytest-timeout",
74+
"pytest-xdist",
75+
"ruff>=0.8.0",
76+
"sphinx",
77+
"sphinx_autosummary_accessors",
78+
"xarray[complete,types]",
79+
80+
]
81+
7982
[project.urls]
8083
Documentation = "https://docs.xarray.dev"
8184
SciPy2015-talk = "https://www.youtube.com/watch?v=X0pAhJgySxk"

xarray/core/dataarray.py

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5991,26 +5991,30 @@ def idxmin(
59915991

59925992
def idxmax(
59935993
self,
5994-
dim: Hashable = None,
5994+
dim: Dims = None,
59955995
*,
59965996
skipna: bool | None = None,
59975997
fill_value: Any = dtypes.NA,
59985998
keep_attrs: bool | None = None,
5999-
) -> Self:
6000-
"""Return the coordinate label of the maximum value along a dimension.
5999+
) -> Self | dict[Hashable, Self]:
6000+
"""Return the coordinate label of the maximum value along one or more dimensions.
60016001
60026002
Returns a new `DataArray` named after the dimension with the values of
60036003
the coordinate labels along that dimension corresponding to maximum
60046004
values along that dimension.
60056005
6006+
If a sequence is passed to 'dim', then result is returned as dict of DataArrays.
6007+
If a single str is passed to 'dim' then returns a DataArray.
6008+
60066009
In comparison to :py:meth:`~DataArray.argmax`, this returns the
60076010
coordinate label while :py:meth:`~DataArray.argmax` returns the index.
6011+
Internally, this method uses argmax to locate the maximum values.
60086012
60096013
Parameters
60106014
----------
6011-
dim : Hashable, optional
6012-
Dimension over which to apply `idxmax`. This is optional for 1D
6013-
arrays, but required for arrays with 2 or more dimensions.
6015+
dim : "...", str, Iterable of Hashable or None, optional
6016+
The dimensions over which to find the maximum. By default, finds maximum over
6017+
all dimensions if array is 1D, otherwise requires explicit specification.
60146018
skipna : bool or None, default: None
60156019
If True, skip missing values (as marked by NaN). By default, only
60166020
skips missing values for ``float``, ``complex``, and ``object``
@@ -6029,9 +6033,9 @@ def idxmax(
60296033
60306034
Returns
60316035
-------
6032-
reduced : DataArray
6033-
New `DataArray` object with `idxmax` applied to its data and the
6034-
indicated dimension removed.
6036+
reduced : DataArray or dict of DataArray
6037+
New `DataArray` object(s) with `idxmax` applied to its data and the
6038+
indicated dimension(s) removed.
60356039
60366040
See Also
60376041
--------
@@ -6076,15 +6080,40 @@ def idxmax(
60766080
array([0., 4., 4.])
60776081
Coordinates:
60786082
* y (y) int64 24B -1 0 1
6079-
"""
6080-
return computation._calc_idxminmax(
6081-
array=self,
6082-
func=lambda x, *args, **kwargs: x.argmax(*args, **kwargs),
6083-
dim=dim,
6084-
skipna=skipna,
6085-
fill_value=fill_value,
6086-
keep_attrs=keep_attrs,
6087-
)
6083+
>>> array.idxmax(dim=["x", "y"])
6084+
{'x': <xarray.DataArray 'x' ()> Size: 8B
6085+
array(0.),
6086+
'y': <xarray.DataArray 'y' ()> Size: 8B
6087+
array(-1)}
6088+
"""
6089+
# Check if dim is multi-dimensional (either ellipsis or a sequence, not a string or tuple)
6090+
if (dim is ... or (isinstance(dim, Iterable) and not isinstance(dim, str))) and not isinstance(
6091+
dim, tuple
6092+
):
6093+
# For multiple dimensions, process each dimension separately
6094+
# This matches the behavior pattern of argmax when given multiple dimensions,
6095+
# but returns coordinate labels instead of indices
6096+
result = {}
6097+
for k in dim if dim is not ... else self.dims:
6098+
result[k] = self.idxmax(
6099+
dim=k,
6100+
skipna=skipna,
6101+
fill_value=fill_value,
6102+
keep_attrs=keep_attrs,
6103+
)
6104+
return result
6105+
else:
6106+
# Use the existing implementation for single dimension
6107+
# This wraps argmax through the _calc_idxminmax helper function
6108+
# which converts indices to coordinate values
6109+
return computation._calc_idxminmax(
6110+
array=self,
6111+
func=lambda x, *args, **kwargs: x.argmax(*args, **kwargs),
6112+
dim=dim,
6113+
skipna=skipna,
6114+
fill_value=fill_value,
6115+
keep_attrs=keep_attrs,
6116+
)
60886117

60896118
def argmin(
60906119
self,

xarray/tests/test_dataarray.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5716,6 +5716,22 @@ def test_idxmax(
57165716
ar0 = ar0_raw.chunk({})
57175717
else:
57185718
ar0 = ar0_raw
5719+
5720+
# Test multi-dimensional idxmax
5721+
if not np.isnan(maxindex).any():
5722+
# Get the indices for the maximum values along both dimensions
5723+
idx_y = ar0.argmax(dim="x")
5724+
idx_x = ar0.argmax(dim="y")
5725+
5726+
# Get the coordinate labels for these maximum values using idxmax
5727+
idxmax_result = ar0.idxmax(dim=["x", "y"])
5728+
5729+
# Verify we have the expected keys in the result dictionary
5730+
assert set(idxmax_result.keys()) == {"x", "y"}
5731+
5732+
# Verify the values match what we'd expect from individually applying idxmax
5733+
assert_identical(idxmax_result["x"], ar0.idxmax(dim="x"))
5734+
assert_identical(idxmax_result["y"], ar0.idxmax(dim="y"))
57195735

57205736
# No dimension specified
57215737
with pytest.raises(ValueError):

0 commit comments

Comments
 (0)