如何使用Python在任意平面内绘制矢量场?

时间:2017-08-17 11:35:56

标签: python numpy matplotlib vector 3d

我有一个三维速度矢量场,形状为numpy(zlength,ylength,xlength,3)。 ' 3'包含速度分量(u,v,w)。

我可以很容易地使用箭头绘制正交x-y,x-z和y-z平面中的矢量场,例如

X, Y = np.meshgrid(xvalues, yvalues)

xyfieldfig = plt.figure()
xyfieldax = xyfieldfig.add_subplot(111)
Q1 = xyfieldax.quiver(X, Y, velocity_field[zslice,:,:,0], velocity_field[zslice,:,:,1])

但是,我希望能够在任意平面内查看速度场。

我尝试通过执行以下操作将速度场投影到平面上:

projected_field = np.zeros(zlength,ylength,xlength,3)
normal = (nx,ny,nz) #normalised normal to the plane

for i in range(zlength):
    for j in range(ylength):
        for k in range(xlength):
            projected_field[i,j,m] = velocity_field[i,j,m] - np.dot(velocity_field[i,j,m], normal)*normal

然而,这(当然)仍然留给我一个具有相同形状的3d numpy数组:(zlength,ylength,xlength,3)。 projection_field现在包含位于每个局部(x,y,z)位置的平面内的每个(x,y,z)位置的速度矢量。

如何将velocity_field投影到单个平面上?或者,我现在如何沿一个平面绘制我的projection_field?

提前致谢!

1 个答案:

答案 0 :(得分:1)

你关闭了。 Daniel F的建议是对的,你只需要知道如何进行插值。这是一个有效的例子

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate  


def norm(v,axis=0):
    return np.sqrt(np.sum(v**2,axis=axis))

#Original velocity field
xpoints = np.arange(-.2, .21, 0.05)
ypoints = np.arange(-.2, .21, 0.05)
zpoints = np.arange(-.2, .21, 0.05)

x, y, z = np.meshgrid(xpoints,ypoints,zpoints,indexing='ij')

#Simple example
#(u,v,w) are the components of your velocity field
u = x
v = y
w = z 

#Setup a template for the projection plane. z-axis will be rotated to point
#along the plane normal
planex, planey, planez  =
    np.meshgrid(np.arange(-.2,.2001,.1), 
                 np.arange(-.2,.2001,.1), [0.1], 
                 indexing='ij')

planeNormal = np.array([0.1,0.4,.4])
planeNormal /= norm(planeNormal)

#pick an arbirtrary vector for projection x-axis
u0 = np.array([-(planeNormal[2] + planeNormal[1])/planeNormal[0], 1, 1])
u1 = -np.cross(planeNormal,u0) 
u0 /= norm(u0)
u1 /= norm(u1)

#rotation matrix
rotation = np.array([u0,u1,planeNormal]).T


#Rotate plane to get projection vertices
rotatedVertices = rotation.dot( np.array( [planex.flatten(), planey.flatten(), planez.flatten()]) ).T


#Now you can interpolate gridded vector field to rotated vertices
uprime = scipy.interpolate.interpn( (xpoints,ypoints,zpoints), u, rotatedVertices, bounds_error=False )
vprime = scipy.interpolate.interpn( (xpoints,ypoints,zpoints), v, rotatedVertices, bounds_error=False )
wprime = scipy.interpolate.interpn( (xpoints,ypoints,zpoints), w, rotatedVertices, bounds_error=False )

#Projections
cosineMagnitudes = planeNormal.dot( np.array([uprime,vprime,wprime]) )

uProjected = uprime - planeNormal[0]*cosineMagnitudes
vProjected = vprime - planeNormal[1]*cosineMagnitudes
wProjected = wprime - planeNormal[2]*cosineMagnitudes

如果你想获得想象力,可以使用一些tensordot操作减少行数。另外,这个或一些近似变体在indexing='ij'中没有meshgrid的情况下也可以使用。

原始字段:

fig = plt.figure()
ax = fig.gca(projection='3d')

ax.quiver(x, y, z, u, v, w, length=0.1, normalize=True)

original

预计字段:

fig = plt.figure()
ax = fig.gca(projection='3d')

ax.quiver(rotatedVertices[:,0], rotatedVertices[:,1], rotatedVertices[:,2], 
          uprime, vprime,wprime, length=0.5, color='blue', label='Interpolation only')
ax.quiver(rotatedVertices[:,0], rotatedVertices[:,1], rotatedVertices[:,2], 
          uProjected, vProjected, wProjected, length=0.5, color='red', label='Interpolation + Projection')


plt.legend()

projected