@@ -17,6 +17,90 @@ New Features
17
17
Breaking changes
18
18
~~~~~~~~~~~~~~~~
19
19
20
+ - **All xarray operations now preserve attributes by default ** (:issue: `3891 `, :issue: `2582 `).
21
+ Previously, operations would drop attributes unless explicitly told to preserve them via ``keep_attrs=True ``.
22
+ This aligns xarray with the common scientific workflow where metadata preservation is essential.
23
+
24
+ **What changed: **
25
+
26
+ .. code-block :: python
27
+
28
+ # Before (xarray <2025.09.1):
29
+ data = xr.DataArray([1 , 2 , 3 ], attrs = {" units" : " meters" , " long_name" : " height" })
30
+ result = data.mean()
31
+ result.attrs # {} - Attributes lost!
32
+
33
+ # After (xarray ≥2025.09.1):
34
+ data = xr.DataArray([1 , 2 , 3 ], attrs = {" units" : " meters" , " long_name" : " height" })
35
+ result = data.mean()
36
+ result.attrs # {"units": "meters", "long_name": "height"} - Attributes preserved!
37
+
38
+ **Affected operations include: **
39
+
40
+ *Computational operations: *
41
+
42
+ - Reductions: ``mean() ``, ``sum() ``, ``std() ``, ``var() ``, ``min() ``, ``max() ``, ``median() ``, ``quantile() ``, etc.
43
+ - Rolling windows: ``rolling().mean() ``, ``rolling().sum() ``, etc.
44
+ - Groupby: ``groupby().mean() ``, ``groupby().sum() ``, etc.
45
+ - Resampling: ``resample().mean() ``, etc.
46
+ - Weighted: ``weighted().mean() ``, ``weighted().sum() ``, etc.
47
+ - ``apply_ufunc() `` and NumPy universal functions
48
+
49
+ *Binary operations: *
50
+
51
+ - Arithmetic: ``+ ``, ``- ``, ``* ``, ``/ ``, ``** ``, ``// ``, ``% `` (attributes from left operand)
52
+ - Comparisons: ``< ``, ``> ``, ``== ``, ``!= ``, ``<= ``, ``>= `` (attributes from left operand)
53
+ - With scalars: ``data * 2 ``, ``10 - data `` (preserves data's attributes)
54
+
55
+ *Data manipulation: *
56
+
57
+ - Missing data: ``fillna() ``, ``dropna() ``, ``interpolate_na() ``, ``ffill() ``, ``bfill() ``
58
+ - Indexing/selection: ``isel() ``, ``sel() ``, ``where() ``, ``clip() ``
59
+ - Alignment: ``interp() ``, ``reindex() ``, ``align() ``
60
+ - Transformations: ``map() ``, ``pipe() ``, ``assign() ``, ``assign_coords() ``
61
+ - Shape operations: ``expand_dims() ``, ``squeeze() ``, ``transpose() ``, ``stack() ``, ``unstack() ``
62
+
63
+ **Binary operations - attributes from left operand: **
64
+
65
+ .. code-block :: python
66
+
67
+ a = xr.DataArray([1 , 2 ], attrs = {" source" : " sensor_a" })
68
+ b = xr.DataArray([3 , 4 ], attrs = {" source" : " sensor_b" })
69
+ (a + b).attrs # {"source": "sensor_a"} - Left operand wins
70
+ (b + a).attrs # {"source": "sensor_b"} - Order matters!
71
+
72
+ **How to restore previous behavior: **
73
+
74
+ 1. **Globally for your entire script: **
75
+
76
+ .. code-block :: python
77
+
78
+ import xarray as xr
79
+
80
+ xr.set_options(keep_attrs = False ) # Affects all subsequent operations
81
+
82
+ 2. **For specific operations: **
83
+
84
+ .. code-block :: python
85
+
86
+ result = data.mean(dim = " time" , keep_attrs = False )
87
+
88
+ 3. **For code blocks: **
89
+
90
+ .. code-block :: python
91
+
92
+ with xr.set_options(keep_attrs = False ):
93
+ # All operations in this block drop attrs
94
+ result = data1 + data2
95
+
96
+ 4. **Remove attributes after operations: **
97
+
98
+ .. code-block :: python
99
+
100
+ result = data.mean().drop_attrs()
101
+
102
+ By `Maximilian Roos <https://github.com/max-sixty >`_.
103
+
20
104
- :py:meth: `Dataset.update ` now returns ``None ``, instead of the updated dataset. This
21
105
completes the deprecation cycle started in version 0.17. The method still updates the
22
106
dataset in-place. (:issue: `10167 `)
0 commit comments