Skip to content

Commit 0d95eba

Browse files
authored
Fix interp bug when indexer shares coordinates with array (#3758)
* added test demonstrating interp bug for nd indexes sharing coordinate with array * fix test so it works with sel * support shared dimensions in interp * isort fixes * update whats new * Revert "isort fixes" This reverts commit 5df6c9c. * test requires scipy
1 parent 7f4f027 commit 0d95eba

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

doc/whats-new.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ New Features
5454

5555
Bug fixes
5656
~~~~~~~~~
57+
- Fix :py:meth:`Dataset.interp` when indexing array shares coordinates with the
58+
indexed variable (:issue:`3252`).
59+
By `David Huard <https://github.com/huard>`_.
5760

5861
- Fix alignment with ``join="override"`` when some dimensions are unindexed. (:issue:`3681`).
5962
By `Deepak Cherian <https://github.com/dcherian>`_.

xarray/core/dataset.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,6 +2574,17 @@ def interp(
25742574
coords = either_dict_or_kwargs(coords, coords_kwargs, "interp")
25752575
indexers = dict(self._validate_interp_indexers(coords))
25762576

2577+
if coords:
2578+
# This avoids broadcasting over coordinates that are both in
2579+
# the original array AND in the indexing array. It essentially
2580+
# forces interpolation along the shared coordinates.
2581+
sdims = (
2582+
set(self.dims)
2583+
.intersection(*[set(nx.dims) for nx in indexers.values()])
2584+
.difference(coords.keys())
2585+
)
2586+
indexers.update({d: self.variables[d] for d in sdims})
2587+
25772588
obj = self if assume_sorted else self.sortby([k for k in coords])
25782589

25792590
def maybe_variable(obj, k):

xarray/tests/test_interp.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,36 @@ def test_interpolate_nd(case):
244244
assert_allclose(actual.transpose("y", "z"), expected)
245245

246246

247+
@requires_scipy
248+
def test_interpolate_nd_nd():
249+
"""Interpolate nd array with an nd indexer sharing coordinates."""
250+
# Create original array
251+
a = [0, 2]
252+
x = [0, 1, 2]
253+
da = xr.DataArray(
254+
np.arange(6).reshape(2, 3), dims=("a", "x"), coords={"a": a, "x": x}
255+
)
256+
257+
# Create indexer into `a` with dimensions (y, x)
258+
y = [10]
259+
c = {"x": x, "y": y}
260+
ia = xr.DataArray([[1, 2, 2]], dims=("y", "x"), coords=c)
261+
out = da.interp(a=ia)
262+
expected = xr.DataArray([[1.5, 4, 5]], dims=("y", "x"), coords=c)
263+
xr.testing.assert_allclose(out.drop_vars("a"), expected)
264+
265+
# If the *shared* indexing coordinates do not match, interp should fail.
266+
with pytest.raises(ValueError):
267+
c = {"x": [1], "y": y}
268+
ia = xr.DataArray([[1]], dims=("y", "x"), coords=c)
269+
da.interp(a=ia)
270+
271+
with pytest.raises(ValueError):
272+
c = {"x": [5, 6, 7], "y": y}
273+
ia = xr.DataArray([[1]], dims=("y", "x"), coords=c)
274+
da.interp(a=ia)
275+
276+
247277
@pytest.mark.parametrize("method", ["linear"])
248278
@pytest.mark.parametrize("case", [0, 1])
249279
def test_interpolate_scalar(method, case):

0 commit comments

Comments
 (0)