_ndgriddata.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. """
  2. Convenience interface to N-D interpolation
  3. .. versionadded:: 0.9
  4. """
  5. import numpy as np
  6. from .interpnd import LinearNDInterpolator, NDInterpolatorBase, \
  7. CloughTocher2DInterpolator, _ndim_coords_from_arrays
  8. from scipy.spatial import cKDTree
  9. __all__ = ['griddata', 'NearestNDInterpolator', 'LinearNDInterpolator',
  10. 'CloughTocher2DInterpolator']
  11. #------------------------------------------------------------------------------
  12. # Nearest-neighbor interpolation
  13. #------------------------------------------------------------------------------
  14. class NearestNDInterpolator(NDInterpolatorBase):
  15. """NearestNDInterpolator(x, y).
  16. Nearest-neighbor interpolation in N > 1 dimensions.
  17. .. versionadded:: 0.9
  18. Methods
  19. -------
  20. __call__
  21. Parameters
  22. ----------
  23. x : (Npoints, Ndims) ndarray of floats
  24. Data point coordinates.
  25. y : (Npoints,) ndarray of float or complex
  26. Data values.
  27. rescale : boolean, optional
  28. Rescale points to unit cube before performing interpolation.
  29. This is useful if some of the input dimensions have
  30. incommensurable units and differ by many orders of magnitude.
  31. .. versionadded:: 0.14.0
  32. tree_options : dict, optional
  33. Options passed to the underlying ``cKDTree``.
  34. .. versionadded:: 0.17.0
  35. Notes
  36. -----
  37. Uses ``scipy.spatial.cKDTree``
  38. Examples
  39. --------
  40. We can interpolate values on a 2D plane:
  41. >>> from scipy.interpolate import NearestNDInterpolator
  42. >>> import numpy as np
  43. >>> import matplotlib.pyplot as plt
  44. >>> rng = np.random.default_rng()
  45. >>> x = rng.random(10) - 0.5
  46. >>> y = rng.random(10) - 0.5
  47. >>> z = np.hypot(x, y)
  48. >>> X = np.linspace(min(x), max(x))
  49. >>> Y = np.linspace(min(y), max(y))
  50. >>> X, Y = np.meshgrid(X, Y) # 2D grid for interpolation
  51. >>> interp = NearestNDInterpolator(list(zip(x, y)), z)
  52. >>> Z = interp(X, Y)
  53. >>> plt.pcolormesh(X, Y, Z, shading='auto')
  54. >>> plt.plot(x, y, "ok", label="input point")
  55. >>> plt.legend()
  56. >>> plt.colorbar()
  57. >>> plt.axis("equal")
  58. >>> plt.show()
  59. See also
  60. --------
  61. griddata :
  62. Interpolate unstructured D-D data.
  63. LinearNDInterpolator :
  64. Piecewise linear interpolant in N dimensions.
  65. CloughTocher2DInterpolator :
  66. Piecewise cubic, C1 smooth, curvature-minimizing interpolant in 2D.
  67. """
  68. def __init__(self, x, y, rescale=False, tree_options=None):
  69. NDInterpolatorBase.__init__(self, x, y, rescale=rescale,
  70. need_contiguous=False,
  71. need_values=False)
  72. if tree_options is None:
  73. tree_options = dict()
  74. self.tree = cKDTree(self.points, **tree_options)
  75. self.values = np.asarray(y)
  76. def __call__(self, *args):
  77. """
  78. Evaluate interpolator at given points.
  79. Parameters
  80. ----------
  81. x1, x2, ... xn : array-like of float
  82. Points where to interpolate data at.
  83. x1, x2, ... xn can be array-like of float with broadcastable shape.
  84. or x1 can be array-like of float with shape ``(..., ndim)``
  85. """
  86. xi = _ndim_coords_from_arrays(args, ndim=self.points.shape[1])
  87. xi = self._check_call_shape(xi)
  88. xi = self._scale_x(xi)
  89. dist, i = self.tree.query(xi)
  90. return self.values[i]
  91. #------------------------------------------------------------------------------
  92. # Convenience interface function
  93. #------------------------------------------------------------------------------
  94. def griddata(points, values, xi, method='linear', fill_value=np.nan,
  95. rescale=False):
  96. """
  97. Interpolate unstructured D-D data.
  98. Parameters
  99. ----------
  100. points : 2-D ndarray of floats with shape (n, D), or length D tuple of 1-D ndarrays with shape (n,).
  101. Data point coordinates.
  102. values : ndarray of float or complex, shape (n,)
  103. Data values.
  104. xi : 2-D ndarray of floats with shape (m, D), or length D tuple of ndarrays broadcastable to the same shape.
  105. Points at which to interpolate data.
  106. method : {'linear', 'nearest', 'cubic'}, optional
  107. Method of interpolation. One of
  108. ``nearest``
  109. return the value at the data point closest to
  110. the point of interpolation. See `NearestNDInterpolator` for
  111. more details.
  112. ``linear``
  113. tessellate the input point set to N-D
  114. simplices, and interpolate linearly on each simplex. See
  115. `LinearNDInterpolator` for more details.
  116. ``cubic`` (1-D)
  117. return the value determined from a cubic
  118. spline.
  119. ``cubic`` (2-D)
  120. return the value determined from a
  121. piecewise cubic, continuously differentiable (C1), and
  122. approximately curvature-minimizing polynomial surface. See
  123. `CloughTocher2DInterpolator` for more details.
  124. fill_value : float, optional
  125. Value used to fill in for requested points outside of the
  126. convex hull of the input points. If not provided, then the
  127. default is ``nan``. This option has no effect for the
  128. 'nearest' method.
  129. rescale : bool, optional
  130. Rescale points to unit cube before performing interpolation.
  131. This is useful if some of the input dimensions have
  132. incommensurable units and differ by many orders of magnitude.
  133. .. versionadded:: 0.14.0
  134. Returns
  135. -------
  136. ndarray
  137. Array of interpolated values.
  138. Notes
  139. -----
  140. .. versionadded:: 0.9
  141. For data on a regular grid use `interpn` instead.
  142. Examples
  143. --------
  144. Suppose we want to interpolate the 2-D function
  145. >>> import numpy as np
  146. >>> def func(x, y):
  147. ... return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2
  148. on a grid in [0, 1]x[0, 1]
  149. >>> grid_x, grid_y = np.mgrid[0:1:100j, 0:1:200j]
  150. but we only know its values at 1000 data points:
  151. >>> rng = np.random.default_rng()
  152. >>> points = rng.random((1000, 2))
  153. >>> values = func(points[:,0], points[:,1])
  154. This can be done with `griddata` -- below we try out all of the
  155. interpolation methods:
  156. >>> from scipy.interpolate import griddata
  157. >>> grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')
  158. >>> grid_z1 = griddata(points, values, (grid_x, grid_y), method='linear')
  159. >>> grid_z2 = griddata(points, values, (grid_x, grid_y), method='cubic')
  160. One can see that the exact result is reproduced by all of the
  161. methods to some degree, but for this smooth function the piecewise
  162. cubic interpolant gives the best results:
  163. >>> import matplotlib.pyplot as plt
  164. >>> plt.subplot(221)
  165. >>> plt.imshow(func(grid_x, grid_y).T, extent=(0,1,0,1), origin='lower')
  166. >>> plt.plot(points[:,0], points[:,1], 'k.', ms=1)
  167. >>> plt.title('Original')
  168. >>> plt.subplot(222)
  169. >>> plt.imshow(grid_z0.T, extent=(0,1,0,1), origin='lower')
  170. >>> plt.title('Nearest')
  171. >>> plt.subplot(223)
  172. >>> plt.imshow(grid_z1.T, extent=(0,1,0,1), origin='lower')
  173. >>> plt.title('Linear')
  174. >>> plt.subplot(224)
  175. >>> plt.imshow(grid_z2.T, extent=(0,1,0,1), origin='lower')
  176. >>> plt.title('Cubic')
  177. >>> plt.gcf().set_size_inches(6, 6)
  178. >>> plt.show()
  179. See Also
  180. --------
  181. LinearNDInterpolator :
  182. Piecewise linear interpolant in N dimensions.
  183. NearestNDInterpolator :
  184. Nearest-neighbor interpolation in N dimensions.
  185. CloughTocher2DInterpolator :
  186. Piecewise cubic, C1 smooth, curvature-minimizing interpolant in 2D.
  187. """
  188. points = _ndim_coords_from_arrays(points)
  189. if points.ndim < 2:
  190. ndim = points.ndim
  191. else:
  192. ndim = points.shape[-1]
  193. if ndim == 1 and method in ('nearest', 'linear', 'cubic'):
  194. from ._interpolate import interp1d
  195. points = points.ravel()
  196. if isinstance(xi, tuple):
  197. if len(xi) != 1:
  198. raise ValueError("invalid number of dimensions in xi")
  199. xi, = xi
  200. # Sort points/values together, necessary as input for interp1d
  201. idx = np.argsort(points)
  202. points = points[idx]
  203. values = values[idx]
  204. if method == 'nearest':
  205. fill_value = 'extrapolate'
  206. ip = interp1d(points, values, kind=method, axis=0, bounds_error=False,
  207. fill_value=fill_value)
  208. return ip(xi)
  209. elif method == 'nearest':
  210. ip = NearestNDInterpolator(points, values, rescale=rescale)
  211. return ip(xi)
  212. elif method == 'linear':
  213. ip = LinearNDInterpolator(points, values, fill_value=fill_value,
  214. rescale=rescale)
  215. return ip(xi)
  216. elif method == 'cubic' and ndim == 2:
  217. ip = CloughTocher2DInterpolator(points, values, fill_value=fill_value,
  218. rescale=rescale)
  219. return ip(xi)
  220. else:
  221. raise ValueError("Unknown interpolation method %r for "
  222. "%d dimensional data" % (method, ndim))