274 lines
8.9 KiB
Python
274 lines
8.9 KiB
Python
|
"""
|
||
|
Convenience interface to N-D interpolation
|
||
|
|
||
|
.. versionadded:: 0.9
|
||
|
|
||
|
"""
|
||
|
import numpy as np
|
||
|
from .interpnd import LinearNDInterpolator, NDInterpolatorBase, \
|
||
|
CloughTocher2DInterpolator, _ndim_coords_from_arrays
|
||
|
from scipy.spatial import cKDTree
|
||
|
|
||
|
__all__ = ['griddata', 'NearestNDInterpolator', 'LinearNDInterpolator',
|
||
|
'CloughTocher2DInterpolator']
|
||
|
|
||
|
#------------------------------------------------------------------------------
|
||
|
# Nearest-neighbor interpolation
|
||
|
#------------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
class NearestNDInterpolator(NDInterpolatorBase):
|
||
|
"""NearestNDInterpolator(x, y).
|
||
|
|
||
|
Nearest-neighbor interpolation in N > 1 dimensions.
|
||
|
|
||
|
.. versionadded:: 0.9
|
||
|
|
||
|
Methods
|
||
|
-------
|
||
|
__call__
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
x : (Npoints, Ndims) ndarray of floats
|
||
|
Data point coordinates.
|
||
|
y : (Npoints,) ndarray of float or complex
|
||
|
Data values.
|
||
|
rescale : boolean, optional
|
||
|
Rescale points to unit cube before performing interpolation.
|
||
|
This is useful if some of the input dimensions have
|
||
|
incommensurable units and differ by many orders of magnitude.
|
||
|
|
||
|
.. versionadded:: 0.14.0
|
||
|
tree_options : dict, optional
|
||
|
Options passed to the underlying ``cKDTree``.
|
||
|
|
||
|
.. versionadded:: 0.17.0
|
||
|
|
||
|
|
||
|
Notes
|
||
|
-----
|
||
|
Uses ``scipy.spatial.cKDTree``
|
||
|
|
||
|
Examples
|
||
|
--------
|
||
|
We can interpolate values on a 2D plane:
|
||
|
|
||
|
>>> from scipy.interpolate import NearestNDInterpolator
|
||
|
>>> import numpy as np
|
||
|
>>> import matplotlib.pyplot as plt
|
||
|
>>> rng = np.random.default_rng()
|
||
|
>>> x = rng.random(10) - 0.5
|
||
|
>>> y = rng.random(10) - 0.5
|
||
|
>>> z = np.hypot(x, y)
|
||
|
>>> X = np.linspace(min(x), max(x))
|
||
|
>>> Y = np.linspace(min(y), max(y))
|
||
|
>>> X, Y = np.meshgrid(X, Y) # 2D grid for interpolation
|
||
|
>>> interp = NearestNDInterpolator(list(zip(x, y)), z)
|
||
|
>>> Z = interp(X, Y)
|
||
|
>>> plt.pcolormesh(X, Y, Z, shading='auto')
|
||
|
>>> plt.plot(x, y, "ok", label="input point")
|
||
|
>>> plt.legend()
|
||
|
>>> plt.colorbar()
|
||
|
>>> plt.axis("equal")
|
||
|
>>> plt.show()
|
||
|
|
||
|
See also
|
||
|
--------
|
||
|
griddata :
|
||
|
Interpolate unstructured D-D data.
|
||
|
LinearNDInterpolator :
|
||
|
Piecewise linear interpolant in N dimensions.
|
||
|
CloughTocher2DInterpolator :
|
||
|
Piecewise cubic, C1 smooth, curvature-minimizing interpolant in 2D.
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(self, x, y, rescale=False, tree_options=None):
|
||
|
NDInterpolatorBase.__init__(self, x, y, rescale=rescale,
|
||
|
need_contiguous=False,
|
||
|
need_values=False)
|
||
|
if tree_options is None:
|
||
|
tree_options = dict()
|
||
|
self.tree = cKDTree(self.points, **tree_options)
|
||
|
self.values = np.asarray(y)
|
||
|
|
||
|
def __call__(self, *args):
|
||
|
"""
|
||
|
Evaluate interpolator at given points.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
x1, x2, ... xn : array-like of float
|
||
|
Points where to interpolate data at.
|
||
|
x1, x2, ... xn can be array-like of float with broadcastable shape.
|
||
|
or x1 can be array-like of float with shape ``(..., ndim)``
|
||
|
|
||
|
"""
|
||
|
xi = _ndim_coords_from_arrays(args, ndim=self.points.shape[1])
|
||
|
xi = self._check_call_shape(xi)
|
||
|
xi = self._scale_x(xi)
|
||
|
dist, i = self.tree.query(xi)
|
||
|
return self.values[i]
|
||
|
|
||
|
|
||
|
#------------------------------------------------------------------------------
|
||
|
# Convenience interface function
|
||
|
#------------------------------------------------------------------------------
|
||
|
|
||
|
def griddata(points, values, xi, method='linear', fill_value=np.nan,
|
||
|
rescale=False):
|
||
|
"""
|
||
|
Interpolate unstructured D-D data.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
points : 2-D ndarray of floats with shape (n, D), or length D tuple of 1-D ndarrays with shape (n,).
|
||
|
Data point coordinates.
|
||
|
values : ndarray of float or complex, shape (n,)
|
||
|
Data values.
|
||
|
xi : 2-D ndarray of floats with shape (m, D), or length D tuple of ndarrays broadcastable to the same shape.
|
||
|
Points at which to interpolate data.
|
||
|
method : {'linear', 'nearest', 'cubic'}, optional
|
||
|
Method of interpolation. One of
|
||
|
|
||
|
``nearest``
|
||
|
return the value at the data point closest to
|
||
|
the point of interpolation. See `NearestNDInterpolator` for
|
||
|
more details.
|
||
|
|
||
|
``linear``
|
||
|
tessellate the input point set to N-D
|
||
|
simplices, and interpolate linearly on each simplex. See
|
||
|
`LinearNDInterpolator` for more details.
|
||
|
|
||
|
``cubic`` (1-D)
|
||
|
return the value determined from a cubic
|
||
|
spline.
|
||
|
|
||
|
``cubic`` (2-D)
|
||
|
return the value determined from a
|
||
|
piecewise cubic, continuously differentiable (C1), and
|
||
|
approximately curvature-minimizing polynomial surface. See
|
||
|
`CloughTocher2DInterpolator` for more details.
|
||
|
fill_value : float, optional
|
||
|
Value used to fill in for requested points outside of the
|
||
|
convex hull of the input points. If not provided, then the
|
||
|
default is ``nan``. This option has no effect for the
|
||
|
'nearest' method.
|
||
|
rescale : bool, optional
|
||
|
Rescale points to unit cube before performing interpolation.
|
||
|
This is useful if some of the input dimensions have
|
||
|
incommensurable units and differ by many orders of magnitude.
|
||
|
|
||
|
.. versionadded:: 0.14.0
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
ndarray
|
||
|
Array of interpolated values.
|
||
|
|
||
|
Notes
|
||
|
-----
|
||
|
|
||
|
.. versionadded:: 0.9
|
||
|
|
||
|
For data on a regular grid use `interpn` instead.
|
||
|
|
||
|
Examples
|
||
|
--------
|
||
|
|
||
|
Suppose we want to interpolate the 2-D function
|
||
|
|
||
|
>>> import numpy as np
|
||
|
>>> def func(x, y):
|
||
|
... return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2
|
||
|
|
||
|
on a grid in [0, 1]x[0, 1]
|
||
|
|
||
|
>>> grid_x, grid_y = np.mgrid[0:1:100j, 0:1:200j]
|
||
|
|
||
|
but we only know its values at 1000 data points:
|
||
|
|
||
|
>>> rng = np.random.default_rng()
|
||
|
>>> points = rng.random((1000, 2))
|
||
|
>>> values = func(points[:,0], points[:,1])
|
||
|
|
||
|
This can be done with `griddata` -- below we try out all of the
|
||
|
interpolation methods:
|
||
|
|
||
|
>>> from scipy.interpolate import griddata
|
||
|
>>> grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')
|
||
|
>>> grid_z1 = griddata(points, values, (grid_x, grid_y), method='linear')
|
||
|
>>> grid_z2 = griddata(points, values, (grid_x, grid_y), method='cubic')
|
||
|
|
||
|
One can see that the exact result is reproduced by all of the
|
||
|
methods to some degree, but for this smooth function the piecewise
|
||
|
cubic interpolant gives the best results:
|
||
|
|
||
|
>>> import matplotlib.pyplot as plt
|
||
|
>>> plt.subplot(221)
|
||
|
>>> plt.imshow(func(grid_x, grid_y).T, extent=(0,1,0,1), origin='lower')
|
||
|
>>> plt.plot(points[:,0], points[:,1], 'k.', ms=1)
|
||
|
>>> plt.title('Original')
|
||
|
>>> plt.subplot(222)
|
||
|
>>> plt.imshow(grid_z0.T, extent=(0,1,0,1), origin='lower')
|
||
|
>>> plt.title('Nearest')
|
||
|
>>> plt.subplot(223)
|
||
|
>>> plt.imshow(grid_z1.T, extent=(0,1,0,1), origin='lower')
|
||
|
>>> plt.title('Linear')
|
||
|
>>> plt.subplot(224)
|
||
|
>>> plt.imshow(grid_z2.T, extent=(0,1,0,1), origin='lower')
|
||
|
>>> plt.title('Cubic')
|
||
|
>>> plt.gcf().set_size_inches(6, 6)
|
||
|
>>> plt.show()
|
||
|
|
||
|
See Also
|
||
|
--------
|
||
|
LinearNDInterpolator :
|
||
|
Piecewise linear interpolant in N dimensions.
|
||
|
NearestNDInterpolator :
|
||
|
Nearest-neighbor interpolation in N dimensions.
|
||
|
CloughTocher2DInterpolator :
|
||
|
Piecewise cubic, C1 smooth, curvature-minimizing interpolant in 2D.
|
||
|
|
||
|
"""
|
||
|
|
||
|
points = _ndim_coords_from_arrays(points)
|
||
|
|
||
|
if points.ndim < 2:
|
||
|
ndim = points.ndim
|
||
|
else:
|
||
|
ndim = points.shape[-1]
|
||
|
|
||
|
if ndim == 1 and method in ('nearest', 'linear', 'cubic'):
|
||
|
from ._interpolate import interp1d
|
||
|
points = points.ravel()
|
||
|
if isinstance(xi, tuple):
|
||
|
if len(xi) != 1:
|
||
|
raise ValueError("invalid number of dimensions in xi")
|
||
|
xi, = xi
|
||
|
# Sort points/values together, necessary as input for interp1d
|
||
|
idx = np.argsort(points)
|
||
|
points = points[idx]
|
||
|
values = values[idx]
|
||
|
if method == 'nearest':
|
||
|
fill_value = 'extrapolate'
|
||
|
ip = interp1d(points, values, kind=method, axis=0, bounds_error=False,
|
||
|
fill_value=fill_value)
|
||
|
return ip(xi)
|
||
|
elif method == 'nearest':
|
||
|
ip = NearestNDInterpolator(points, values, rescale=rescale)
|
||
|
return ip(xi)
|
||
|
elif method == 'linear':
|
||
|
ip = LinearNDInterpolator(points, values, fill_value=fill_value,
|
||
|
rescale=rescale)
|
||
|
return ip(xi)
|
||
|
elif method == 'cubic' and ndim == 2:
|
||
|
ip = CloughTocher2DInterpolator(points, values, fill_value=fill_value,
|
||
|
rescale=rescale)
|
||
|
return ip(xi)
|
||
|
else:
|
||
|
raise ValueError("Unknown interpolation method %r for "
|
||
|
"%d dimensional data" % (method, ndim))
|