531 lines
20 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding=utf-8
#-----------------------------------------------------
# Author: Yaqiang Wang
# Date: 2017-3-9
# Purpose: MeteoInfoLab interpolate module
# Note: Jython
#-----------------------------------------------------
from org.meteoinfo.math.interpolate import InterpUtil, RectLinearInterpolator, RectNearestInterpolator, \
RectNearestInterpolator3D, RectLinearInterpolator3D
from org.meteoinfo.ndarray.math import ArrayUtil
from org.meteoinfo.geometry.geoprocess import GeometryUtil, GeoComputation
from ..core import NDArray
from ..core import numeric as np
__all__ = [
'interp1d','interp2d','linint2','nearestint2','RectBivariateSpline','RectInterpLinear',
'RectInterpLinear3D','RectInterpNearest','RectInterpNearest3D','griddata'
]
class interp1d(object):
'''
Interpolate a 1-D function.
:param x: (*array_like*) A 1-D array of real values.
:param y: (*array_like*) A 1-D array of real values. The length of y must be equal to the length of x.
:param kind: (*boolean*) Specifies the kind of interpolation as a string (linear,
cubic,akima,divided,loess,neville,'kriging'). Default is linear.
'''
def __init__(self, x, y, kind='linear', **kwargs):
if isinstance(x, list):
x = np.array(x)
if isinstance(y, list):
y = np.array(y)
if kind == 'kriging':
beta = kwargs.pop('beta', 1.5)
self._func = InterpUtil.getKriging1D(x.asarray(), y.asarray(), beta)
else:
self._func = InterpUtil.getInterpFunc(x.asarray(), y.asarray(), kind)
def __call__(self, x):
'''
Evaluate the interpolate values.
:param x: (*array_like*) Points to evaluate the interpolate at.
'''
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
r = InterpUtil.evaluate(self._func, x)
if isinstance(r, float):
return r
else:
return NDArray(r)
class interp2d(object):
'''
Interpolate over a 2-D grid.
x, y and z are arrays of values used to approximate some function f: z = f(x, y).
This class returns a function whose call method uses spline interpolation to find
the value of new points.
If x and y represent a regular grid, consider using RectBivariateSpline.
:param x: (*array_like*) 1-D arrays of x coordinate in strictly ascending order.
:param y: (*array_like*) 1-D arrays of y coordinate in strictly ascending order.
:param z: (*array_like*) 2-D array of data with shape (x.size,y.size).
:param kind: (*boolean*) Specifies the kind of interpolation as a string (linear,
nearest, 'kriging'). Default is linear.
'''
def __init__(self, x, y, z, kind='linear', **kwargs):
if isinstance(x, list):
x = np.array(x)
if isinstance(y, list):
y = np.array(y)
if isinstance(z, list):
z = np.array(z)
if kind == 'kriging':
if z.ndim == 2:
if x.ndim == 1:
x, y = np.meshgrid(x, y)
x = x.reshape(-1)
y = y.reshape(-1)
z = z.reshape(-1)
beta = kwargs.pop('beta', 1.5)
self._func = InterpUtil.getKriging2D(x.asarray(), y.asarray(), z.asarray(), beta)
else:
self._func = InterpUtil.getBiInterpFunc(x.asarray(), y.asarray(), z.T.asarray(), kind)
def __call__(self, x, y):
'''
Evaluate the interpolate values.
:param x: (*array_like*) X to evaluate the interpolate at.
:param y: (*array_like*) Y to evaluate the interpolate at.
'''
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
if isinstance(y, list):
y = np.array(y)
if isinstance(y, NDArray):
y = y.asarray()
r = InterpUtil.evaluate(self._func, x, y)
if isinstance(r, float):
return r
else:
return NDArray(r)
class RectBivariateSpline(object):
'''
Bivariate spline approximation over a rectangular mesh.
Can be used for both smoothing and interpolating data.
:param x: (*array_like*) 1-D arrays of x coordinate in strictly ascending order.
:param y: (*array_like*) 1-D arrays of y coordinate in strictly ascending order.
:param z: (*array_like*) 2-D array of data with shape (x.size,y.size).
'''
def __init__(self, x, y, z):
if isinstance(x, list):
x = np.array(x)
if isinstance(y, list):
y = np.array(y)
if isinstance(z, list):
z = np.array(z)
self._func = InterpUtil.getBiInterpFunc(x.asarray(), y.asarray(), z.asarray(), 'linear')
def __call__(self, x, y):
'''
Evaluate the interpolate values.
:param x: (*array_like*) X to evaluate the interpolate at.
:param y: (*array_like*) Y to evaluate the interpolate at.
'''
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
if isinstance(y, list):
y = np.array(y)
if isinstance(y, NDArray):
y = y.asarray()
r = InterpUtil.evaluate(self._func, x, y)
if isinstance(r, float):
return r
else:
return NDArray(r)
class RectInterpLinear(object):
'''
Bivariate linear interpolation over a rectangular mesh.
Can be used for both smoothing and interpolating data.
:param x: (*array_like*) 1-D arrays of x coordinate in strictly ascending order.
:param y: (*array_like*) 1-D arrays of y coordinate in strictly ascending order.
:param z: (*array_like*) 2-D array of data with shape (x.size,y.size).
'''
def __init__(self, x, y, z):
if isinstance(x, list):
x = np.array(x)
if isinstance(y, list):
y = np.array(y)
if isinstance(z, list):
z = np.array(z)
self._func = RectLinearInterpolator(x.asarray(), y.asarray(), z.asarray())
def __call__(self, x, y):
'''
Evaluate the interpolate values.
:param x: (*array_like*) X to evaluate the interpolate at.
:param y: (*array_like*) Y to evaluate the interpolate at.
'''
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
if isinstance(y, list):
y = np.array(y)
if isinstance(y, NDArray):
y = y.asarray()
r = self._func.interpolate(x, y)
if isinstance(r, float):
return r
else:
return NDArray(r)
class RectInterpNearest(object):
'''
Bivariate nearest interpolation over a rectangular mesh.
Can be used for both smoothing and interpolating data.
:param x: (*array_like*) 1-D arrays of x coordinate in strictly ascending order.
:param y: (*array_like*) 1-D arrays of y coordinate in strictly ascending order.
:param z: (*array_like*) 2-D array of data with shape (x.size,y.size).
'''
def __init__(self, x, y, z):
if isinstance(x, list):
x = np.array(x)
if isinstance(y, list):
y = np.array(y)
if isinstance(z, list):
z = np.array(z)
self._func = RectNearestInterpolator(x.asarray(), y.asarray(), z.asarray())
def __call__(self, x, y):
'''
Evaluate the interpolate values.
:param x: (*array_like*) X to evaluate the interpolate at.
:param y: (*array_like*) Y to evaluate the interpolate at.
'''
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
if isinstance(y, list):
y = np.array(y)
if isinstance(y, NDArray):
y = y.asarray()
r = self._func.interpolate(x, y)
if isinstance(r, float):
return r
else:
return NDArray(r)
class RectInterpNearest3D(object):
"""
3D nearest interpolation over a rectangular mesh.
Can be used for both smoothing and interpolating data.
:param x: (*array_like*) 1-D arrays of x coordinate in strictly ascending order.
:param y: (*array_like*) 1-D arrays of y coordinate in strictly ascending order.
:param z: (*array_like*) 1-D array of z coordinate in strictly ascending order.
:param v: (*array_like*) 3-D array of data with shape (z.size,y.size,x.size).
"""
def __init__(self, x, y, z, v):
if isinstance(x, list):
x = np.array(x)
if x.ndim == 3:
x = x[0,0]
if isinstance(y, list):
y = np.array(y)
if y.ndim == 3:
y = y[0,:,0]
if isinstance(z, list):
z = np.array(z)
if z.ndim == 3:
z = z[:,0,0]
if isinstance(v, list):
v = np.array(v)
self._func = RectNearestInterpolator3D(x.asarray(), y.asarray(), z.asarray(), v.asarray())
def __call__(self, x, y, z):
"""
Evaluate the interpolate values.
:param x: (*array_like*) X to evaluate the interpolate at.
:param y: (*array_like*) Y to evaluate the interpolate at.
:param z: (*array_like*) Z to evaluate the interpolate at.
"""
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
if isinstance(y, list):
y = np.array(y)
if isinstance(y, NDArray):
y = y.asarray()
if isinstance(z, list):
z = np.array(z)
if isinstance(z, NDArray):
z = z.asarray()
r = self._func.interpolate(x, y, z)
if isinstance(r, float):
return r
else:
return NDArray(r)
class RectInterpLinear3D(object):
"""
3D linear interpolation over a rectangular mesh.
Can be used for both smoothing and interpolating data.
:param x: (*array_like*) 1-D arrays of x coordinate in strictly ascending order.
:param y: (*array_like*) 1-D arrays of y coordinate in strictly ascending order.
:param z: (*array_like*) 1-D array of z coordinate in strictly ascending order.
:param v: (*array_like*) 3-D array of data with shape (z.size,y.size,x.size).
"""
def __init__(self, x, y, z, v):
if isinstance(x, list):
x = np.array(x)
if x.ndim == 3:
x = x[0,0]
if isinstance(y, list):
y = np.array(y)
if y.ndim == 3:
y = y[0,:,0]
if isinstance(z, list):
z = np.array(z)
if z.ndim == 3:
z = z[:,0,0]
if isinstance(v, list):
v = np.array(v)
self._func = RectLinearInterpolator3D(x.asarray(), y.asarray(), z.asarray(), v.asarray())
def __call__(self, x, y, z):
"""
Evaluate the interpolate values.
:param x: (*array_like*) X to evaluate the interpolate at.
:param y: (*array_like*) Y to evaluate the interpolate at.
:param z: (*array_like*) Z to evaluate the interpolate at.
"""
if isinstance(x, list):
x = np.array(x)
if isinstance(x, NDArray):
x = x.asarray()
if isinstance(y, list):
y = np.array(y)
if isinstance(y, NDArray):
y = y.asarray()
if isinstance(z, list):
z = np.array(z)
if isinstance(z, NDArray):
z = z.asarray()
r = self._func.interpolate(x, y, z)
if isinstance(r, float):
return r
else:
return NDArray(r)
def linint2(*args, **kwargs):
"""
Interpolates from a rectilinear grid to another rectilinear grid using bilinear interpolation.
:param x: (*array_like*) X coordinate array of the sample data (one dimension).
:param y: (*array_like*) Y coordinate array of the sample data (one dimension).
:param z: (*array_like*) Value array of the sample data (multi-dimension, last two dimensions are y and x).
:param xq: (*array_like*) X coordinate array of the query data (one dimension).
:param yq: (*array_like*) Y coordinate array of the query data (one dimension).
:returns: (*array_like*) Interpolated array.
"""
if len(args) == 3:
z = args[0]
x = z.dimvalue(z.ndim - 1)
y = z.dimvalue(z.ndim - 2)
xq = args[1]
yq = args[2]
else:
x = args[0]
y = args[1]
z = args[2]
xq = args[3]
yq = args[4]
x = np.array(x)._array
y = np.array(y)._array
z = np.array(z)._array
xq = np.array(xq)._array
yq = np.array(yq)._array
r = ArrayUtil.linint2(z, x, y, xq, yq)
return NDArray(r)
def nearestint2(*args, **kwargs):
"""
Interpolates from a rectilinear grid to another rectilinear grid using nearest interpolation.
:param x: (*array_like*) X coordinate array of the sample data (one dimension).
:param y: (*array_like*) Y coordinate array of the sample data (one dimension).
:param z: (*array_like*) Value array of the sample data (muti-dimension, last two dimensions are y and x).
:param xq: (*array_like*) X coordinate array of the query data (one dimension).
:param yq: (*array_like*) Y coordinate array of the query data (one dimension).
:returns: (*array_like*) Interpolated array.
"""
if len(args) == 3:
z = args[0]
x = z.dimvalue(z.ndim - 1)
y = z.dimvalue(z.ndim - 2)
xq = args[1]
yq = args[2]
else:
x = args[0]
y = args[1]
z = args[2]
xq = args[3]
yq = args[4]
x = np.array(x)._array
y = np.array(y)._array
z = np.array(z)._array
xq = np.array(xq)._array
yq = np.array(yq)._array
r = InterpUtil.nearestint2(z, x, y, xq, yq)
return NDArray(r)
def griddata(points, values, xi=None, **kwargs):
'''
Interpolate scattered data to grid data.
:param points: (*list*) The list contains x and y coordinate arrays of the scattered data.
:param values: (*array_like*) The scattered data array.
:param xi: (*list*) The list contains x and y coordinate arrays of the grid data. Default is ``None``,
the grid x and y coordinate size were both 500.
:param method: (*string*) The interpolation method. [idw | cressman | nearest | inside_mean | inside_min
| inside_max | inside_sum | inside_count | surface | barnes | kriging]
:param fill_value: (*float*) Fill value, Default is ``nan``.
:param pointnum: (*int*) Only used for 'idw' method. The number of the points to be used for each grid
value interpolation.
:param radius: (*float*) Used for 'idw', 'cressman' and 'neareast' methods. The searching raduis. Default
is ``None`` in 'idw' method, means no raduis was used. Default is ``[10, 7, 4, 2, 1]`` in cressman
method.
:param centerpoint: (*boolean*) The grid points located at center or border of grid. Default
is True (pont at center of grid).
:param convexhull: (*boolean*) If the convexhull will be used to mask result grid data. Default is ``False``.
:returns: (*array*) Interpolated grid data (2-D array)
'''
method = kwargs.pop('method', 'idw')
x_s = points[0]
y_s = points[1]
is_3d = False
if len(points) == 3:
z_s = points[2]
is_3d = True
if xi is None:
xn = 500
yn = 500
if is_3d:
xn = 50
yn = 50
zn = 50
z_g = np.linspace(z_s.min(), z_s.max(), zn)
x_g = np.linspace(x_s.min(), x_s.max(), xn)
y_g = np.linspace(y_s.min(), y_s.max(), yn)
else:
x_g = xi[0]
y_g = xi[1]
if is_3d:
z_g = xi[2]
if isinstance(values, NDArray):
values = values.asarray()
if method == 'idw':
radius = kwargs.pop('radius', None)
if radius is None:
pnum = kwargs.pop('pointnum', None)
if is_3d:
r = InterpUtil.interpolation_IDW_Neighbor(x_s.asarray(), y_s.asarray(), z_s.asarray(), values,
x_g.asarray(), y_g.asarray(), z_g.asarray(), pnum)
return NDArray(r), x_g, y_g, z_g
else:
r = InterpUtil.interpolation_IDW_Neighbor(x_s.asarray(), y_s.asarray(), values,
x_g.asarray(), y_g.asarray(), pnum)
else:
pnum = kwargs.pop('pointnum', 2)
if is_3d:
r = InterpUtil.interpolation_IDW_Radius(x_s.asarray(), y_s.asarray(), z_s.asarray(), values,
x_g.asarray(), y_g.asarray(), z_g.asarray(), pnum, radius)
return NDArray(r), x_g, y_g, z_g
else:
r = InterpUtil.interpolation_IDW_Radius(x_s.asarray(), y_s.asarray(), values,
x_g.asarray(), y_g.asarray(), pnum, radius)
elif method == 'cressman':
radius = kwargs.pop('radius', [10, 7, 4, 2, 1])
if isinstance(radius, NDArray):
radius = radius.aslist()
r = InterpUtil.cressman(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), radius)
elif method == 'barnes':
kappa = kwargs.pop('kappa', 1)
gamma = kwargs.pop('gamma', 1)
radius = kwargs.pop('radius', [10, 7, 4, 2, 1])
if radius is None:
r = InterpUtil.barnes(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), kappa, gamma)
else:
if isinstance(radius, NDArray):
radius = radius.aslist()
r = InterpUtil.barnes(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), radius, kappa, gamma)
elif method == 'nearest':
radius = kwargs.pop('radius', np.inf)
if is_3d:
r = InterpUtil.interpolation_Nearest(x_s.asarray(), y_s.asarray(), z_s.asarray(), values,
x_g.asarray(), y_g.asarray(), z_g.asarray(), radius)
return NDArray(r), x_g, y_g, z_g
else:
r = InterpUtil.interpolation_Nearest(x_s.asarray(), y_s.asarray(), values, x_g.asarray(),
y_g.asarray(), radius)
elif method == 'inside' or method == 'inside_mean':
centerpoint = kwargs.pop('centerpoint', True)
r = InterpUtil.interpolation_Inside_Mean(x_s.asarray(), y_s.asarray(), values, x_g.asarray(), y_g.asarray(), centerpoint)
elif method == 'inside_max':
centerpoint = kwargs.pop('centerpoint', True)
r = InterpUtil.interpolation_Inside_Max(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), centerpoint)
elif method == 'inside_min':
centerpoint = kwargs.pop('centerpoint', True)
r = InterpUtil.interpolation_Inside_Min(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), centerpoint)
elif method == 'inside_sum':
centerpoint = kwargs.pop('centerpoint', True)
r = InterpUtil.interpolation_Inside_Sum(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), centerpoint)
elif method == 'inside_count':
centerpoint = kwargs.pop('centerpoint', True)
r = InterpUtil.interpolation_Inside_Count(x_s.aslist(), y_s.aslist(), values, x_g.aslist(), y_g.aslist(), True, centerpoint)
return NDArray(r[0]), x_g, y_g, NDArray(r[1])
elif method == 'surface':
r = GeoComputation.interpolation_Surface(x_s.asarray(), y_s.asarray(), values, x_g.asarray(), y_g.asarray())
elif method == 'kriging':
beta = kwargs.pop('beta', 1.5)
r = InterpUtil.gridDataKriging(x_s.asarray(), y_s.asarray(), values, x_g.asarray(), y_g.asarray(), beta)
else:
return None
convexhull = kwargs.pop('convexhull', False)
if convexhull:
polyshape = GeometryUtil.convexHull(x_s.asarray(), y_s.asarray())
x_gg, y_gg = np.meshgrid(x_g, y_g)
r = GeometryUtil.maskout(r, x_gg._array, y_gg._array, [polyshape])
return NDArray(r), x_g, y_g
else:
return NDArray(r), x_g, y_g