1

我正在努力使用从文件中读取的数据在 mayavi 中绘制简单的轮廓 3d 绘图。数据是一个规则的 3d 笛卡尔网格,形式为

   x1   y1    z1    val(x1,y1,z1)  
   x1   y1    z2    val(x1,y1,z2)  
    .    .     .       .  
   x1   y1     z_K  val(x1,y1,z_K)  

   x1   y2     z1    val(x1,y2,z1)  
    .    .     .       .  
    .    .     .       .  
   x_L   y_M    z_K    val(x_L,y_M,z_K)  

(这里每行的前 3 个值给出了该点的 (x,y,z) 坐标,而第 4 个值给出了该点的标量值。如果有用,我可以粘贴一个最小的示例文件)

可以使用 numpy.loadtxt 成功读取数据文件,但是如何从那里使用 (mayavi) mlab.contour3d 绘制等值面?我认为 loadtxt 的默认输出数组的格式不适合 mlab.contour3d。

我能够找到的所有 mlab.contour3d 示例都使用 ogrid 生成一个网格,然后绘制该网格的一个简单函数(sin 等)。我已经能够成功运行这些示例,但是它们没有告诉我如何将文件中的数据读入准备好绘图的正确格式的数组。如果有人能给我指点,我相信它会帮助很多处于类似位置的新手;绘制存储在另一个程序生成的文件中的 3D 数据肯定是科学家必须做的最常见的绘图任务之一。

4

2 回答 2

1

我发现以下效果很好。

x,y,z,d 是来自原始输入文本文件的一维 numpy 数组,其中 d = f(x,y,z)

# Import relevant modules
import numpy as np
import scipy.interpolate as si
from mayavi import mlab

# Generate the figure
figure = mlab.figure()

# Generate the 3D mesh
xi, yi, zi = np.meshgrid(*([np.linspace(0,1,100)] * 3))

# Interpolate d over the 3D mesh
di = si.griddata((x, y, z), d, (xi, yi, zi))

# Generate the desired figure
min_d = d.min()
max_d = d.max()
grid = mlab.pipeline.scalar_field(di)
mlab.pipeline.volume(grid, vmin=min_d, vmax=min_d + .5*(max_d-min_d))

# Other good options too
## mlab.contour3d(di, vmin=min_d, vmax=min_d + .8*(max_d-min_d))
## pts = mlab.points3d(x, y, z, d)
mlab.axes()
mlab.show()
于 2019-02-20T07:40:32.417 回答
0

向 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()
于 2014-03-10T06:55:02.837 回答