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
|
"""
A collection of intperolation tools for timeseries
:author: Pierre GF Gerard-Marchant & Matt Knox
:contact: pierregm_at_uga_dot_edu - mattknox_ca_at_hotmail_dot_com
:version: $Id: interpolate.py 2807 2007-03-02 08:48:04Z pierregm $
"""
__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author: pierregm $)"
__version__ = '1.0'
__revision__ = "$Revision: 2807 $"
__date__ = '$Date: 2007-03-02 00:48:04 -0800 (Fri, 02 Mar 2007) $'
import numpy.core.numeric as numeric
from scipy.interpolate import fitpack
import maskedarray as MA
from maskedarray.core import masked, nomask, getmask
from maskedarray.extras import flatnotmasked_edges
marray = MA.array
__all__ = [
'forward_fill', 'backward_fill', 'interp_masked1d',
]
#####---------------------------------------------------------------------------
#---- --- Functions for filling in masked values in a masked array ---
#####---------------------------------------------------------------------------
def forward_fill(marr, maxgap=None):
"""forward_fill(marr, maxgap=None)
Forward fills masked values in a 1-d array when there are less maxgap
consecutive masked values. If maxgap is None, then forward fill all
masked values."""
# Initialization ..................
if numeric.ndim(marr) > 1:
raise ValueError,"The input array should be 1D only!"
marr = marray(marr, copy=True)
if getmask(marr) is nomask or marr.size == 0:
return marr
#
currGap = 0
if maxgap is not None:
for i in range(1, marr.size):
if marr._mask[i]:
currGap += 1
if currGap <= maxgap and not marr._mask[i-1]:
marr._data[i] = marr._data[i-1]
marr._mask[i] = False
elif currGap == maxgap + 1:
marr._mask[i-maxgap:i] = True
else:
currGap = 0
else:
for i in range(1, marr.size):
# CHECK: We should probable be able to speed things up here
if marr._mask[i] and not marr._mask[i-1]:
marr._data[i] = marr._data[i-1]
marr._mask[i] = False
return marr
#..........................................................
def backward_fill(marr, maxgap=None):
"""backward_fill(marr, maxgap=None)
Backward fills masked values in a 1-d array when there are less than maxgap
consecutive masked values. If maxgap is None, then backward fills all
masked values.
"""
return forward_fill(marr[::-1], maxgap=maxgap)[::-1]
#..........................................................
def interp_masked1d(marr, kind='linear'):
"""interp_masked1d(marr, king='linear')
Interpolates masked values in marr according to method kind.
kind must be one of 'constant', 'linear', 'cubic', quintic'
"""
if numeric.ndim(marr) > 1:
raise ValueError("array must be 1 dimensional!")
#
marr = marray(marr, copy=True)
if getmask(marr) is nomask:
return marr
#
unmaskedIndices = (~marr._mask).nonzero()[0]
if unmaskedIndices.size < 2:
return marr
#
kind = kind.lower()
if kind == 'constant':
return forward_fill(marr)
try:
k = {'linear' : 1,
'cubic' : 3,
'quintic' : 5}[kind.lower()]
except KeyError:
raise ValueError("Unsupported interpolation type.")
first_unmasked, last_unmasked = flatnotmasked_edges(marr)
vals = marr.data[unmaskedIndices]
tck = fitpack.splrep(unmaskedIndices, vals, k=k)
maskedIndices = marr._mask.nonzero()[0]
interpIndices = maskedIndices[(maskedIndices > first_unmasked) & \
(maskedIndices < last_unmasked)]
marr[interpIndices] = fitpack.splev(interpIndices, tck).astype(marr.dtype)
return marr
|