tia*_*ago 4 python numpy scipy
我有一个3D numpy数组,其中包含给定函数的值.我想计算一个2D等值面,或一组代表该函数某些值的等值面.
在这种特定情况下,column = myarray[i, j, :]可以独立地处理3D阵列的每个1D列().所以我想知道的是最后一个索引位置(2D数组),其中函数等于某个值,比方说myvalue.
一些(慢)代码举例说明:
# myarray = 3D ndarray
import numpy as np
from scipy import interpolate
result = np.zeros(nx, ny)
z_values = np.arange(nz)
for i in range(nx):
for j in range(ny):
f = interpolate.interp1d(my_array[i, j], z_values)
result[i, j] = f(myvalue)
Run Code Online (Sandbox Code Playgroud)
我知道这可以加快np.ndenumerate一些技巧和其他技巧,但是想知道是否已经有一种更简单的方法来做这种等表面.我找不到任何东西ndimage或其他图书馆.我知道mayavi2和vtk有很多工具来处理iso-surface,但我的目标不是可视化 - 我想对那些iso-surface值进行计算,而不是显示它们.另外,vtk的许多等面方法似乎涉及多边形等,而我需要的只是每个等值面值的2D阵列.
只使用numpy你可以使用一个很好的解决方案argsort,sort,take以及适当的数组操作.下面的函数使用加权平均值来计算等值面:
def calc_iso_surface(my_array, my_value, zs, interp_order=6, power_parameter=0.5):
if interp_order < 1: interp_order = 1
from numpy import argsort, take, clip, zeros
dist = (my_array - my_value)**2
arg = argsort(dist,axis=2)
dist.sort(axis=2)
w_total = 0.
z = zeros(my_array.shape[:2], dtype=float)
for i in xrange(int(interp_order)):
zi = take(zs, arg[:,:,i])
valuei = dist[:,:,i]
wi = 1/valuei
clip(wi, 0, 1.e6, out=wi) # avoiding overflows
w_total += wi**power_parameter
z += zi*wi**power_parameter
z /= w_total
return z
Run Code Online (Sandbox Code Playgroud)
此解决方案不处理存在多个z对应的情况my_value.下面的代码给出了构建下面的iso表面的应用示例:

from numpy import meshgrid, sin, cos, pi, linspace
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
dx = 100; dy = 50; dz = 25
nx = 200; ny = 100; nz = 100
xs = linspace(0,dx,nx)
ys = linspace(0,dy,ny)
zs = linspace(0,dz,nz)
X,Y,Z = meshgrid( xs, ys, zs, dtype=float)
my_array = sin(0.3*pi+0.4*pi*X/dx)*sin(0.3*pi+0.4*pi*Y/dy)*(Z/dz)
fig = plt.figure()
ax = fig.gca(projection='3d')
z = calc_iso_surface( my_array, my_value=0.1, zs=zs, interp_order=6 )
ax.plot_surface(X[:,:,0], Y[:,:,0], z, cstride=4, rstride=4, color='g')
z = calc_iso_surface( my_array, my_value=0.2, zs=zs, interp_order=6 )
ax.plot_surface(X[:,:,0], Y[:,:,0], z, cstride=4, rstride=4, color='y')
z = calc_iso_surface( my_array, my_value=0.3, zs=zs, interp_order=6 )
ax.plot_surface(X[:,:,0], Y[:,:,0], z, cstride=4, rstride=4, color='b')
plt.ion()
plt.show()
Run Code Online (Sandbox Code Playgroud)
您还可以使用不同的插值功能.请参阅下面的一个示例,它取两个最接近的平均值zs:
def calc_iso_surface_2(my_array, my_value, zs):
'''Takes the average of the two closest zs
'''
from numpy import argsort, take
dist = (my_array - my_value)**2
arg = argsort(dist,axis=2)
z0 = take(zs, arg[:,:,0])
z1 = take(zs, arg[:,:,1])
z = (z0+z1)/2
return z
Run Code Online (Sandbox Code Playgroud)