Python: interpolating in a triangular mesh - python

Is there any decent Pythonic way to interpolate in a triangular mesh, or would I need to implement that myself? That is to say, given a (X,Y) point we'll call P, and a mesh (vertices at (X,Y) with value Z, forming triangular facets), estimate the value at P. So that means first find the facet that contains the point, then interpolate - ideally a higher order interpolation than just "linearly between the facet's vertices" (i.e., taking into account the neighboring facets)?
I could implement it myself, but if there's already something available in Python....
(I checked scipy.interpolate, but its "meshes" seem to just be regular point grids. This isn't a grid, it's a true 2D mesh; the vertices can be located anywhere.)

I often use matplotlib.tri for this purpose. Here Xv,Yv are the vertices (or nodes) of the triangles, and Zv the values at those nodes:
from matplotlib.tri import Triangulation, LinearTriInterpolator, CubicTriInterpolator
#you can add keyword triangles here if you have the triangle array, size [Ntri,3]
triObj = Triangulation(Xv,Yv)
#linear interpolation
fz = LinearTriInterpolator(triObj,Zv)
Z = fz(X,Y)
#cubic interpolation
fzc = CubicTriInterpolator(triObj,Zv)
Zc = fz(X,Y)

Related

Inverse of scipy griddata function

I have a rectangular grid of data with coordinates (x,y). For each point in the grid (x_i,y_i) a Z value is associated. I simply want to calculate what the value of Z might be at some generic sparse x_n,y_n points that are within the grid but do not exactly correspond to the grid points. Simply put, I am looking for a function that is the inverse of the scipy gridddata function (e.g., from a grid to scattered data).

SciPy Delaunay triangulation changes multiple points of simplex for tiny change in parameters

I'm using a Delaunay triangulation to interpolate in some function values evaluated at a set of parameters on a regular 4-dimensional grid. Sometimes, when a parameter value changes by a small amount that takes it to a new simplex, more than one point in the simplex changes. I expect that as I vary one of the parameter continuously, I'd move from simplex to simplex by changing just one point in the simplex at a time (and that's usually the case in my code, too). Instead, consider this script:
import numpy as np
from scipy.spatial import Delaunay
# hideous construction to get the desired 4d grid of points
# with points at [-1, -0.5, 0, 0.5, 1] along each axis
X = np.vstack(list(map(np.ravel, np.meshgrid(*[np.linspace(-1, 1, 5) for i in range(4)])))).T
tri = Delaunay(X)
delta = 1e-10
print(np.sort(tri.vertices[tri.find_simplex([-0.25, -0.05, 0.5+delta, 0.1])]))
print(np.sort(tri.vertices[tri.find_simplex([-0.25, -0.05, 0.5-delta, 0.1])]))
which produces
[192 292 317 318 322]
[167 292 293 313 317]
Note that these two simplices differ by 3 points, where I expect one, and I haven't devised a 2- or 3-D example where more than one vertex would change.
I'm 99% sure this is because my points are on a regular grid but I can't find a detailed answer of why or how to avoid the problem. I know that the triangulation isn't unique but that isn't fundamentally a problem. Various tricks appear to change where I encounter this issue but I haven't yet found a "fix" that prevents the issue from appearing anywhere.
Edit
I've managed to find an example in 3D, which allows me to visualise the problem.
import numpy as np
from scipy.spatial import Delaunay
X = np.vstack(list(map(np.ravel, np.meshgrid(*[np.linspace(-1, 1, 5) for i in range(3)])))).T
tri = Delaunay(X)
delta = 1e-6
x = np.array([-0.25, 0, 0.07])
fig = pl.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(*x, c='k')
x[1] = delta
s = X[tri.vertices[tri.find_simplex(x)]]
for i, si in enumerate(s):
for j, sj in enumerate(s[i:]):
ax.plot3D(*np.vstack([si, sj]).T, c='C0')
x[1] = -delta
s = X[tri.vertices[tri.find_simplex(x)]]
for i, si in enumerate(s):
for j, sj in enumerate(s[i:]):
ax.plot3D(*np.vstack([si, sj]).T, c='C1')
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_zlabel('$z$')
and here are two aspects on the output.
The blue and orange simplices are contain the interpolation point before and after it crosses y=0 (from positive to negative). My assumption was that both simplices would have the same triangular face along the y=0 plane but apparently this is incorrect. Is this fundamental to the Delaunay triangulation in this degenerate case or something about the implementation? And is there a way to avoid it? The QHull option Qx (which is in SciPy's default options for D>4) seems to help for this example but I'm not sure about globally.
Your question is not really about the implementation of triangulation in scipy.spatial. and it is more about the math of the Delaunay triangulation as a mathematical object.
Delaunay triangulations in dimension D are very well defined, ... when the points are "general position". That means that no D+2 points from the input points are on a common sphere. If that happens, one says the Delaunay triangulation is "degenerate". When the triangulation is degenerate, the Delaunay triangulation is not well defined, and there exists multiple ways to triangulate the convex hull of the points while preserving the Delaunay property.
What is what you observe: your points are on a regular grid, and that is a very degenerated point set (for the Delaunay property). Any slight modification of the coordinates can trigger the flip of multiple simplices, to restore the Delaunay property.
Maybe you can understand that behavior by having a look at the dual object of the Delaunay triangulation: its Voronoi diagram. For points sets close to a regular grid, the diagram is degenerated: it has Voronoi edges that are zero-length, or with a length close to zero. And any small modification of the coordinates of the point can change the topology of the Voronoi diagram (and thus of the Delaunay triangulation as well).

python - Finding the vertices of the cuboid surrounding a coordinate in a cuboidal 3-d grid with non-regular spacings

I will have a 3-d grid of points (defined by Cartesian vectors). For any given coordinate within the grid, I wish to find the 8 grid points making the cuboid which surrounds the given coordinate. I also need the distances between the vertices of the cuboid and the given coordinate. I have found a way of doing this for a meshgrid with regular spacings, but not for irregular spacings. I do not yet have an example of the irregularly spaced grid data, I just know that the algorithm will have to deal with them eventually. My solution for the regularly spaced points is based off of this post, Finding index of nearest point in numpy arrays of x and y coordinates and is as follows:
import scipy as sp
import numpy as np
x, y, z = np.mgrid[0:5, 0:10, 0:20]
# Example 3-d grid of points.
b = np.dstack((x.ravel(), y.ravel(), z.ravel()))[0]
tree = sp.spatial.cKDTree(b)
example_coord = np.array([1.5, 3.5, 5.5])
d, i = tree.query((example_coord), 8)
# i being the indices of the closest grid points, d being their distance from the
# given coordinate, example_coord
b[i[0]], d[0]
# This gives one of the points of the surrounding cuboid and its distance from
# example_coord
I am looking to make this algorithm run as efficiently as possible as it will need to be run a lot. Thanks in advance for your help.

Alternating triangulation pattern on square lattice

I have an array of points in python making a square lattice. I want to triangulate it like this:
so that the braces alternate in a checkerboard pattern from square to square.
My attempts have been based on deforming it before triangulation. For example, shearing the lattice before triangulating via
xy_skew = np.dstack((xypts[:,0]+ 0.1*xypts[:,1], xypts[:,1]))[0]
tri = scipy.spatial.Delaunay(xy_skew)
TRI = tri.vertices
can give me all 'rightward' diagonals or all 'leftward' diagonals, but I haven't found a deformation that can lead to the desired triangulation.
How can I do this efficiently (for lattices of ~million points)?
If relevant, the indices of my points increase in Y first, then increase in X.
Thanks!

Streamlines on a triangulation with matplotlib

I made a triangulation object in matplotlib (out of the P matrix, which contains points coordinates, and the T matrix, which contains the triangles nodes, that describe a rectangle minus a hole) and computed some scalar field called phi at the nodes of this triangulation (using a finite element method applied to a Poisson equation). Using this triangulation I compute the gradient, which is what I am interested in. I made a quiver plot of this vector field, everything is nice, the vectors don't intersect with the hole.
However, when I want to plot streamlines via the streamplot function, they intersect the hole, like in the following figure:
The thing is, in order to trace streamlines, I have to create a structured grid for the streamplot function. But since my vector field is not defined at the nodes of the regular grid, I need to interpolate the values at these nodes. For that I used griddata. The problem is, in doing so, the hole is covered by the regular grid so the vector field becomes defined inside the hole, hence the result. Here is the relevant piece of code that produced the picture:
def plot_streamlines(P, T, phi):
triangulation = tr.Triangulation(P[:,0], P[:,1], T)
interpolator = tr.CubicTriInterpolator(triangulation, phi)
(u_x,u_y) = interpolator.gradient(triangulation.x, triangulation.y)
grid_x, grid_y = np.mgrid[x_min:x_max:100j, y_min:y_max:100j]
grid_u_x = ip.griddata(P, u_x, (grid_x,grid_y), method='cubic')
grid_u_y = ip.griddata(P, u_y, (grid_x,grid_y), method='cubic')
pl.streamplot(grid_x[:,0], grid_y[0,:], -grid_u_x.T, -grid_u_y.T)
I am aware of masked arrays but didn't manage to use the mask to get the result I wanted. I wanted to create a kind of masked regulard grid and then interpolate the vector field on it, but I didn't manage to do it. Does somebody has experience with this kind of problem? Any suggestion will be appreciated.
Thanks!
In your code sample interpolator.gradientis already an interpolator i.e. you do not need to use it in combination with griddata. Try:
grid_u_x, grid_u_y = interpolator.gradient(grid_x, grid_y)
As this interpolator is aware of your triangulation mesh, it should result is a velocity vector filled of nan outside your mesh. Streamplot should hopefully be able to handle this gracefully as in this example:
http://matplotlib.org/examples/images_contours_and_fields/streamplot_demo_masking.html

Categories

Resources