向 E 先生道歉,因为我周末没有上网。但是,我确实可以使用计算机,并且我找到了我的问题的答案,尽管它有点难看。我确信可以改进以下方法,并且由于上述原因,我知道这是 3d 绘图软件的重要基本用途,因此,如果有人可以提供任何改进,将不胜感激。以下解释假设您使用的是 Linux,但我确信在其他操作系统上执行相同的操作(即保存和运行 python 文件)很简单。
首先生成一个样本数据文件。真实数据来自 Fortran 程序,但出于当前测试目的,我将使用 python 生成示例数据文件。将以下代码存储在文件“gen-data.py”中(复制粘贴到您喜欢的文本编辑器中并然后点击“另存为”等)
#!/usr/bin/python
import numpy as numpy
# run this program with
#" python gen-data.py > stream.out "
# to generate sample data file stream.out
x_low = -1 ; x_upp = 1 ; NX = 5
y_low = -2 ; y_upp = 2 ; NY = 3
z_low = -3 ; z_upp = 3 ; NZ = 3
x_arr = numpy.linspace(x_low,x_upp,num = NX, endpoint=True)
y_arr = numpy.linspace(y_low,y_upp,num = NY, endpoint=True)
z_arr = numpy.linspace(z_low,z_upp,num = NZ, endpoint=True)
#the following line generates data (for distance from the origin)
# over a structured grid
for x in x_arr:
for y in y_arr:
for z in z_arr:
print x , y , z , x**2 + y**2 + z**2
使用 python gen-data.py > stream.out 运行程序,它将在数据文件“stream.out”中存储上述类型的示例数据文件。您应该有一个具有以下值的文件:
-1.0 -2.0 -3.0 14.0
-1.0 -2.0 0.0 5.0
-1.0 -2.0 3.0 14.0
-1.0 0.0 -3.0 10.0
-1.0 0.0 0.0 1.0
-1.0 0.0 3.0 10.0
-1.0 2.0 -3.0 14.0
-1.0 2.0 0.0 5.0
-1.0 2.0 3.0 14.0
-0.5 -2.0 -3.0 13.25
。. . .
0.5 2.0 3.0 13.25
1.0 -2.0 -3.0 14.0
1.0 -2.0 0.0 5.0
1.0 -2.0 3.0 14.0
1.0 0.0 -3.0 10.0
1.0 0.0 0.0 1.0
1.0 0.0 3.0 10.0
1.0 2.0 -3.0 14.0
1.0 2.0 0.0 5.0
1.0 2.0 3.0 14.0
数据文件中的每一行都是
xyz V(x,y,z)的形式,
其中 x,y,z 描述空间中一个点的 x,y,x 坐标,V(x,y,z) 表示值那时的标量。
绘制数据
我们的问题是如何使用 mayavi 绘制这些数据——我对绘制等值面特别感兴趣,这可以使用 contour3d 命令来实现。网络上的大量示例显示了使用 mgrid 命令生成的轮廓 3d 绘图数据。(也有使用 ogrid 命令的示例,但对我来说 mgrid 更容易理解)。策略:如果我们可以操纵我们的数据,使其具有与 mgrid 命令的输出相同的形状和来源,我们应该能够绘制它。
分析来自 mgrid 的输出,很明显需要 3 个 3 维 numpy 数组来存储 x、y 和 z 坐标,以及另一个 3 维 numpy 数组来存储这些点的标量值(上面的 V)。以下程序实现了这些步骤。我认为该程序肯定可以改进:我敢肯定,例程 fill_up_array 可以由了解 python 中的数组切片的人替换为单行程序,并且可能还有其他地方可以改进。我不禁想到,对于知道他们在 numpy/mayavi 中做什么的人来说,整个事情可能只需要 1 或 2 行就可以完成,但是我相信下面的程序很容易理解并且可以工作(你应该请参阅出现的图中截断的球面)。
将以下文件保存到“hope.py”并使用
python hope.py运行
import numpy
from mayavi import mlab
def fill_up_array(output_arr,source_arr,nx,ny,nz,posn):
# takes a slice of results from source_arr and writes to output_arr
# there is probably an easy one liner to do this ?
#TODO: add checks to ensure input is sensible
for i in range(nx):
for j in range(ny):
for k in range(nz):
output_arr[i][j][k] = source_arr[i][j][k][posn]
# these numbers have to correspond to those used in gen-data.py
NX = 5 ; NY = 3 ; NZ = 3
NDIM = 4 # number of columns in data file, 4 for current example
#initialise arrays:
# xx will contain x coordinate of data point
# yy will contain y coordinate of data point
# zz will contain z coordinate of data point
# VV will contain sample scalar value at (x,y,z)
xx = numpy.zeros((NX,NY,NZ))
yy = numpy.zeros((NX,NY,NZ))
zz = numpy.zeros((NX,NY,NZ))
VV = numpy.zeros((NX,NY,NZ))
#now read in values from stream.out file to these arrays
full = numpy.loadtxt("stream.out")
fy = numpy.reshape(full, (NX,NY,NZ,NDIM))
fill_up_array(xx,fy,NX,NY,NZ,0)
fill_up_array(yy,fy,NX,NY,NZ,1)
fill_up_array(zz,fy,NX,NY,NZ,2)
fill_up_array(VV,fy,NX,NY,NZ,3)
#test plot
mlab.contour3d(xx, yy, zz, VV)
mlab.show()