Completed
Pull Request — master (#355)
by
unknown
02:17 queued 01:01
created

interpolate_nans()   B

Complexity

Conditions 3

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
dl 0
loc 30
rs 8.8571
1
# Copyright (c) 2008-2015 MetPy Developers.
2
# Distributed under the terms of the BSD 3-Clause License.
3
# SPDX-License-Identifier: BSD-3-Clause
4
"""Contains a collection of generally useful calculation tools."""
5
6
import numpy as np
7
8
from ..package_tools import Exporter
9
10
exporter = Exporter(globals())
11
12
13
@exporter.export
14
def resample_nn_1d(a, centers):
15
    """Return one-dimensional nearest-neighbor indexes based on user-specified centers.
16
17
    Parameters
18
    ----------
19
    a : array-like
20
        1-dimensional array of numeric values from which to
21
        extract indexes of nearest-neighbors
22
    centers : array-like
23
        1-dimensional array of numeric values representing a subset of values to approximate
24
25
    Returns
26
    -------
27
        An array of indexes representing values closest to given array values
28
    """
29
    ix = []
30
    for center in centers:
31
        index = (np.abs(a - center)).argmin()
32
        if index not in ix:
33
            ix.append(index)
34
    return ix
35
36
37
@exporter.export
38
def nearest_intersection_idx(a, b):
39
    """Determine the index of the point just before two lines with common x values.
40
41
    Parameters
42
    ----------
43
    a : array-like
44
        1-dimensional array of y-values for line 1
45
    b : array-like
46
        1-dimensional array of y-values for line 2
47
48
    Returns
49
    -------
50
        An array of indexes representing the index of the values
51
        just before the intersection(s) of the two lines.
52
    """
53
    # Difference in the two y-value sets
54
    difference = a - b
55
56
    # Determine the point just before the intersection of the lines
57
    # Will return multiple points for multiple intersections
58
    sign_change_idx, = np.nonzero(np.diff(np.sign(difference)))
59
60
    return sign_change_idx
61
62
63
@exporter.export
64
def find_intersections(x, a, b):
65
    """Calculate the best estimate of intersection.
66
67
    Calculates the best estimates of the intersection of two y-value
68
    data sets that share a common x-value set.
69
70
    Parameters
71
    ----------
72
    x : array-like
73
        1-dimensional array of numeric x-values
74
    a : array-like
75
        1-dimensional array of y-values for line 1
76
    b : array-like
77
        1-dimensional array of y-values for line 2
78
79
    Returns
80
    -------
81
        A tuple (x, y) of array-like with the x and y coordinates of the
82
        intersections of the lines.
83
    """
84
    # Find the index of the points just before the intersection(s)
85
    nearest_idx = nearest_intersection_idx(a, b)
86
    next_idx = nearest_idx + 1
87
88
    # x-values around each intersection
89
    x0 = x[nearest_idx]
90
    x1 = x[next_idx]
91
92
    # y-values around each intersection for the first line
93
    a0 = a[nearest_idx]
94
    a1 = a[next_idx]
95
96
    # y-values around each intersection for the second line
97
    b0 = b[nearest_idx]
98
    b1 = b[next_idx]
99
100
    # Calculate the x-intersection. This comes from finding the equations of the two lines,
101
    # one through (x0, a0) and (x1, a1) and the other through (x0, b0) and (x1, b1),
102
    # finding their intersection, and reducing with a bunch of algebra.
103
    delta_y0 = a0 - b0
104
    delta_y1 = a1 - b1
105
    intersect_x = (delta_y1 * x0 - delta_y0 * x1) / (delta_y1 - delta_y0)
106
107
    # Calculate the y-intersection of the lines. Just plug the x above into the equation
108
    # for the line through the a points. One could solve for y like x above, but this
109
    # causes weirder unit behavior and seems a little less good numerically.
110
    intersect_y = ((intersect_x - x0) / (x1 - x0)) * (a1 - a0) + a0
111
112
    return intersect_x, intersect_y
113
114
115
@exporter.export
116
def interpolate_nans(x, y, kind='linear'):
117
    """Interpolate NaN values in y.
118
119
    Interpolate NaN values in the y dimension. Works with unsorted x values.
120
121
    Parameters
122
    ----------
123
    x : array-like
124
        1-dimensional array of numeric x-values
125
    y : array-like
126
        1-dimensional array of numeric y-values
127
    kind : string
128
        specifies the kind of interpolation x coordinate - 'linear' or 'log'
129
130
    Returns
131
    -------
132
        An array of the y coordinate data with NaN values interpolated.
133
    """
134
    x_sort_args = np.argsort(x)
135
    x = x[x_sort_args]
136
    y = y[x_sort_args]
137
    nans = np.isnan(y)
138
    if kind is 'linear':
139
        y[nans] = np.interp(x[nans], x[~nans], y[~nans])
140
    elif kind is 'log':
141
        y[nans] = np.interp(np.log(x[nans]), np.log(x[~nans]), y[~nans])
142
    else:
143
        raise ValueError('Unknown option for kind: {0}'.format(str(kind)))
144
    return y[x_sort_args]
145