Skip to content

Commit 572a528

Browse files
jukentdcherianmax-sixty
authored
Preserve attrs with coarsen (#4360)
* pass **kwargs into _coarsen_reshape * change _replace to copy in coarsen return * copy back to replace, variable=copy * take out self.copy * update pre-commit config (tags not branches) * add test that coarsen maintains OG object * del comment * check global for keep attrs * black reformatter * line break * variable._attrs to variable.attrs * if not keep_attrs * {} to None * set_options goes in a with block * remove test dependency on netcdf * add bug fix to whats-new.rst * Update doc/whats-new.rst Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com> * go back to v0.1.2 of blackdock * add test_coarsen_keep_attrs to test_dataarray.py * fix tests * black test_dataarray * xr.set_options * move keep_attrs to coarsen from _reshape_coarsen * flake8 * clean up * move keep_attrs to fx signature * remove kwarg check for keep_attrs * black on variable.py * fix test_variable * Format with black * fix test * check for global attribute * black variable.py * black test_variable.py * format w black * Update xarray/core/variable.py Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com> Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com> Co-authored-by: Maximilian Roos <m@maxroos.com>
1 parent 66259d1 commit 572a528

File tree

7 files changed

+55
-8
lines changed

7 files changed

+55
-8
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ repos:
66
hooks:
77
- id: isort
88
# https://github.com/python/black#version-control-integration
9-
- repo: https://github.com/python/black
9+
- repo: https://github.com/psf/black
1010
rev: 20.8b1
1111
hooks:
1212
- id: black

doc/whats-new.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Bug fixes
7777
and :py:meth:`DataArray.str.wrap` (:issue:`4334`). By `Mathias Hauser <https://github.com/mathause>`_.
7878
- Fixed overflow issue causing incorrect results in computing means of :py:class:`cftime.datetime`
7979
arrays (:issue:`4341`). By `Spencer Clark <https://github.com/spencerkclark>`_.
80+
- Fixed :py:meth:`Dataset.coarsen`, :py:meth:`DataArray.coarsen` dropping attributes on original object (:issue:`4120`, :pull:`4360`). by `Julia Kent <https://github.com/jukent>`_.
8081
- fix the signature of the plot methods. (:pull:`4359`) By `Justus Magin <https://github.com/keewis>`_.
8182
- Fix :py:func:`xarray.apply_ufunc` with ``vectorize=True`` and ``exclude_dims`` (:issue:`3890`).
8283
By `Mathias Hauser <https://github.com/mathause>`_.

xarray/core/rolling.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ def wrapped_func(self, **kwargs):
690690
from .dataarray import DataArray
691691

692692
reduced = self.obj.variable.coarsen(
693-
self.windows, func, self.boundary, self.side, **kwargs
693+
self.windows, func, self.boundary, self.side, self.keep_attrs, **kwargs
694694
)
695695
coords = {}
696696
for c, v in self.obj.coords.items():
@@ -703,6 +703,7 @@ def wrapped_func(self, **kwargs):
703703
self.coord_func[c],
704704
self.boundary,
705705
self.side,
706+
self.keep_attrs,
706707
**kwargs,
707708
)
708709
else:

xarray/core/variable.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,21 +1993,32 @@ def rolling_window(
19931993
),
19941994
)
19951995

1996-
def coarsen(self, windows, func, boundary="exact", side="left", **kwargs):
1996+
def coarsen(
1997+
self, windows, func, boundary="exact", side="left", keep_attrs=None, **kwargs
1998+
):
19971999
"""
19982000
Apply reduction function.
19992001
"""
20002002
windows = {k: v for k, v in windows.items() if k in self.dims}
20012003
if not windows:
20022004
return self.copy()
20032005

2006+
if keep_attrs is None:
2007+
keep_attrs = _get_keep_attrs(default=False)
2008+
2009+
if keep_attrs:
2010+
_attrs = self.attrs
2011+
else:
2012+
_attrs = None
2013+
20042014
reshaped, axes = self._coarsen_reshape(windows, boundary, side)
20052015
if isinstance(func, str):
20062016
name = func
20072017
func = getattr(duck_array_ops, name, None)
20082018
if func is None:
20092019
raise NameError(f"{name} is not a valid method.")
2010-
return self._replace(data=func(reshaped, axis=axes, **kwargs))
2020+
2021+
return self._replace(data=func(reshaped, axis=axes, **kwargs), attrs=_attrs)
20112022

20122023
def _coarsen_reshape(self, windows, boundary, side):
20132024
"""
@@ -2072,9 +2083,6 @@ def _coarsen_reshape(self, windows, boundary, side):
20722083
else:
20732084
shape.append(variable.shape[i])
20742085

2075-
keep_attrs = _get_keep_attrs(default=False)
2076-
variable.attrs = variable._attrs if keep_attrs else {}
2077-
20782086
return variable.data.reshape(shape), tuple(axes)
20792087

20802088
@property

xarray/tests/test_dataarray.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6186,6 +6186,35 @@ def test_isin(da):
61866186
assert_equal(result, expected)
61876187

61886188

6189+
def test_coarsen_keep_attrs():
6190+
_attrs = {"units": "test", "long_name": "testing"}
6191+
6192+
da = xr.DataArray(
6193+
np.linspace(0, 364, num=364),
6194+
dims="time",
6195+
coords={"time": pd.date_range("15/12/1999", periods=364)},
6196+
attrs=_attrs,
6197+
)
6198+
6199+
da2 = da.copy(deep=True)
6200+
6201+
# Test dropped attrs
6202+
dat = da.coarsen(time=3, boundary="trim").mean()
6203+
assert dat.attrs == {}
6204+
6205+
# Test kept attrs using dataset keyword
6206+
dat = da.coarsen(time=3, boundary="trim", keep_attrs=True).mean()
6207+
assert dat.attrs == _attrs
6208+
6209+
# Test kept attrs using global option
6210+
with xr.set_options(keep_attrs=True):
6211+
dat = da.coarsen(time=3, boundary="trim").mean()
6212+
assert dat.attrs == _attrs
6213+
6214+
# Test kept attrs in original object
6215+
xr.testing.assert_identical(da, da2)
6216+
6217+
61896218
@pytest.mark.filterwarnings("error:Mean of empty slice")
61906219
@pytest.mark.parametrize("da", (1, 2), indirect=True)
61916220
def test_rolling_iter(da):

xarray/tests/test_dataset.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5956,6 +5956,8 @@ def test_coarsen_keep_attrs():
59565956
attrs=_attrs,
59575957
)
59585958

5959+
ds2 = ds.copy(deep=True)
5960+
59595961
# Test dropped attrs
59605962
dat = ds.coarsen(coord=5).mean()
59615963
assert dat.attrs == {}
@@ -5969,6 +5971,9 @@ def test_coarsen_keep_attrs():
59695971
dat = ds.coarsen(coord=5).mean()
59705972
assert dat.attrs == _attrs
59715973

5974+
# Test kept attrs in original object
5975+
xr.testing.assert_identical(ds, ds2)
5976+
59725977

59735978
def test_rolling_keep_attrs():
59745979
_attrs = {"units": "test", "long_name": "testing"}

xarray/tests/test_variable.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1949,7 +1949,10 @@ def test_coarsen_keep_attrs(self, operation="mean"):
19491949
# Test kept attrs
19501950
with set_options(keep_attrs=True):
19511951
new = Variable(["coord"], np.linspace(1, 10, 100), attrs=_attrs).coarsen(
1952-
windows={"coord": 1}, func=test_func, boundary="exact", side="left"
1952+
windows={"coord": 1},
1953+
func=test_func,
1954+
boundary="exact",
1955+
side="left",
19531956
)
19541957
assert new.attrs == _attrs
19551958

0 commit comments

Comments
 (0)