interpolate()   C
last analyzed

Complexity

Conditions 7

Size

Total Lines 94

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
dl 0
loc 94
rs 5.325
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
# Copyright (c) 2016 MetPy Developers.
2
# Distributed under the terms of the BSD 3-Clause License.
3
# SPDX-License-Identifier: BSD-3-Clause
4
"""Tools and calculations for assigning values to a grid."""
5
6
from __future__ import division
7
8
import numpy as np
9
from scipy.interpolate import griddata, Rbf
10
from scipy.spatial.distance import cdist
11
12
from . import interpolation, points
13
from ..package_tools import Exporter
14
15
exporter = Exporter(globals())
16
17
18
def calc_kappa(spacing, kappa_star=5.052):
19
    r"""Calculate the kappa parameter for barnes interpolation.
20
21
    Parameters
22
    ----------
23
    spacing: float
24
        Average spacing between observations
25
    kappa_star: float
26
        Non-dimensional response parameter. Default 5.052.
27
28
    Returns
29
    -------
30
        kappa: float
31
32
    """
33
    return kappa_star * (2.0 * spacing / np.pi)**2
34
35
36
def remove_observations_below_value(x, y, z, val=0):
37
    r"""Remove all x, y, and z where z is less than val.
38
39
    Will not destroy original values.
40
41
    Parameters
42
    ----------
43
    x: array_like
44
        x coordinate.
45
    y: array_like
46
        y coordinate.
47
    z: array_like
48
        Observation value.
49
    val: float
50
        Value at which to threshold z.
51
52
    Returns
53
    -------
54
    x, y, z
55
        List of coordinate observation pairs without
56
        observation values less than val.
57
58
    """
59
    x_ = x[z >= val]
60
    y_ = y[z >= val]
61
    z_ = z[z >= val]
62
63
    return x_, y_, z_
64
65
66
def remove_nan_observations(x, y, z):
67
    r"""Remove all x, y, and z where z is nan.
68
69
    Will not destroy original values.
70
71
    Parameters
72
    ----------
73
    x: array_like
74
        x coordinate
75
    y: array_like
76
        y coordinate
77
    z: array_like
78
        observation value
79
80
    Returns
81
    -------
82
    x, y, z
83
        List of coordinate observation pairs without
84
        nan valued observations.
85
86
    """
87
    x_ = x[~np.isnan(z)]
88
    y_ = y[~np.isnan(z)]
89
    z_ = z[~np.isnan(z)]
90
91
    return x_, y_, z_
92
93
94
def remove_repeat_coordinates(x, y, z):
95
    r"""Remove all x, y, and z where (x,y) is repeated and keep the first occurrence only.
96
97
    Will not destroy original values.
98
99
    Parameters
100
    ----------
101
    x: array_like
102
        x coordinate
103
    y: array_like
104
        y coordinate
105
    z: array_like
106
        observation value
107
108
    Returns
109
    -------
110
    x, y, z
111
        List of coordinate observation pairs without
112
        repeated coordinates.
113
114
    """
115
    coords = []
116
    variable = []
117
118
    for (x_, y_, t_) in zip(x, y, z):
119
        if (x_, y_) not in coords:
120
            coords.append((x_, y_))
121
            variable.append(t_)
122
123
    coords = np.array(coords)
124
125
    x_ = coords[:, 0]
126
    y_ = coords[:, 1]
127
128
    z_ = np.array(variable)
129
130
    return x_, y_, z_
131
132
133
@exporter.export
134
def interpolate(x, y, z, interp_type='linear', hres=50000,
135
                minimum_neighbors=3, gamma=0.25, kappa_star=5.052,
136
                search_radius=None, rbf_func='linear', rbf_smooth=0):
137
    r"""Interpolate given (x,y), observation (z) pairs to a grid based on given parameters.
138
139
    Parameters
140
    ----------
141
    x: array_like
142
        x coordinate
143
    y: array_like
144
        y coordinate
145
    z: array_like
146
        observation value
147
    interp_type: str
148
        What type of interpolation to use. Available options include:
149
        1) "linear", "nearest", "cubic", or "rbf" from Scipy.interpolate.
150
        2) "natural_neighbor", "barnes", or "cressman" from Metpy.mapping .
151
        Default "linear".
152
    hres: float
153
        The horizontal resolution of the generated grid. Default 50000 meters.
154
    minimum_neighbors: int
155
        Minimum number of neighbors needed to perform barnes or cressman interpolation for a
156
        point. Default is 3.
157
    gamma: float
158
        Adjustable smoothing parameter for the barnes interpolation. Default 0.25.
159
    kappa_star: float
160
        Response parameter for barnes interpolation, specified nondimensionally
161
        in terms of the Nyquist. Default 5.052
162
    search_radius: float
163
        A search radius to use for the barnes and cressman interpolation schemes.
164
        If search_radius is not specified, it will default to the average spacing of
165
        observations.
166
    rbf_func: str
167
        Specifies which function to use for Rbf interpolation.
168
        Options include: 'multiquadric', 'inverse', 'gaussian', 'linear', 'cubic',
169
        'quintic', and 'thin_plate'. Defualt 'linear'. See scipy.interpolate.Rbf for more
170
        information.
171
    rbf_smooth: float
172
        Smoothing value applied to rbf interpolation.  Higher values result in more smoothing.
173
174
    Returns
175
    -------
176
    grid_x: (N, 2) ndarray
177
        Meshgrid for the resulting interpolation in the x dimension
178
    grid_y: (N, 2) ndarray
179
        Meshgrid for the resulting interpolation in the y dimension ndarray
180
    img: (M, N) ndarray
181
        2-dimensional array representing the interpolated values for each grid.
182
183
    """
184
    grid_x, grid_y = points.generate_grid(hres, points.get_boundary_coords(x, y))
185
186
    if interp_type in ['linear', 'nearest', 'cubic']:
187
        points_zip = np.array(list(zip(x, y)))
188
        img = griddata(points_zip, z, (grid_x, grid_y), method=interp_type)
189
190
    elif interp_type == 'natural_neighbor':
191
        img = interpolation.natural_neighbor(x, y, z, grid_x, grid_y)
192
193
    elif interp_type in ['cressman', 'barnes']:
194
        ave_spacing = np.mean((cdist(list(zip(x, y)), list(zip(x, y)))))
195
196
        if search_radius is None:
197
            search_radius = ave_spacing
198
199
        if interp_type == 'cressman':
200
            img = interpolation.inverse_distance(x, y, z, grid_x, grid_y, search_radius,
201
                                                 min_neighbors=minimum_neighbors,
202
                                                 kind=interp_type)
203
        else:
204
            kappa = calc_kappa(ave_spacing, kappa_star)
205
            img = interpolation.inverse_distance(x, y, z, grid_x, grid_y, search_radius,
206
                                                 gamma, kappa, min_neighbors=minimum_neighbors,
207
                                                 kind=interp_type)
208
209
    elif interp_type == 'rbf':
210
        # 3-dimensional support not yet included.
211
        # Assign a zero to each z dimension for observations.
212
        h = np.zeros((len(x)))
213
214
        rbfi = Rbf(x, y, h, z, function=rbf_func, smooth=rbf_smooth)
215
216
        # 3-dimensional support not yet included.
217
        # Assign a zero to each z dimension grid cell position.
218
        hi = np.zeros(grid_x.shape)
219
        img = rbfi(grid_x, grid_y, hi)
220
221
    else:
222
        raise ValueError('Interpolation option not available. '
223
                         'Try: linear, nearest, cubic, natural_neighbor, '
224
                         'barnes, cressman, rbf')
225
226
    return grid_x, grid_y, img
227