Skip to content

Commit 3674b5e

Browse files
committed
Fix groupby binary ops when grouped array is subset relative to other
Closes pydata#7797
1 parent 25d9a28 commit 3674b5e

File tree

3 files changed

+29
-2
lines changed

3 files changed

+29
-2
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ Deprecations
3939

4040
Bug fixes
4141
~~~~~~~~~
42-
42+
Fix groupby binary ops when grouped array is subset relative to other. (:issue:`7797`).
43+
By `Deepak Cherian <https://github.com/dcherian`_.
4344

4445
Documentation
4546
~~~~~~~~~~~~~

xarray/core/groupby.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,9 @@ def _binary_op(self, other, f, reflexive=False):
669669
obj = obj.where(~mask, drop=True)
670670
codes = codes.where(~mask, drop=True).astype(int)
671671

672-
other, _ = align(other, coord, join="outer")
672+
# codes are defined for coord, so we align `other` with `coord`
673+
# before indexing
674+
other, _ = align(other, coord, join="right")
673675
expanded = other.isel({name: codes})
674676

675677
result = g(obj, expanded)

xarray/tests/test_groupby.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,8 +1302,15 @@ def test_groupby_math_not_aligned(self):
13021302
expected = DataArray([10, 11, np.nan, np.nan], array.coords)
13031303
assert_identical(expected, actual)
13041304

1305+
# regression test for #7797
1306+
other = array.groupby("b").sum()
1307+
actual = array.sel(x=[0, 1]).groupby("b") - other
1308+
expected = DataArray([-1, 0], {"b": ("x", [0, 0]), "x": [0, 1]}, dims="x")
1309+
assert_identical(expected, actual)
1310+
13051311
other = DataArray([10], coords={"c": 123, "b": [0]}, dims="b")
13061312
actual = array.groupby("b") + other
1313+
expected = DataArray([10, 11, np.nan, np.nan], array.coords)
13071314
expected.coords["c"] = (["x"], [123] * 2 + [np.nan] * 2)
13081315
assert_identical(expected, actual)
13091316

@@ -2289,3 +2296,20 @@ def test_resample_cumsum(method: str, expected_array: list[float]) -> None:
22892296
actual = getattr(ds.foo.resample(time="3M"), method)(dim="time")
22902297
expected.coords["time"] = ds.time
22912298
assert_identical(expected.drop_vars(["time"]).foo, actual)
2299+
2300+
2301+
def test_groupby_binary_op_regression():
2302+
# regression test for #7797
2303+
# monthly timeseries that should return "zero anomalies" everywhere
2304+
time = xr.date_range("2023-01-01", "2023-12-31", freq="MS")
2305+
data = np.linspace(-1, 1, 12)
2306+
x = xr.DataArray(data, coords={"time": time})
2307+
clim = xr.DataArray(data, coords={"month": np.arange(1, 13, 1)})
2308+
2309+
# seems to give the correct result if we use the full x, but not with a slice
2310+
x_slice = x.sel(time=["2023-04-01"])
2311+
2312+
# two typical ways of computing anomalies
2313+
anom_gb = x_slice.groupby("time.month") - clim
2314+
2315+
assert_identical(xr.zeros_like(anom_gb), anom_gb)

0 commit comments

Comments
 (0)