Skip to content

Commit 1afeccc

Browse files
TomNicholasmax-sixtymathausedcherian
authored andcommitted
Roll coords deprecation (pydata#5653)
* changed default * updated tests * updated whats-new * Fix mypy * Update xarray/core/dataarray.py Co-authored-by: Mathias Hauser <[email protected]> * Update xarray/core/dataarray.py Co-authored-by: Mathias Hauser <[email protected]> * Update xarray/core/dataarray.py Co-authored-by: Mathias Hauser <[email protected]> * Update xarray/core/dataset.py Co-authored-by: Mathias Hauser <[email protected]> * Update xarray/core/dataset.py Co-authored-by: Mathias Hauser <[email protected]> * tidy up specification of default argument in docstring * isort linting * Update xarray/core/indexes.py Co-authored-by: Maximilian Roos <[email protected]> Co-authored-by: Mathias Hauser <[email protected]> Co-authored-by: Deepak Cherian <[email protected]>
1 parent c7566af commit 1afeccc

File tree

6 files changed

+75
-72
lines changed

6 files changed

+75
-72
lines changed

doc/whats-new.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,12 @@ Breaking changes
5656
Deprecations
5757
~~~~~~~~~~~~
5858

59+
- Set the default argument for `roll_coords` to `False` for :py:meth:`DataArray.roll`
60+
and :py:meth:`Dataset.roll`. (:pull:`5653`)
61+
By `Tom Nicholas <https://github.com/TomNicholas>`_.
5962
- :py:meth:`xarray.open_mfdataset` will now error instead of warn when a value for ``concat_dim`` is
60-
passed alongside ``combine='by_coords'``. By `Tom Nicholas <https://github.com/TomNicholas>`_.
61-
63+
passed alongside ``combine='by_coords'``.
64+
By `Tom Nicholas <https://github.com/TomNicholas>`_.
6265

6366
Bug fixes
6467
~~~~~~~~~

xarray/core/dataarray.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3169,11 +3169,14 @@ def shift(
31693169
fill_value: Any = dtypes.NA,
31703170
**shifts_kwargs: int,
31713171
) -> "DataArray":
3172-
"""Shift this array by an offset along one or more dimensions.
3172+
"""Shift this DataArray by an offset along one or more dimensions.
31733173
3174-
Only the data is moved; coordinates stay in place. Values shifted from
3175-
beyond array bounds are replaced by NaN. This is consistent with the
3176-
behavior of ``shift`` in pandas.
3174+
Only the data is moved; coordinates stay in place. This is consistent
3175+
with the behavior of ``shift`` in pandas.
3176+
3177+
Values shifted from beyond array bounds will appear at one end of
3178+
each dimension, which are filled according to `fill_value`. For periodic
3179+
offsets instead see `roll`.
31773180
31783181
Parameters
31793182
----------
@@ -3212,12 +3215,15 @@ def shift(
32123215

32133216
def roll(
32143217
self,
3215-
shifts: Mapping[Any, int] = None,
3216-
roll_coords: bool = None,
3218+
shifts: Mapping[Hashable, int] = None,
3219+
roll_coords: bool = False,
32173220
**shifts_kwargs: int,
32183221
) -> "DataArray":
32193222
"""Roll this array by an offset along one or more dimensions.
32203223
3224+
Unlike shift, roll treats the given dimensions as periodic, so will not
3225+
create any missing values to be filled.
3226+
32213227
Unlike shift, roll may rotate all variables, including coordinates
32223228
if specified. The direction of rotation is consistent with
32233229
:py:func:`numpy.roll`.
@@ -3228,12 +3234,9 @@ def roll(
32283234
Integer offset to rotate each of the given dimensions.
32293235
Positive offsets roll to the right; negative offsets roll to the
32303236
left.
3231-
roll_coords : bool
3232-
Indicates whether to roll the coordinates by the offset
3233-
The current default of roll_coords (None, equivalent to True) is
3234-
deprecated and will change to False in a future version.
3235-
Explicitly pass roll_coords to silence the warning.
3236-
**shifts_kwargs
3237+
roll_coords : bool, default: False
3238+
Indicates whether to roll the coordinates by the offset too.
3239+
**shifts_kwargs : {dim: offset, ...}, optional
32373240
The keyword arguments form of ``shifts``.
32383241
One of shifts or shifts_kwargs must be provided.
32393242

xarray/core/dataset.py

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ def _replace(
10971097
coord_names: Set[Hashable] = None,
10981098
dims: Dict[Any, int] = None,
10991099
attrs: Union[Dict[Hashable, Any], None, Default] = _default,
1100-
indexes: Union[Dict[Any, Index], None, Default] = _default,
1100+
indexes: Union[Dict[Hashable, Index], None, Default] = _default,
11011101
encoding: Union[dict, None, Default] = _default,
11021102
inplace: bool = False,
11031103
) -> "Dataset":
@@ -5866,12 +5866,22 @@ def diff(self, dim, n=1, label="upper"):
58665866
else:
58675867
return difference
58685868

5869-
def shift(self, shifts=None, fill_value=dtypes.NA, **shifts_kwargs):
5869+
def shift(
5870+
self,
5871+
shifts: Mapping[Hashable, int] = None,
5872+
fill_value: Any = dtypes.NA,
5873+
**shifts_kwargs: int,
5874+
) -> "Dataset":
5875+
58705876
"""Shift this dataset by an offset along one or more dimensions.
58715877
58725878
Only data variables are moved; coordinates stay in place. This is
58735879
consistent with the behavior of ``shift`` in pandas.
58745880
5881+
Values shifted from beyond array bounds will appear at one end of
5882+
each dimension, which are filled according to `fill_value`. For periodic
5883+
offsets instead see `roll`.
5884+
58755885
Parameters
58765886
----------
58775887
shifts : mapping of hashable to int
@@ -5926,80 +5936,87 @@ def shift(self, shifts=None, fill_value=dtypes.NA, **shifts_kwargs):
59265936

59275937
return self._replace(variables)
59285938

5929-
def roll(self, shifts=None, roll_coords=None, **shifts_kwargs):
5939+
def roll(
5940+
self,
5941+
shifts: Mapping[Hashable, int] = None,
5942+
roll_coords: bool = False,
5943+
**shifts_kwargs: int,
5944+
) -> "Dataset":
59305945
"""Roll this dataset by an offset along one or more dimensions.
59315946
5932-
Unlike shift, roll may rotate all variables, including coordinates
5947+
Unlike shift, roll treats the given dimensions as periodic, so will not
5948+
create any missing values to be filled.
5949+
5950+
Also unlike shift, roll may rotate all variables, including coordinates
59335951
if specified. The direction of rotation is consistent with
59345952
:py:func:`numpy.roll`.
59355953
59365954
Parameters
59375955
----------
5938-
shifts : dict, optional
5956+
shifts : mapping of hashable to int, optional
59395957
A dict with keys matching dimensions and values given
59405958
by integers to rotate each of the given dimensions. Positive
59415959
offsets roll to the right; negative offsets roll to the left.
5942-
roll_coords : bool
5943-
Indicates whether to roll the coordinates by the offset
5944-
The current default of roll_coords (None, equivalent to True) is
5945-
deprecated and will change to False in a future version.
5946-
Explicitly pass roll_coords to silence the warning.
5960+
roll_coords : bool, default: False
5961+
Indicates whether to roll the coordinates by the offset too.
59475962
**shifts_kwargs : {dim: offset, ...}, optional
59485963
The keyword arguments form of ``shifts``.
59495964
One of shifts or shifts_kwargs must be provided.
5965+
59505966
Returns
59515967
-------
59525968
rolled : Dataset
5953-
Dataset with the same coordinates and attributes but rolled
5954-
variables.
5969+
Dataset with the same attributes but rolled data and coordinates.
59555970
59565971
See Also
59575972
--------
59585973
shift
59595974
59605975
Examples
59615976
--------
5962-
>>> ds = xr.Dataset({"foo": ("x", list("abcde"))})
5977+
>>> ds = xr.Dataset({"foo": ("x", list("abcde"))}, coords={"x": np.arange(5)})
59635978
>>> ds.roll(x=2)
59645979
<xarray.Dataset>
59655980
Dimensions: (x: 5)
5966-
Dimensions without coordinates: x
5981+
Coordinates:
5982+
* x (x) int64 0 1 2 3 4
59675983
Data variables:
59685984
foo (x) <U1 'd' 'e' 'a' 'b' 'c'
5985+
5986+
>>> ds.roll(x=2, roll_coords=True)
5987+
<xarray.Dataset>
5988+
Dimensions: (x: 5)
5989+
Coordinates:
5990+
* x (x) int64 3 4 0 1 2
5991+
Data variables:
5992+
foo (x) <U1 'd' 'e' 'a' 'b' 'c'
5993+
59695994
"""
59705995
shifts = either_dict_or_kwargs(shifts, shifts_kwargs, "roll")
59715996
invalid = [k for k in shifts if k not in self.dims]
59725997
if invalid:
59735998
raise ValueError(f"dimensions {invalid!r} do not exist")
59745999

5975-
if roll_coords is None:
5976-
warnings.warn(
5977-
"roll_coords will be set to False in the future."
5978-
" Explicitly set roll_coords to silence warning.",
5979-
FutureWarning,
5980-
stacklevel=2,
5981-
)
5982-
roll_coords = True
5983-
59846000
unrolled_vars = () if roll_coords else self.coords
59856001

59866002
variables = {}
5987-
for k, v in self.variables.items():
6003+
for k, var in self.variables.items():
59886004
if k not in unrolled_vars:
5989-
variables[k] = v.roll(
5990-
**{k: s for k, s in shifts.items() if k in v.dims}
6005+
variables[k] = var.roll(
6006+
shifts={k: s for k, s in shifts.items() if k in var.dims}
59916007
)
59926008
else:
5993-
variables[k] = v
6009+
variables[k] = var
59946010

59956011
if roll_coords:
5996-
indexes = {}
5997-
for k, v in self.xindexes.items():
6012+
indexes: Dict[Hashable, Index] = {}
6013+
idx: pd.Index
6014+
for k, idx in self.xindexes.items():
59986015
(dim,) = self.variables[k].dims
59996016
if dim in shifts:
6000-
indexes[k] = roll_index(v, shifts[dim])
6017+
indexes[k] = roll_index(idx, shifts[dim])
60016018
else:
6002-
indexes[k] = v
6019+
indexes[k] = idx
60036020
else:
60046021
indexes = dict(self.xindexes)
60056022

xarray/core/indexes.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
Dict,
66
Hashable,
77
Iterable,
8+
Iterator,
89
Mapping,
910
Optional,
1011
Sequence,
@@ -449,7 +450,7 @@ class Indexes(collections.abc.Mapping):
449450

450451
__slots__ = ("_indexes",)
451452

452-
def __init__(self, indexes):
453+
def __init__(self, indexes: Mapping[Any, Union[pd.Index, Index]]) -> None:
453454
"""Not for public consumption.
454455
455456
Parameters
@@ -459,7 +460,7 @@ def __init__(self, indexes):
459460
"""
460461
self._indexes = indexes
461462

462-
def __iter__(self):
463+
def __iter__(self) -> Iterator[pd.Index]:
463464
return iter(self._indexes)
464465

465466
def __len__(self):
@@ -468,7 +469,7 @@ def __len__(self):
468469
def __contains__(self, key):
469470
return key in self._indexes
470471

471-
def __getitem__(self, key):
472+
def __getitem__(self, key) -> pd.Index:
472473
return self._indexes[key]
473474

474475
def __repr__(self):

xarray/tests/test_dataarray.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3378,19 +3378,10 @@ def test_roll_coords(self):
33783378

33793379
def test_roll_no_coords(self):
33803380
arr = DataArray([1, 2, 3], coords={"x": range(3)}, dims="x")
3381-
actual = arr.roll(x=1, roll_coords=False)
3381+
actual = arr.roll(x=1)
33823382
expected = DataArray([3, 1, 2], coords=[("x", [0, 1, 2])])
33833383
assert_identical(expected, actual)
33843384

3385-
def test_roll_coords_none(self):
3386-
arr = DataArray([1, 2, 3], coords={"x": range(3)}, dims="x")
3387-
3388-
with pytest.warns(FutureWarning):
3389-
actual = arr.roll(x=1, roll_coords=None)
3390-
3391-
expected = DataArray([3, 1, 2], coords=[("x", [2, 0, 1])])
3392-
assert_identical(expected, actual)
3393-
33943385
def test_copy_with_data(self):
33953386
orig = DataArray(
33963387
np.random.random(size=(2, 2)),

xarray/tests/test_dataset.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5098,25 +5098,13 @@ def test_roll_no_coords(self):
50985098
coords = {"bar": ("x", list("abc")), "x": [-4, 3, 2]}
50995099
attrs = {"meta": "data"}
51005100
ds = Dataset({"foo": ("x", [1, 2, 3])}, coords, attrs)
5101-
actual = ds.roll(x=1, roll_coords=False)
5101+
actual = ds.roll(x=1)
51025102

51035103
expected = Dataset({"foo": ("x", [3, 1, 2])}, coords, attrs)
51045104
assert_identical(expected, actual)
51055105

51065106
with pytest.raises(ValueError, match=r"dimensions"):
5107-
ds.roll(abc=321, roll_coords=False)
5108-
5109-
def test_roll_coords_none(self):
5110-
coords = {"bar": ("x", list("abc")), "x": [-4, 3, 2]}
5111-
attrs = {"meta": "data"}
5112-
ds = Dataset({"foo": ("x", [1, 2, 3])}, coords, attrs)
5113-
5114-
with pytest.warns(FutureWarning):
5115-
actual = ds.roll(x=1, roll_coords=None)
5116-
5117-
ex_coords = {"bar": ("x", list("cab")), "x": [2, -4, 3]}
5118-
expected = Dataset({"foo": ("x", [3, 1, 2])}, ex_coords, attrs)
5119-
assert_identical(expected, actual)
5107+
ds.roll(abc=321)
51205108

51215109
def test_roll_multidim(self):
51225110
# regression test for 2445

0 commit comments

Comments
 (0)