File: ND_regular_grid.rst

package info (click to toggle)
scipy 1.17.0-1exp2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 235,340 kB
  • sloc: cpp: 506,914; python: 357,038; ansic: 215,028; javascript: 89,566; fortran: 19,308; cs: 3,081; f90: 1,150; sh: 860; makefile: 519; pascal: 284; lisp: 134; xml: 56; perl: 51
file content (225 lines) | stat: -rw-r--r-- 9,012 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
.. _tutorial-interpolate_regular_grid_interpolator:

.. currentmodule:: scipy.interpolate

=====================================================================================
Multivariate data interpolation on a regular grid  (:class:`RegularGridInterpolator`)
=====================================================================================

Suppose you have N-dimensional data on a regular grid, and you
want to interpolate it. In such a case, :class:`RegularGridInterpolator` can be
useful. Several interpolation strategies are supported: nearest-neighbor,
linear, and tensor product splines of odd degree.

Strictly speaking, this class efficiently handles data given on *rectilinear*
grids: hypercubic lattices with possibly unequal spacing between points.
The number of points per dimension can be different for different dimensions.

The following example demonstrates its use, and compares the interpolation results
using each method.

.. plot::

   >>> import numpy as np
   >>> import matplotlib.pyplot as plt
   >>> from scipy.interpolate import RegularGridInterpolator

   Suppose we want to interpolate this 2-D function.

   >>> def F(u, v):
   ...     return u * np.cos(u * v) + v * np.sin(u * v)

   Suppose we only know some data on a regular grid.

   >>> fit_points = [np.linspace(0, 3, 8), np.linspace(0, 3, 11)]
   >>> values = F(*np.meshgrid(*fit_points, indexing='ij'))

   Creating test points and true values for evaluations.

   >>> ut, vt = np.meshgrid(np.linspace(0, 3, 80), np.linspace(0, 3, 80), indexing='ij')
   >>> true_values = F(ut, vt)
   >>> test_points = np.array([ut.ravel(), vt.ravel()]).T

   We can create the interpolator and interpolate test points using each method.

   >>> interp = RegularGridInterpolator(fit_points, values)
   >>> fig, axes = plt.subplots(2, 3, figsize=(10, 6))
   >>> axes = axes.ravel()
   >>> fig_index = 0
   >>> for method in ['linear', 'nearest', 'slinear', 'cubic', 'quintic']:
   ...     im = interp(test_points, method=method).reshape(80, 80)
   ...     axes[fig_index].imshow(im)
   ...     axes[fig_index].set_title(method)
   ...     axes[fig_index].axis("off")
   ...     fig_index += 1
   >>> axes[fig_index].imshow(true_values)
   >>> axes[fig_index].set_title("True values")
   >>> fig.tight_layout()
   >>> fig.show()

   As expected, the higher degree spline interpolations are closest to the
   true values, though are more expensive to compute than with `linear`
   or `nearest`. The `slinear` interpolation also matches the `linear`
   interpolation.

If your data is such that spline methods produce ringing, you may consider
using ``method="pchip"``, which uses the tensor product of PCHIP interpolators,
a `PchipInterpolator` per dimension.

If you prefer a functional interface opposed to explicitly creating a class instance,
the `interpn` convenience function offers the equivalent functionality.

Specifically, these two forms give identical results:

    >>> from scipy.interpolate import interpn
    >>> rgi = RegularGridInterpolator(fit_points, values)
    >>> result_rgi = rgi(test_points)

and

    >>> result_interpn = interpn(fit_points, values, test_points)
    >>> np.allclose(result_rgi, result_interpn, atol=1e-15)
    True


For data confined to an (N-1)-dimensional subspace of N-dimensional space, i.e.
when one of the grid axes has length 1, the extrapolation along this axis is
controlled by the ``fill_value`` keyword parameter:

    >>> x = np.array([0, 5, 10])
    >>> y = np.array([0])
    >>> data = np.array([[0], [5], [10]])
    >>> rgi = RegularGridInterpolator((x, y), data,
    ...                               bounds_error=False, fill_value=None)
    >>> rgi([(2, 0), (2, 1), (2, -1)])   # extrapolates the value on the axis
    array([2., 2., 2.])
    >>> rgi.fill_value = -101
    >>> rgi([(2, 0), (2, 1), (2, -1)])
    array([2., -101., -101.])

.. note::

    If the input data is such that input dimensions have incommensurate
    units and differ by many orders of magnitude, the interpolant may have
    numerical artifacts. Consider rescaling the data before interpolating.



.. _tutorial-interpolate_RGI_batching:


Batch dimensions of ``values``
==============================

Suppose you have a vector function :math:`f(x) = y`, where :math:`x` and :math:`y` are
vectors, potentially of different lengths, and you want to sample the function on a grid
of :math:`x` values. One way to address this is to use the fact that `RegularGridInterpolator`
allows ``values`` with *trailing* dimensions.

In accordance with how :ref:`1D interpolators
interpret multidimensional arrays <tutorial-interpolate_batching>`, the interpretation is
that the first :math:`N` dimensions of the ``values`` arrays are data dimensions
(i.e. they correspond to the points defined by the ``grid`` argument), and the *trailing*
dimensions are batch axes. Note that this disagrees with a usual NumPy broadcasting
conventions, where broadcasting proceeds along the *leading* dimensions.

To illustrate:

    >>> n = 5   # the number of batch components

    >>> # make a 3D grid
    >>> x1 = np.linspace(-np.pi, np.pi, 10)
    >>> x2 = np.linspace(0.0, np.pi, 15)
    >>> x3 = np.linspace(0.0, np.pi/2, 20)
    >>> points = (x1, x2, x3)
    >>>
    >>> # define a function and sample it on the grid
    >>> def f(x1, x2, x3, n):
    ...     lst = [np.sin(np.pi*x1/2) * np.exp(x2/2) + x3 + i for i in range(n)]
    ...     return np.asarray(lst)
    >>>
    >>> X1, X2, X3 = np.meshgrid(x1, x2, x3, indexing="ij")
    >>> values = f(X1, X2, X3, n)
    >>> values.shape
    (5, 10, 15, 20)
    >>> 
    >>> # prepare the data and construct the interpolator
    >>> values = np.moveaxis(values, 0, -1)
    >>> values.shape
    (10, 15, 20, 5)     # the batch dimension is 5
    >>> rgi = RegularGridInterpolator(points, values)
    >>>
    >>> # Coordinates to compute the interpolation at
    >>> x = np.asarray([0.2, np.pi/2.1, np.pi/4.1])
    >>>
    # evaluate
    >>> rgi(x).shape
    (1, 5)

In this example, we evaluated a batch of :math:`n=5` functions on a
three-dimensional grid. In general, multiple batching dimensions are allowed, and the
shape of the result follows by appending the batching shape (in this example, ``(5,)``)
to the shape of the input ``x`` (in this example, `(1,)``).


.. _tutorial-interpolate_cartesian-grids:

Uniformly spaced data
=====================

If you are dealing with data on Cartesian grids with integer coordinates, e.g.
resampling image data, these routines may not be the optimal choice. Consider
using `scipy.ndimage.map_coordinates` instead.

For floating-point data on grids with equal spacing, ``map_coordinates`` can
be easily wrapped into a `RegularGridInterpolator` look-alike. The following is
a bare-bones example originating from `the Johanness Buchner's
'regulargrid' package <https://github.com/JohannesBuchner/regulargrid/>`_::

    class CartesianGridInterpolator:
        def __init__(self, points, values, method='linear'):
            self.limits = np.array([[min(x), max(x)] for x in points])
            self.values = np.asarray(values, dtype=float)
            self.order = {'linear': 1, 'cubic': 3, 'quintic': 5}[method]

        def __call__(self, xi):
            """
            `xi` here is an array-like (an array or a list) of points.

            Each "point" is an ndim-dimensional array_like, representing
            the coordinates of a point in ndim-dimensional space.
            """
            # transpose the xi array into the ``map_coordinates`` convention
            # which takes coordinates of a point along columns of a 2D array.
            xi = np.asarray(xi).T

            # convert from data coordinates to pixel coordinates
            ns = self.values.shape
            coords = [(n-1)*(val - lo) / (hi - lo)
                      for val, n, (lo, hi) in zip(xi, ns, self.limits)]

            # interpolate
            return map_coordinates(self.values, coords, 
                                   order=self.order,
                                   cval=np.nan)  # fill_value

This wrapper can be used as a(n almost) drop-in replacement for the
`RegularGridInterpolator`:

    >>> x, y = np.arange(5), np.arange(6)
    >>> xx, yy = np.meshgrid(x, y, indexing='ij')
    >>> values = xx**3 + yy**3
    >>> rgi = RegularGridInterpolator((x, y), values, method='linear')
    >>> rgi([[1.5, 1.5], [3.5, 2.6]])
    array([ 9. , 64.9])
    >>> cgi = CartesianGridInterpolator((x, y), values, method='linear')
    >>> cgi([[1.5, 1.5], [3.5, 2.6]])
    array([ 9. , 64.9])

Note that the example above uses the ``map_coordinates`` boundary conditions.
Thus, results of the ``cubic`` and ``quintic`` interpolations may differ from
those of the ``RegularGridInterpolator``. 
Refer to `scipy.ndimage.map_coordinates` documentation for more details on
boundary conditions and other additional arguments.
Finally, we note that this simplified example assumes that the input data is
given in the ascending order.