|
| 1 | +import collections |
| 2 | +import itertools |
| 3 | + |
| 4 | +import numpy as np |
| 5 | + |
| 6 | +from .dataarray import DataArray |
| 7 | + |
| 8 | + |
| 9 | +def map_coordinates(source, target, keep_attrs=False, **kwargs): |
| 10 | + """ |
| 11 | + Uses ``scipy.ndimage.interpolation.map_coordinates`` to map the |
| 12 | + source data array to the given target coordinates using spline |
| 13 | + interpolation. Target must consist of numerical coordinates only. |
| 14 | +
|
| 15 | + Parameters |
| 16 | + ------------ |
| 17 | + source : DataArray |
| 18 | + Gridded source data. |
| 19 | + target : dict |
| 20 | + Target coordinates; mapping from dimension names to coordinate |
| 21 | + values to sample at. |
| 22 | + keep_attrs : boolean, optional |
| 23 | + If True, attributes are copied from source (default is False). |
| 24 | + **kwargs |
| 25 | + Additional keyword args are passed to |
| 26 | + ``scipy.ndimage.interpolation.map_coordinates``. |
| 27 | +
|
| 28 | + Returns |
| 29 | + --------- |
| 30 | + interpolated : DataArray |
| 31 | + Data array with interpolated values. Coordinates and dimensions |
| 32 | + are copied from source. |
| 33 | +
|
| 34 | + """ |
| 35 | + from scipy.interpolate import interp1d |
| 36 | + from scipy import ndimage |
| 37 | + |
| 38 | + # Set up the interpolators to map coordinates onto array indices |
| 39 | + interpolators = {} |
| 40 | + for dim_name in target.keys(): |
| 41 | + dim = source.coords[dim_name] |
| 42 | + if not np.issubdtype(dim.dtype, np.number): |
| 43 | + raise ValueError('Only numerical dimensions ' |
| 44 | + 'can be interpolated on.') |
| 45 | + try: |
| 46 | + interpolators[dim_name] = interp1d(dim, list(range(len(dim)))) |
| 47 | + except ValueError: # Raised if there is only one entry |
| 48 | + # 0 is the only index that exists |
| 49 | + interpolators[dim_name] = lambda x: 0 |
| 50 | + |
| 51 | + # Set up the array indices on which to interpolate, |
| 52 | + # and the final coordinates to apply to the result |
| 53 | + indices = collections.OrderedDict() |
| 54 | + coords = collections.OrderedDict() |
| 55 | + for d in source.dims: |
| 56 | + if d not in target.keys(): |
| 57 | + # Choose all entries from non-interpolated dimensions |
| 58 | + indices[d] = list(range(len(source.coords[d]))) |
| 59 | + coords[d] = source.coords[d] |
| 60 | + else: |
| 61 | + # Choose selected entries from interpolated dimensions |
| 62 | + indices[d] = [interpolators[d](i) for i in target[d]] |
| 63 | + coords[d] = target[d] |
| 64 | + |
| 65 | + # Generate array of all coordinates |
| 66 | + # Shape should be n(dims) * n(product of all interpolators) |
| 67 | + coordinates = np.array(list(zip( |
| 68 | + *itertools.product(*[i for i in indices.values()])) |
| 69 | + )) |
| 70 | + |
| 71 | + interp_array = ndimage.map_coordinates(source.values, coordinates, |
| 72 | + **kwargs) |
| 73 | + |
| 74 | + # Reshape the resulting array according to the target coordinates |
| 75 | + result_shape = [len(i) for i in indices.values()] |
| 76 | + attrs = source.attrs if keep_attrs else None # Copy attrs if asked for |
| 77 | + return DataArray(interp_array.reshape(result_shape), |
| 78 | + coords=coords, attrs=attrs) |
0 commit comments