From 4e1be1bb81a13c27cbd104ca1f80eecbec738a32 Mon Sep 17 00:00:00 2001 From: Louis Stenger Date: Thu, 26 May 2022 11:42:41 +0200 Subject: [PATCH 1/5] Fix kwargs used for extrapolation in docs The current version of xarray tries to call scipy's interp1d whenever possible, and kwargs used in the user guide should reflect this. Fixes #6617 --- doc/user-guide/interpolation.rst | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/doc/user-guide/interpolation.rst b/doc/user-guide/interpolation.rst index 73c0b312241..b1d2d15cb17 100644 --- a/doc/user-guide/interpolation.rst +++ b/doc/user-guide/interpolation.rst @@ -132,8 +132,12 @@ It is now possible to safely compute the difference ``other - interpolated``. Interpolation methods --------------------- -We use :py:class:`scipy.interpolate.interp1d` for 1-dimensional interpolation and -:py:func:`scipy.interpolate.interpn` for multi-dimensional interpolation. +We use :py:class:`scipy.interpolate.interp1d` for 1-dimensional interpolation. +For multi-dimensional interpolation, an attempt is first made to decompose the +interpolation in a series of 1-dimensional interpolations, in which case +:py:class:`scipy.interpolate.interp1d` is used. If a decomposition cannot be +made (e.g. with advanced interpolation), :py:func:`scipy.interpolate.interpn` is +used. The interpolation method can be specified by the optional ``method`` argument. @@ -165,7 +169,7 @@ Additional keyword arguments can be passed to scipy's functions. [("time", np.arange(4)), ("space", [0.1, 0.2, 0.3])], ) - da.interp(time=4, space=np.linspace(-0.1, 0.5, 10), kwargs={"fill_value": None}) + da.interp(time=4, space=np.linspace(-0.1, 0.5, 10), kwargs={"fill_value": "extrapolate"}) Advanced Interpolation @@ -198,23 +202,26 @@ For example: y = xr.DataArray([0.1, 0.2, 0.3], dims="z") da.sel(x=x, y=y) - # advanced interpolation - x = xr.DataArray([0.5, 1.5, 2.5], dims="z") - y = xr.DataArray([0.15, 0.25, 0.35], dims="z") + # advanced interpolation, without extrapolation + x = xr.DataArray([0.5, 1.5, 2.5, 3.5], dims="z") + y = xr.DataArray([0.15, 0.25, 0.35, 0.45], dims="z") da.interp(x=x, y=y) where values on the original coordinates -``(x, y) = ((0.5, 0.15), (1.5, 0.25), (2.5, 0.35))`` are obtained by the -2-dimensional interpolation and mapped along a new dimension ``z``. +``(x, y) = ((0.5, 0.15), (1.5, 0.25), (2.5, 0.35), (3.5, 0.45))`` are obtained +by the 2-dimensional interpolation and mapped along a new dimension ``z``. Since +no keyword arguments are passed to the interpolation routine, no extrapolation +is performed resulting in a ``nan`` value. If you want to add a coordinate to the new dimension ``z``, you can supply -:py:class:`~xarray.DataArray` s with a coordinate, +:py:class:`~xarray.DataArray` s with a coordinate. Extrapolation can be achieved +by passing additional arguments to SciPy's ``interpnd`` function, .. ipython:: python - x = xr.DataArray([0.5, 1.5, 2.5], dims="z", coords={"z": ["a", "b", "c"]}) - y = xr.DataArray([0.15, 0.25, 0.35], dims="z", coords={"z": ["a", "b", "c"]}) - da.interp(x=x, y=y) + x = xr.DataArray([0.5, 1.5, 2.5, 3.5], dims="z", coords={"z": ["a", "b", "c", "d"]}) + y = xr.DataArray([0.15, 0.25, 0.35, 0.45], dims="z", coords={"z": ["a", "b", "c", "d"]}) + da.interp(x=x, y=y, kwargs={"fill_value": None}) For the details of the advanced indexing, see :ref:`more advanced indexing `. From 2707ed54960764b16a05598959c0d3e8ea17e076 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 May 2022 09:54:31 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/user-guide/interpolation.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/interpolation.rst b/doc/user-guide/interpolation.rst index b1d2d15cb17..2dc47e9f591 100644 --- a/doc/user-guide/interpolation.rst +++ b/doc/user-guide/interpolation.rst @@ -169,7 +169,9 @@ Additional keyword arguments can be passed to scipy's functions. [("time", np.arange(4)), ("space", [0.1, 0.2, 0.3])], ) - da.interp(time=4, space=np.linspace(-0.1, 0.5, 10), kwargs={"fill_value": "extrapolate"}) + da.interp( + time=4, space=np.linspace(-0.1, 0.5, 10), kwargs={"fill_value": "extrapolate"} + ) Advanced Interpolation @@ -220,7 +222,9 @@ by passing additional arguments to SciPy's ``interpnd`` function, .. ipython:: python x = xr.DataArray([0.5, 1.5, 2.5, 3.5], dims="z", coords={"z": ["a", "b", "c", "d"]}) - y = xr.DataArray([0.15, 0.25, 0.35, 0.45], dims="z", coords={"z": ["a", "b", "c", "d"]}) + y = xr.DataArray( + [0.15, 0.25, 0.35, 0.45], dims="z", coords={"z": ["a", "b", "c", "d"]} + ) da.interp(x=x, y=y, kwargs={"fill_value": None}) For the details of the advanced indexing, From 8f4c62343def3a2353b220276bf370c5b40c4cf5 Mon Sep 17 00:00:00 2001 From: Louis Stenger Date: Fri, 27 May 2022 14:29:22 +0200 Subject: [PATCH 3/5] Add extended summary for interp methods The extended summaries for Dataset.interp and DataArray.interp explain how the scipy interpolator is selected --- xarray/core/dataarray.py | 26 +++++++++++++++++++------- xarray/core/dataset.py | 24 ++++++++++++++++++------ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 35c0aab3fb8..d839a92849d 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -1709,28 +1709,40 @@ def interp( kwargs: Mapping[str, Any] = None, **coords_kwargs: Any, ) -> DataArray: - """Multidimensional interpolation of variables. + """Interpolate a DataArray onto new coordinates + + Performs univariate or multivariate interpolation of a DataArray onto + new coordinates using scipy's interpolation routines. If interpolating + along an existing dimension, :py:class:`scipy.interpolate.interp1d` is + called. When interpolating along multiple existing dimensions, an + attempt is made to decompose the interpolation into multiple + 1-dimensional interpolations. If this is possible, + :py:class:`scipy.interpolate.interp1d` is called. Otherwise, + :py:func:`scipy.interpolate.interpn` is called. Parameters ---------- coords : dict, optional Mapping from dimension names to the new coordinates. - New coordinate can be an scalar, array-like or DataArray. + New coordinate can be a scalar, array-like or DataArray. If DataArrays are passed as new coordinates, their dimensions are used for the broadcasting. Missing values are skipped. method : str, default: "linear" - The method used to interpolate. Choose from + The method used to interpolate. The method should be supported by + the scipy interpolator: + + - ``interp1d``: {"linear", "nearest", "zero", "slinear", + "quadratic", "cubic"} + - ``interpn``: {"linear", "nearest"} - - {"linear", "nearest"} for multidimensional array, - - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} for 1-dimensional array. assume_sorted : bool, optional If False, values of x can be in any order and they are sorted first. If True, x has to be an array of monotonically increasing values. kwargs : dict Additional keyword arguments passed to scipy's interpolator. Valid - options and their behavior depend on if 1-dimensional or - multi-dimensional interpolation is used. + options and their behavior depend whether ``interp1d`` or + ``interpn`` is used. **coords_kwargs : {dim: coordinate, ...}, optional The keyword arguments form of ``coords``. One of coords or coords_kwargs must be provided. diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 8cf5138c259..7cc81a84ad6 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -3036,7 +3036,16 @@ def interp( method_non_numeric: str = "nearest", **coords_kwargs: Any, ) -> Dataset: - """Multidimensional interpolation of Dataset. + """Interpolate a Dataset onto new coordinates + + Performs univariate or multivariate interpolation of a Dataset onto + new coordinates using scipy's interpolation routines. If interpolating + along an existing dimension, :py:class:`scipy.interpolate.interp1d` is + called. When interpolating along multiple existing dimensions, an + attempt is made to decompose the interpolation into multiple + 1-dimensional interpolations. If this is possible, + :py:class:`scipy.interpolate.interp1d` is called. Otherwise, + :py:func:`scipy.interpolate.interpn` is called. Parameters ---------- @@ -3046,9 +3055,12 @@ def interp( If DataArrays are passed as new coordinates, their dimensions are used for the broadcasting. Missing values are skipped. method : str, optional - {"linear", "nearest"} for multidimensional array, - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} - for 1-dimensional array. "linear" is used by default. + The method used to interpolate. The method should be supported by + the scipy interpolator: + + - ``interp1d``: {"linear", "nearest", "zero", "slinear", + "quadratic", "cubic"} + - ``interpn``: {"linear", "nearest"} assume_sorted : bool, optional If False, values of coordinates that are interpolated over can be in any order and they are sorted first. If True, interpolated @@ -3056,8 +3068,8 @@ def interp( values. kwargs : dict, optional Additional keyword arguments passed to scipy's interpolator. Valid - options and their behavior depend on if 1-dimensional or - multi-dimensional interpolation is used. + options and their behavior depend whether ``interp1d`` or + ``interpn`` is used. method_non_numeric : {"nearest", "pad", "ffill", "backfill", "bfill"}, optional Method for non-numeric types. Passed on to :py:meth:`Dataset.reindex`. ``"nearest"`` is used by default. From a5d6ce92fa2f22cfd9b7b51d39ad747ed41d6405 Mon Sep 17 00:00:00 2001 From: Louis Stenger Date: Fri, 27 May 2022 14:32:47 +0200 Subject: [PATCH 4/5] Update interp_like extended summary Explains how the scipy interpolator is chosen, similarly as done in Dataset.interp and DataArray.interp --- xarray/core/dataarray.py | 16 +++++++++++++--- xarray/core/dataset.py | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index d839a92849d..a06f5b60910 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -1853,6 +1853,13 @@ def interp_like( """Interpolate this object onto the coordinates of another object, filling out of range values with NaN. + If interpolating along a single existing dimension, + :py:class:`scipy.interpolate.interp1d` is called. When interpolating + along multiple existing dimensions, an attempt is made to decompose the + interpolation into multiple 1-dimensional interpolations. If this is + possible, :py:class:`scipy.interpolate.interp1d` is called. Otherwise, + :py:func:`scipy.interpolate.interpn` is called. + Parameters ---------- other : Dataset or DataArray @@ -1860,10 +1867,13 @@ def interp_like( names to an 1d array-like, which provides coordinates upon which to index the variables in this dataset. Missing values are skipped. method : str, default: "linear" - The method used to interpolate. Choose from + The method used to interpolate. The method should be supported by + the scipy interpolator: + + - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} + when ``interp1d`` is called. + - {"linear", "nearest"} when ``interpn`` is called. - - {"linear", "nearest"} for multidimensional array, - - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} for 1-dimensional array. assume_sorted : bool, optional If False, values of coordinates that are interpolated over can be in any order and they are sorted first. If True, interpolated diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 7cc81a84ad6..14828c0e71e 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -3311,6 +3311,13 @@ def interp_like( """Interpolate this object onto the coordinates of another object, filling the out of range values with NaN. + If interpolating along a single existing dimension, + :py:class:`scipy.interpolate.interp1d` is called. When interpolating + along multiple existing dimensions, an attempt is made to decompose the + interpolation into multiple 1-dimensional interpolations. If this is + possible, :py:class:`scipy.interpolate.interp1d` is called. Otherwise, + :py:func:`scipy.interpolate.interpn` is called. + Parameters ---------- other : Dataset or DataArray @@ -3318,9 +3325,12 @@ def interp_like( names to an 1d array-like, which provides coordinates upon which to index the variables in this dataset. Missing values are skipped. method : str, optional - {"linear", "nearest"} for multidimensional array, - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} - for 1-dimensional array. 'linear' is used by default. + The method used to interpolate. The method should be supported by + the scipy interpolator: + + - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} + when ``interp1d`` is called. + - {"linear", "nearest"} when ``interpn`` is called. assume_sorted : bool, optional If False, values of coordinates that are interpolated over can be in any order and they are sorted first. If True, interpolated From 75ebd799c4919e0db81e65df1a1893d207f281b1 Mon Sep 17 00:00:00 2001 From: Louis Stenger Date: Fri, 27 May 2022 14:33:49 +0200 Subject: [PATCH 5/5] Add the "polynomial" option to interp(_like) When scipy.interpolate.interp1d is called, it is possible to interpolate with the polynomial method if the `order` kwarg is provided. --- xarray/core/dataarray.py | 10 +++++++--- xarray/core/dataset.py | 12 +++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index a06f5b60910..ea945ad196b 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -1732,9 +1732,11 @@ def interp( the scipy interpolator: - ``interp1d``: {"linear", "nearest", "zero", "slinear", - "quadratic", "cubic"} + "quadratic", "cubic", "polynomial"} - ``interpn``: {"linear", "nearest"} + If ``"polynomial"`` is passed, the ``order`` keyword argument must + also be provided. assume_sorted : bool, optional If False, values of x can be in any order and they are sorted first. If True, x has to be an array of monotonically increasing @@ -1870,10 +1872,12 @@ def interp_like( The method used to interpolate. The method should be supported by the scipy interpolator: - - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} - when ``interp1d`` is called. + - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic", + "polynomial"} when ``interp1d`` is called. - {"linear", "nearest"} when ``interpn`` is called. + If ``"polynomial"`` is passed, the ``order`` keyword argument must + also be provided. assume_sorted : bool, optional If False, values of coordinates that are interpolated over can be in any order and they are sorted first. If True, interpolated diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 14828c0e71e..73dd187b27a 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -3059,8 +3059,11 @@ def interp( the scipy interpolator: - ``interp1d``: {"linear", "nearest", "zero", "slinear", - "quadratic", "cubic"} + "quadratic", "cubic", "polynomial"} - ``interpn``: {"linear", "nearest"} + + If ``"polynomial"`` is passed, the ``order`` keyword argument must + also be provided. assume_sorted : bool, optional If False, values of coordinates that are interpolated over can be in any order and they are sorted first. If True, interpolated @@ -3328,9 +3331,12 @@ def interp_like( The method used to interpolate. The method should be supported by the scipy interpolator: - - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic"} - when ``interp1d`` is called. + - {"linear", "nearest", "zero", "slinear", "quadratic", "cubic", + "polynomial"} when ``interp1d`` is called. - {"linear", "nearest"} when ``interpn`` is called. + + If ``"polynomial"`` is passed, the ``order`` keyword argument must + also be provided. assume_sorted : bool, optional If False, values of coordinates that are interpolated over can be in any order and they are sorted first. If True, interpolated