I should read entire posts before sending people down the wrong
pathways. I just happened to be working on a Python equivalent to MATLAB
"triplot" stuff when I read your subject line and made the wrong
assumptions. That program does just plot the edges, as you noted.
I have attached a python program, much of which is a translation of a
program I found at M*B central, contributed from the outside. Given a
triangulation, it allows you to interpolate on a regular rectangular
grid (dx=constant, dy=another constant). In your case, it should allow
you to use your original triangulation, and should avoid the convex hull
artifacts of your original griddata plot. I do not know if this new
program will give you a figure that will look as good as your latest
based on John's suggestion or not.
Just a few warnings:
1. I use an environment that (like matlab but very unpythonic) imports
everything, so the attached may need to import one or two more routines
2. I have only tested with generated data, using triangulations created
with delaunay, but it worked okay as long as my random points did not
lead to bad triangles.
3. The routines use a lot of loops, so they are relatively slow - should
be an ideal program for Cython though.
3. method='linear' uses linear interp,and is very stable. It should not
be influenced in any way by convexity.
method='quadratic' uses a quadratic method, which does well except in
the presence of very thin triangles. I suspect that derivative
estimation at the vertices has problems on the edges and may very well
be influenced by the convexity.
linear on a fine grid will probably look pretty good for you.
4. to get something as nice as the mayavi sample, you will probably need
a fine rectangular mesh (maybe 200x200).
I tested the tinterp program in octave for a number of problems and
found that the quadratic option gave nice results when I did not have
functional discontinuities, and when I had good triangulations. I have
been meaning to translate this to Python, so thanks for the motivation.
At the very least, this program may help you appreciate John's
suggestions more.
Cheers,
Eric
Ondrej Certik wrote:
Ok, I made a progress, it seems it's working. Script and picture
Forgot to attach the script.
Ondrej
------------------------------------------------------------------------
------------------------------------------------------------------------------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, &
iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian
Group, R/GA, & Big Spaceship. http://www.creativitycat.com
------------------------------------------------------------------------
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
import numpy as np
from numpy import ones,shape, int32, floor, ceil, array, dot, zeros,reshape
from numpy import logical_not, NaN, any, vstack, sum, mgrid, sin,cos
def mesh_grid_tsearch(X,Y,dx,dy,points,tris):
"""
locate the specific triangle for point in a uniform mesh
INPUT:
X,Y are the x- and y- coodinates from the mesh generated with
meshgrid or mgrid or ogrid (X,Y must have the same shape)
dx is the constant distance between x grid lines and
dy is the constant distance between y grid lines
(dx does not have to equal dy)
points are the vertices of triangulation (shape(points)==[n_points,2])
tris are the triangles, three integer index values pointing to rows from points
shape(tris)==[n_triangles,3]
OUTPUT:
triangle number (row of tris) for each point of the mesh,
or -1 if the mesh point is not located in any triangle
"""
## Compute vectors
tri_loc=int32(-ones(shape(X)))
nr,nc=shape(X)
x_min=np.min(X)
x_max=np.max(X)
y_min=np.min(Y)
y_max=np.max(Y)
n_tris = shape(tris)[0]
for n in range(n_tris):
r=tris[n,:]
A=points[r[0],:]
B=points[r[1],:]
C=points[r[2],:]
tri_x_min=min(A[0],B[0],C[0])
tri_y_min=min(A[1],B[1],C[1])
tri_x_max=max(A[0],B[0],C[0])
tri_y_max=max(A[1],B[1],C[1])
# determination of imin, etc only place where grid regularity required
i_min = int32(max(0,floor((tri_x_min-x_min)/dx)))
j_min = int32(max(0,floor((tri_y_min-y_min)/dy)))
i_max = int32(min(nc,ceil((tri_x_max-x_min)/dx)+1))
j_max = int32(min(nr,ceil((tri_y_max-y_min)/dy)+1))
if not (i_min>=nc or i_max<=0 or j_min>=nc or j_max<=0):
for i in range(i_min,i_max):
for j in range(j_min,j_max):
if tri_loc[i,j]<0:
P=array([X[i,j],Y[i,j]])
v0 = C - A
v1 = B - A
v2 = P - A
## Compute dot products
dot00 = dot(v0, v0)
dot01 = dot(v0, v1)
dot02 = dot(v0, v2)
dot11 = dot(v1, v1)
dot12 = dot(v1, v2)
## Compute barycentric coordinates
invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01)
u = (dot11 * dot02 - dot01 * dot12) * invDenom
v = (dot00 * dot12 - dot01 * dot02) * invDenom
## Check if point is in triangle
if (u >= 0) and (v >= 0) and (u + v <= 1):
tri_loc[i,j]=int32(n)
return tri_loc
def tinterp(p,t,f,xi,yi,method='linear'):
"""
Interpolation of scattered, triangulated data on a uniform grid.
INPUTS:
p = [x1,y1 x2,y2 etc] - an Nx2 array defining the [x,y]
coordinates of the scattered vertices
t = [n11,n12,n13 n21,n22,n23 etc] - an Mx3 array defining the
triangulation of the points in p, as
returned by delaunayn(p)
f = [f1 f2 etc] - an Nx1 vector defining the value
of the function at the scattered
vertices
xi,yi - arrays of identical
size, defining the [x,y] coordinates
where the function is to be
interpolated
method = 'linear','quadratic' - Type of interpolant, method is
optional and if not passed the
'linear' method is used
OUTPUT:
fi - The interpolation evaluated at
all points in xi,yi.
The 'linear' method should return identical results to griddata. The
'quadratic' method is NEW! (I think) and should return more accurate results
when compared with the 'cubic' method in gridata (See tester.m).
Example:
p = rand(100,2)
t = delaunay(p)
f = exp(-20*sum((p-0.5)**2,2))
figure, trimesh(t,p(:,1),p(:,2),f), title('Exact solution on scattered data')
x = linspace(0,1,50)
x,y = meshgrid(x,x)
fL = tinterp(p,t,f,x,y)
fQ = tinterp(p,t,f,x,y,'quadratic')
figure, mesh(x,y,fL), title('Linear interpolation')
figure, mesh(x,y,fQ), title('Quadratic interpolation')
Original MATLAB VERSION:
Any comments? Let me know:
d_engwi...@hotmail.com
Darren Engwirda - 2006
Quick Python Translation from M*B
Eric Carlson - 2009
"""
# Check I/O
# Error checking
sizx = shape(xi)
sizy = shape(yi)
dx=xi[1,0]-xi[0,0]
dy=yi[0,1]-yi[0,0]
# Find enclosing triangle of points in pii
i=mesh_grid_tsearch(xi,yi,dx,dy,p,t)
ig = i.flatten()
pii = vstack((xi.flatten(),yi.flatten())).T
# Allocate output
fi = zeros(shape(pii)[0])
# i = tsearch(p[:,0],p[:,1],t,pii[:,0],pii[:,1])
# Deal with points oustide convex hull
in1 = logical_not(ig<0)
# Keep internal points
pin = pii[in1,:]
tin = t[ig[in1],:]
# Corner nodes
t1 = tin[:,0]
t2 = tin[:,1]
t3 = tin[:,2]
# Linear shape functions
dp1 = pin-p[t1,:]
dp2 = pin-p[t2,:]
dp3 = pin-p[t3,:]
A3 = abs(dp1[:,0]*dp2[:,1]-dp1[:,1]*dp2[:,0])
A2 = abs(dp1[:,0]*dp3[:,1]-dp1[:,1]*dp3[:,0])
A1 = abs(dp3[:,0]*dp2[:,1]-dp3[:,1]*dp2[:,0])
# Interpolant
if method=='linear': # Linear interpolation
# Take weighted average of constant extrapolations
print 'linear interpolation'
fi[in1] = (A1*f[t1]+A2*f[t2]+A3*f[t3]) / (A1+A2+A3)
else: # Quadratic interpolation
print 'quadratic interpolation'
# Form gradients
fx,fy = tgrad(p,t,f)
# Take weighted average of linear extrapolations
fi[in1] = ( A1*(f[t1] + dp1[:,0]*fx[t1] + dp1[:,1]*fy[t1]) +
A2*(f[t2] + dp2[:,0]*fx[t2] + dp2[:,1]*fy[t2]) +
A3*(f[t3] + dp3[:,0]*fx[t3] + dp3[:,1]*fy[t3]) )/ (A1+A2+A3)
# Deal with outside points
if any(logical_not(in1)):
fi[logical_not(in1)] = NaN
fi = np.ma.masked_where(np.isnan(fi),fi)
# Reshape output
fi = reshape(fi,sizx)
return fi
#######################################################################################
def tgrad(p,t,f):
"""
Approximate [df/dx,df/dy] at the vertices of triangulation.
"""
# Nodes
t1 = t[:,0]
t2 = t[:,1]
t3 = t[:,2]
# Evaluate centroidal gradients (piecewise-linear interpolants)
x23 = p[t2,0]-p[t3,0]
y23 = p[t2,1]-p[t3,1]
x21 = p[t2,0]-p[t1,0]
y21 = p[t2,1]-p[t1,1]
# Centroidal values - [df/dx,df/dy]
den = (x23*y21-x21*y23)
fcx = (y23*f[t1]+(y21-y23)*f[t2]-y21*f[t3])/den
fcy = -(x23*f[t1]+(x21-x23)*f[t2]-x21*f[t3])/den
# Calculate simplex quality
q = quality(p,t)
# Form nodal gradients.
# Take the quality weighted average of the neighbouring centroidal values.
# Low quality simplices ("thin" triangles) can contribute inaccurate
# gradient information - quality weighting seems to limit this effect.
fnx = 0.0*f
fny = 0.0*f
den = 0.0*f
for k in range(shape(t)[0]):
# Nodes
n1 = t1[k]
n2 = t2[k]
n3 = t3[k]
# Current values
qk = q[k]
qfx = qk*fcx[k]
qfy = qk*fcy[k]
# Average to n1
fnx[n1] = fnx[n1]+qfx
fny[n1] = fny[n1]+qfy
den[n1] = den[n1]+qk
# Average to n2
fnx[n2] = fnx[n2]+qfx
fny[n2] = fny[n2]+qfy
den[n2] = den[n2]+qk
# Average to n3
fnx[n3] = fnx[n3]+qfx
fny[n3] = fny[n3]+qfy
den[n3] = den[n3]+qk
fnx = fnx/den
fny = fny/den
return fnx,fny
######################################################################################
def quality(p,t):
"""
Approximate simplex quality of triangulation
"""
# Nodes
p1 = p[t[:,0],:]
p2 = p[t[:,1],:]
p3 = p[t[:,2],:]
# Approximate quality
d12 = p2-p1
d13 = p3-p1
q = 3.4641*abs(d12[:,0]*d13[:,1]-d12[:,1]*d13[:,0])/(sum(d12**2,1)+sum(d13**2,1)+sum((p3-p2)**2,1))
return q
import matplotlib.delaunay as delaunay
import matplotlib.pyplot as pp
import scipy as sp
x, y = mgrid[0.0:2.0:101j,0.0:2.0:101j]
dx=x[1,0]-x[0,0]
dy=y[0,1]-y[0,0]
npts=105
#using scipy version >= .7
#scipy version<.7, sp.random(npts)
xpt=sp.random.random_sample(npts)*1.75+.125
ypt=sp.random.random_sample(npts)*1.75+.125
#create triangulation
pts=vstack((xpt,ypt)).T
my_func=lambda x,y:sin(x**2)*cos(y*x)
f = my_func(xpt,ypt)
circumcenters, edges, tri_points, tri_neighbors = delaunay.delaunay(xpt, ypt)
fa1=tinterp(pts,tri_points,f,x,y,method='linear')
pp.contourf(x,y,fa1)
#pp.plot(xpt[edges.T],ypt[edges.T],'k--', linewidth=.5)
pp.figure()
fa=tinterp(pts,tri_points,f,x,y,method='quadratic')
pp.contourf(x,y,fa)
#pp.plot(xpt[edges.T],ypt[edges.T],'k--', linewidth=.5)
pp.figure()
pp.contourf(x,y,my_func(x,y))
pp.figure()
##tri1 = delaunay.Triangulation(xpt,ypt)
### interpolate data
##interp1 = tri1.nn_interpolator(f)
##pp.contourf(x,y,interp1(x,y))
import griddata
pp.contourf(x,y,pp.mlab.griddata(xpt, ypt, f, x, y))
##figure()
##contourf(x,y,fa-fa1)
##pp.plot(xpt[edges.T],ypt[edges.T],'k--', linewidth=.5)
##for n in range(shape(tri_points)[0]):
## r=tri_points[n,:]
## A=pts[r[0],:]
## B=pts[r[1],:]
## C=pts[r[2],:]
## the_center = (A+B+C)/3
## text(the_center[0], the_center[1],str(n))
#plot(x,y,'k.')
------------------------------------------------------------------------------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, &
iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian
Group, R/GA, & Big Spaceship. http://www.creativitycat.com
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users