Reputation: 63
Given a set of points in (X, Y, Z) coordinates that are points on a surface, I would like to be able to interpolate Z-values at arbitrary (X, Y) coordinates. I've found some success using mlab.griddata for interpolating values on a grid, but I want to be able to call a general use function for any (X, Y) coordinate.
The set of points form a roughly hemispherical surface. To simplify the problem, I am trying to write a method that interpolates values between known points of the hemisphere defined by the x, y, and z coordinates below. Although there is an analytical solution to find z = f(x, y) for a perfect sphere, such that you don't have to interpolate, the actual set of points will not be a perfect sphere, so we should assume that we need to interpolate values at unknown (X, Y) coordinates. Link to IPython notebook with point data
resolution = 10
u = np.linspace(-np.pi / 2, np.pi / 2, resolution)
v = np.linspace(0, np.pi, resolution)
U, V = np.meshgrid(u, v)
xs = np.sin(U) * np.cos(V)
ys = np.sin(U) * np.sin(V)
zs = np.cos(U)
I have been using scipy.interpolate.interp2d
, which "returns a function whose call method uses spline interpolation to find the value of new points."
def polar(xs, ys, zs, resolution=10):
rs = np.sqrt(np.multiply(xs, xs) + np.multiply(ys, ys))
ts = np.arctan2(ys, xs)
func = interp2d(rs, ts, zs, kind='cubic')
vectorized = np.vectorize(func)
# Guesses
ri = np.linspace(0, rs.max(), resolution)
ti = np.linspace(0, np.pi * 2, resolution)
R, T = np.meshgrid(ri, ti)
Z = vectorized(R, T)
return R * np.cos(T), R * np.sin(T), Z
Unfortunately I get pretty weird results, similarly to another StackOverflow user who tried to use interp2d.
The most success I have found thus far is using inverse squares to estimate values of Z at (X, Y). But the function is not perfect for estimating values of Z near Z=0.
What can I do to get a function z = f(x, y)
given a set of points in (x, y, z)? Am I missing something here... do I need more than a point cloud to reliably estimate a value on a surface?
EDIT:
This is the function that I ended up writing. The function takes input arrays of xs, ys, zs
and interpolates at x, y
using scipy.interpolate.griddata
, which does not require a regular grid. I'm sure there is a smarter way to do this and would appreciate any updates, but it works and I'm not concerned with performance. Including a snippet in case it helps anyone in the future.
def interpolate(x, y, xs, ys, zs):
r = np.sqrt(x*x + y*y)
t = np.arctan2(y, x)
rs = np.sqrt(np.multiply(xs, xs) + np.multiply(ys, ys))
ts = np.arctan2(ys, xs)
rs = rs.ravel()
ts = ts.ravel()
zs = zs.ravel()
ts = np.concatenate((ts - np.pi * 2, ts, ts + np.pi * 2))
rs = np.concatenate((rs, rs, rs))
zs = np.concatenate((zs, zs, zs))
Z = scipy.interpolate.griddata((rs, ts), zs, (r, t))
Z = Z.ravel()
R, T = np.meshgrid(r, t)
return Z
Upvotes: 6
Views: 4125
Reputation: 15423
You're saying that you've tried using griddata
. So why was that not working? griddata
also works if the new points are not regularly spaced. For example,
# Definitions of xs, ys and zs
nx, ny = 20, 30
x = np.linspace(0, np.pi, nx)
y = np.linspace(0, 2*np.pi, ny)
X,Y = np.meshgrid(x, y)
xs = X.reshape((nx*ny, 1))
ys = Y.reshape((nx*ny, 1))
## Arbitrary definition of zs
zs = np.cos(3*xs/2.)+np.sin(5*ys/3.)**2
## new points where I want the interpolations
points = np.random.rand(1000, 2)
import scipy.interpolate
zs2 = scipy.interpolate.griddata(np.hstack((xs, ys)), zs, points)
Is this not what you are after?
Upvotes: 3
Reputation: 15423
If I understand your question, you have points xs
, ys
, zs
that are defined by
xs = np.sin(U) * np.cos(V)
ys = np.sin(U) * np.sin(V)
zs = np.cos(U)
What you want is to be able to interpolate and find a z-value for a given x and y? Why do you need interpolation? The above equations represent a sphere, they can be rewritten as xs*xs + ys*ys + zs*zs = 1
, so there is an easy analytical solution to this problem:
def Z(X, Y):
return np.sqrt(1-X**2-Y**2)
## or return -np.sqrt(1-X**2-Y**2) since this equation has two solutions
unless I misunderstood the question.
Upvotes: 1