Skip to content

Commit 5f55d41

Browse files
authored
Remove sel_points (#3261)
* remove .[i ]sel_points * dangling decorator * whatsnew
1 parent 3f1b879 commit 5f55d41

File tree

6 files changed

+8
-411
lines changed

6 files changed

+8
-411
lines changed

doc/indexing.rst

-8
Original file line numberDiff line numberDiff line change
@@ -392,14 +392,6 @@ These methods may also be applied to ``Dataset`` objects
392392
You may find increased performance by loading your data into memory first,
393393
e.g., with :py:meth:`~xarray.Dataset.load`.
394394

395-
.. note::
396-
397-
Vectorized indexing is a new feature in v0.10.
398-
In older versions of xarray, dimensions of indexers are ignored.
399-
Dedicated methods for some advanced indexing use cases,
400-
``isel_points`` and ``sel_points`` are now deprecated.
401-
See :ref:`more_advanced_indexing` for their alternative.
402-
403395
.. note::
404396

405397
If an indexer is a :py:meth:`~xarray.DataArray`, its coordinates should not

doc/whats-new.rst

+8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ v0.13.0 (unreleased)
2121
This release increases the minimum required Python version from 3.5.0 to 3.5.3
2222
(:issue:`3089`). By `Guido Imperiale <https://github.com/crusaderky>`_.
2323

24+
Breaking changes
25+
~~~~~~~~~~~~~~~~
26+
27+
The ``isel_points`` and ``sel_points`` methods are removed, having been deprecated
28+
since v0.10.0. These are redundant with the ``isel`` / ``sel`` methods.
29+
See :ref:`vectorized_indexing` for the details
30+
By `Maximilian Roos <https://github.com/max-sixty>`_
31+
2432
New functions/methods
2533
~~~~~~~~~~~~~~~~~~~~~
2634

xarray/core/dataarray.py

-26
Original file line numberDiff line numberDiff line change
@@ -1026,32 +1026,6 @@ def sel(
10261026
)
10271027
return self._from_temp_dataset(ds)
10281028

1029-
def isel_points(self, dim="points", **indexers) -> "DataArray":
1030-
"""Return a new DataArray whose data is given by pointwise integer
1031-
indexing along the specified dimension(s).
1032-
1033-
See Also
1034-
--------
1035-
Dataset.isel_points
1036-
"""
1037-
ds = self._to_temp_dataset().isel_points(dim=dim, **indexers)
1038-
return self._from_temp_dataset(ds)
1039-
1040-
def sel_points(
1041-
self, dim="points", method=None, tolerance=None, **indexers
1042-
) -> "DataArray":
1043-
"""Return a new DataArray whose dataset is given by pointwise selection
1044-
of index labels along the specified dimension(s).
1045-
1046-
See Also
1047-
--------
1048-
Dataset.sel_points
1049-
"""
1050-
ds = self._to_temp_dataset().sel_points(
1051-
dim=dim, method=method, tolerance=tolerance, **indexers
1052-
)
1053-
return self._from_temp_dataset(ds)
1054-
10551029
def broadcast_like(
10561030
self, other: Union["DataArray", Dataset], exclude: Iterable[Hashable] = None
10571031
) -> "DataArray":

xarray/core/dataset.py

-209
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
duck_array_ops,
4141
formatting,
4242
groupby,
43-
indexing,
4443
ops,
4544
pdcompat,
4645
resample,
@@ -1999,214 +1998,6 @@ def sel(
19991998
result = self.isel(indexers=pos_indexers, drop=drop)
20001999
return result._overwrite_indexes(new_indexes)
20012000

2002-
def isel_points(self, dim: Any = "points", **indexers: Any) -> "Dataset":
2003-
"""Returns a new dataset with each array indexed pointwise along the
2004-
specified dimension(s).
2005-
2006-
This method selects pointwise values from each array and is akin to
2007-
the NumPy indexing behavior of `arr[[0, 1], [0, 1]]`, except this
2008-
method does not require knowing the order of each array's dimensions.
2009-
2010-
Parameters
2011-
----------
2012-
dim : hashable or DataArray or pandas.Index or other list-like object,
2013-
optional
2014-
Name of the dimension to concatenate along. If dim is provided as a
2015-
hashable, it must be a new dimension name, in which case it is added
2016-
along axis=0. If dim is provided as a DataArray or Index or
2017-
list-like object, its name, which must not be present in the
2018-
dataset, is used as the dimension to concatenate along and the
2019-
values are added as a coordinate.
2020-
**indexers : {dim: indexer, ...}
2021-
Keyword arguments with names matching dimensions and values given
2022-
by array-like objects. All indexers must be the same length and
2023-
1 dimensional.
2024-
2025-
Returns
2026-
-------
2027-
obj : Dataset
2028-
A new Dataset with the same contents as this dataset, except each
2029-
array and dimension is indexed by the appropriate indexers. With
2030-
pointwise indexing, the new Dataset will always be a copy of the
2031-
original.
2032-
2033-
See Also
2034-
--------
2035-
Dataset.sel
2036-
Dataset.isel
2037-
Dataset.sel_points
2038-
DataArray.isel_points
2039-
""" # noqa
2040-
warnings.warn(
2041-
"Dataset.isel_points is deprecated: use Dataset.isel()" "instead.",
2042-
DeprecationWarning,
2043-
stacklevel=2,
2044-
)
2045-
2046-
indexer_dims = set(indexers)
2047-
2048-
def take(variable, slices):
2049-
# Note: remove helper function when once when numpy
2050-
# supports vindex https://github.com/numpy/numpy/pull/6075
2051-
if hasattr(variable.data, "vindex"):
2052-
# Special case for dask backed arrays to use vectorised list
2053-
# indexing
2054-
sel = variable.data.vindex[slices]
2055-
else:
2056-
# Otherwise assume backend is numpy array with 'fancy' indexing
2057-
sel = variable.data[slices]
2058-
return sel
2059-
2060-
def relevant_keys(mapping):
2061-
return [
2062-
k for k, v in mapping.items() if any(d in indexer_dims for d in v.dims)
2063-
]
2064-
2065-
coords = relevant_keys(self.coords)
2066-
indexers = {k: np.asarray(v) for k, v in indexers.items()}
2067-
non_indexed_dims = set(self.dims) - indexer_dims
2068-
non_indexed_coords = set(self.coords) - set(coords)
2069-
2070-
# All the indexers should be iterables
2071-
# Check that indexers are valid dims, integers, and 1D
2072-
for k, v in indexers.items():
2073-
if k not in self.dims:
2074-
raise ValueError("dimension %s does not exist" % k)
2075-
if v.dtype.kind != "i": # type: ignore
2076-
raise TypeError("Indexers must be integers")
2077-
if v.ndim != 1: # type: ignore
2078-
raise ValueError("Indexers must be 1 dimensional")
2079-
2080-
# all the indexers should have the same length
2081-
lengths = {len(v) for k, v in indexers.items()}
2082-
if len(lengths) > 1:
2083-
raise ValueError("All indexers must be the same length")
2084-
2085-
# Existing dimensions are not valid choices for the dim argument
2086-
if isinstance(dim, str):
2087-
if dim in self.dims:
2088-
# dim is an invalid string
2089-
raise ValueError(
2090-
"Existing dimension names are not valid "
2091-
"choices for the dim argument in sel_points"
2092-
)
2093-
2094-
elif hasattr(dim, "dims"):
2095-
# dim is a DataArray or Coordinate
2096-
if dim.name in self.dims:
2097-
# dim already exists
2098-
raise ValueError(
2099-
"Existing dimensions are not valid choices "
2100-
"for the dim argument in sel_points"
2101-
)
2102-
2103-
# Set the new dim_name, and optionally the new dim coordinate
2104-
# dim is either an array-like or a string
2105-
if not utils.is_scalar(dim):
2106-
# dim is array like get name or assign 'points', get as variable
2107-
dim_name = "points" if not hasattr(dim, "name") else dim.name
2108-
dim_coord = as_variable(dim, name=dim_name)
2109-
else:
2110-
# dim is a string
2111-
dim_name = dim
2112-
dim_coord = None # type: ignore
2113-
2114-
reordered = self.transpose(*list(indexer_dims), *list(non_indexed_dims))
2115-
2116-
variables = OrderedDict() # type: ignore
2117-
2118-
for name, var in reordered.variables.items():
2119-
if name in indexers or any(d in indexer_dims for d in var.dims):
2120-
# slice if var is an indexer or depends on an indexed dim
2121-
slc = [indexers.get(k, slice(None)) for k in var.dims]
2122-
2123-
var_dims = [dim_name] + [d for d in var.dims if d in non_indexed_dims]
2124-
selection = take(var, tuple(slc))
2125-
var_subset = type(var)(var_dims, selection, var.attrs)
2126-
variables[name] = var_subset
2127-
else:
2128-
# If not indexed just add it back to variables or coordinates
2129-
variables[name] = var
2130-
2131-
coord_names = (set(coords) & set(variables)) | non_indexed_coords
2132-
2133-
dset = self._replace_vars_and_dims(variables, coord_names=coord_names)
2134-
# Add the dim coord to the new dset. Must be done after creation
2135-
# because_replace_vars_and_dims can only access existing coords,
2136-
# not add new ones
2137-
if dim_coord is not None:
2138-
dset.coords[dim_name] = dim_coord
2139-
return dset
2140-
2141-
def sel_points(
2142-
self,
2143-
dim: Any = "points",
2144-
method: str = None,
2145-
tolerance: Number = None,
2146-
**indexers: Any
2147-
):
2148-
"""Returns a new dataset with each array indexed pointwise by tick
2149-
labels along the specified dimension(s).
2150-
2151-
In contrast to `Dataset.isel_points`, indexers for this method should
2152-
use labels instead of integers.
2153-
2154-
In contrast to `Dataset.sel`, this method selects points along the
2155-
diagonal of multi-dimensional arrays, not the intersection.
2156-
2157-
Parameters
2158-
----------
2159-
dim : hashable or DataArray or pandas.Index or other list-like object,
2160-
optional
2161-
Name of the dimension to concatenate along. If dim is provided as a
2162-
hashable, it must be a new dimension name, in which case it is added
2163-
along axis=0. If dim is provided as a DataArray or Index or
2164-
list-like object, its name, which must not be present in the
2165-
dataset, is used as the dimension to concatenate along and the
2166-
values are added as a coordinate.
2167-
method : {None, 'nearest', 'pad'/'ffill', 'backfill'/'bfill'}, optional
2168-
Method to use for inexact matches (requires pandas>=0.16):
2169-
2170-
* None (default): only exact matches
2171-
* pad / ffill: propagate last valid index value forward
2172-
* backfill / bfill: propagate next valid index value backward
2173-
* nearest: use nearest valid index value
2174-
tolerance : optional
2175-
Maximum distance between original and new labels for inexact
2176-
matches. The values of the index at the matching locations must
2177-
satisfy the equation ``abs(index[indexer] - target) <= tolerance``.
2178-
Requires pandas>=0.17.
2179-
**indexers : {dim: indexer, ...}
2180-
Keyword arguments with names matching dimensions and values given
2181-
by array-like objects. All indexers must be the same length and
2182-
1 dimensional.
2183-
2184-
Returns
2185-
-------
2186-
obj : Dataset
2187-
A new Dataset with the same contents as this dataset, except each
2188-
array and dimension is indexed by the appropriate indexers. With
2189-
pointwise indexing, the new Dataset will always be a copy of the
2190-
original.
2191-
2192-
See Also
2193-
--------
2194-
Dataset.sel
2195-
Dataset.isel
2196-
Dataset.isel_points
2197-
DataArray.sel_points
2198-
""" # noqa
2199-
warnings.warn(
2200-
"Dataset.sel_points is deprecated: use Dataset.sel()" "instead.",
2201-
DeprecationWarning,
2202-
stacklevel=2,
2203-
)
2204-
2205-
pos_indexers, _ = indexing.remap_label_indexers(
2206-
self, indexers, method=method, tolerance=tolerance
2207-
)
2208-
return self.isel_points(dim=dim, **pos_indexers)
2209-
22102001
def broadcast_like(
22112002
self, other: Union["Dataset", "DataArray"], exclude: Iterable[Hashable] = None
22122003
) -> "Dataset":

xarray/tests/test_dataarray.py

-58
Original file line numberDiff line numberDiff line change
@@ -1001,64 +1001,6 @@ def test_isel_drop(self):
10011001
selected = data.isel(x=0, drop=False)
10021002
assert_identical(expected, selected)
10031003

1004-
@pytest.mark.filterwarnings("ignore:Dataset.isel_points")
1005-
def test_isel_points(self):
1006-
shape = (10, 5, 6)
1007-
np_array = np.random.random(shape)
1008-
da = DataArray(
1009-
np_array, dims=["time", "y", "x"], coords={"time": np.arange(0, 100, 10)}
1010-
)
1011-
y = [1, 3]
1012-
x = [3, 0]
1013-
1014-
expected = da.values[:, y, x]
1015-
1016-
actual = da.isel_points(y=y, x=x, dim="test_coord")
1017-
assert actual.coords["test_coord"].shape == (len(y),)
1018-
assert list(actual.coords) == ["time"]
1019-
assert actual.dims == ("test_coord", "time")
1020-
1021-
actual = da.isel_points(y=y, x=x)
1022-
assert "points" in actual.dims
1023-
# Note that because xarray always concatenates along the first
1024-
# dimension, We must transpose the result to match the numpy style of
1025-
# concatenation.
1026-
np.testing.assert_equal(actual.T, expected)
1027-
1028-
# a few corner cases
1029-
da.isel_points(time=[1, 2], x=[2, 2], y=[3, 4])
1030-
np.testing.assert_allclose(
1031-
da.isel_points(time=[1], x=[2], y=[4]).values.squeeze(),
1032-
np_array[1, 4, 2].squeeze(),
1033-
)
1034-
da.isel_points(time=[1, 2])
1035-
y = [-1, 0]
1036-
x = [-2, 2]
1037-
expected = da.values[:, y, x]
1038-
actual = da.isel_points(x=x, y=y).values
1039-
np.testing.assert_equal(actual.T, expected)
1040-
1041-
# test that the order of the indexers doesn't matter
1042-
assert_identical(da.isel_points(y=y, x=x), da.isel_points(x=x, y=y))
1043-
1044-
# make sure we're raising errors in the right places
1045-
with raises_regex(ValueError, "All indexers must be the same length"):
1046-
da.isel_points(y=[1, 2], x=[1, 2, 3])
1047-
with raises_regex(ValueError, "dimension bad_key does not exist"):
1048-
da.isel_points(bad_key=[1, 2])
1049-
with raises_regex(TypeError, "Indexers must be integers"):
1050-
da.isel_points(y=[1.5, 2.2])
1051-
with raises_regex(TypeError, "Indexers must be integers"):
1052-
da.isel_points(x=[1, 2, 3], y=slice(3))
1053-
with raises_regex(ValueError, "Indexers must be 1 dimensional"):
1054-
da.isel_points(y=1, x=2)
1055-
with raises_regex(ValueError, "Existing dimension names are not"):
1056-
da.isel_points(y=[1, 2], x=[1, 2], dim="x")
1057-
1058-
# using non string dims
1059-
actual = da.isel_points(y=[1, 2], x=[1, 2], dim=["A", "B"])
1060-
assert "points" in actual.coords
1061-
10621004
def test_loc(self):
10631005
self.ds["x"] = ("x", np.array(list("abcdefghij")))
10641006
da = self.ds["foo"]

0 commit comments

Comments
 (0)