3.5. 使用Mayavi 绘制3D图

../../_images/mayavi-logo.png

作者GaëlVaroquaux

小费

Mayavi是一种交互式3D绘图软件包。matplotlib也可以做简单的3D绘图,但Mayavi依赖于更强大的引擎(VTK),更适合显示大型或复杂数据。

3.5.1. Mlab:脚本接口

mayavi.mlab模块提供了简单的绘图函数,适用于numpy数组,类似于matplotlib或matlab的绘图界面。尝试在IPython中使用它们,通过使用开关--gui=wx启动IPython。

3.5.1.1. 3D绘图函数

3.5.1.1.1. 点

../../_images/points3d.png

暗示

3D点,用标记(或“字形”)和可选的不同尺寸表示。

x, y, z, value = np.random.random((4, 40))
mlab.points3d(x, y, z, value)

3.5.1.1.2. 线

../../_images/plot3d.png

暗示

连接3D点中的点的线,具有可选的厚度和变化的颜色。

mlab.clf()  # Clear the figure
t = np.linspace(0, 20, 200)
mlab.plot3d(np.sin(t), np.cos(t), 0.1*t, t)

3.5.1.1.3. 高度表面

../../_images/surf.png

暗示

由其高程给定的表面,编码为2D数组

mlab.clf()
x, y = np.mgrid[-10:10:100j, -10:10:100j]
r = np.sqrt(x**2 + y**2)
z = np.sin(r)/r
mlab.surf(z, warp_scale='auto')

3.5.1.1.4. 任意常规网格

../../_images/mesh.png

暗示

由其节点的x,y,z位置给出的表面网格

mlab.clf()
phi, theta = np.mgrid[0:np.pi:11j, 0:2*np.pi:11j]
x = np.sin(phi) * np.cos(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(phi)
mlab.mesh(x, y, z)
mlab.mesh(x, y, z, representation='wireframe', color=(0, 0, 0))

注意

表面由点连接定义以形成三角形或多边形。mayavi.mlab.surf()mayavi.mlab.mesh()中,连接是由数组布局给出的隐式。另请参见mayavi.mlab.triangular_mesh()

我们的数据通常不只是点和值:它需要一些连接信息

3.5.1.1.5. 体数据

../../_images/contour3d.png

暗示

如果您的数据在3D中密集,则更难显示。一个选择是采用数据的等高线。

mlab.clf()
x, y, z = np.mgrid[-5:5:64j, -5:5:64j, -5:5:64j]
values = x*x*0.5 + y*y + z*z*2.0
mlab.contour3d(values)
../../_images/viz_volume_structure.png

此函数适用于规则正交网格: 数组是给出网格形状的3D数组。

3.5.1.2. 数字和装饰

3.5.1.2.1. 图管理

小费

这里是一个有用的功能列表来控制当前的数字

获取当前图: mlab.gcf()
清除当前图: mlab.clf()
设置当前图: mlab.figure(1,bgcolor =(1,1,1),fgcolor =(0.5,0.5,0.5)
将图形保存到图像文件: mlab.savefig('foo.png',size =(300,300))
更改视图: mlab.view(方位角= 45,高程= 54,距离= 1)

3.5.1.2.2. 更改绘图属性

小费

通常,图上各种对象的许多属性可以改变。如果这些可视化是通过mlab函数创建的,更改它们的最简单的方法是使用这些函数的关键字参数,如docstrings中所述。

示例docstring: mlab.mesh

使用作为2D阵列提供的网格间隔数据绘制曲面。

函数签名

mesh(x, y, z, ...)

x,y,z是2D阵列,所有都是相同的形状,给出表面的顶点的位置。这些点之间的连接性由阵列上的连接性表示。

对于简单结构(例如正交网格),优选surf函数,因为它将创建更有效的数据结构。

关键字参数:

颜色:vtk对象的颜色。如果指定,覆盖色彩映射(如果有)。这被指定为范围从0到1的浮点数的三元组,例如对于白色是(1,1,1)。
颜色:要使用的颜色映射类型。
程度:[xmin,xmax,ymin,ymax,zmin,zmax]默认值为x,y,z数组范围。使用此选项可更改所创建对象的范围。
数字:图填充。
行宽:与线,如果使用。必须是浮点数。默认值:2.0
面具:布尔掩码数组来抑制一些数据点。
mask_points:如果提供,则只显示一个“mask_points”数据点。此选项有用来减少大型数据集上显示的点数必须是整数或无。
模式:字形的模式。必须为「2darrow」或「2dcircle」或「2dcross」或「2ddash」或「2ddiamond」或「2dhooked_arrow」或「2dsquare」或「2dthick_arrow」或「2dthick_cross」或「2dtriangle」或「2dvertex」或「箭头」锥形“或”立方体“或”圆柱体“或”点“或”球体“。默认值:sphere
名称:创建的vtk对象的名称。
表示:用于表面的表示类型。必须是“表面”或“线框”或“点”或“网格”或“fancymesh”。默认值:surface
解析度:创建的字形的分辨率。例如,对于球体,这是沿θ和phi的分割数。必须为整数。默认值:8
标量:可选标量数据。
比例因子:在fancy_mesh模式中用于表示顶点的字形的比例因子。必须是浮点数。默认值:0.05
scale_mode:字形的缩放模式('矢量','标量'或'无')。
透明:使得actor的不透明度取决于标量。
tube_radius:用于表示线的管的半径,以网格模式。如果为None,则使用简单的线。
管子:用于表示线的管的边的数量。必须为整数。默认值:6
vmax:vmax用于缩放色度图如果“无”,将使用数据的最大值
vmin:vmin用于缩放色度图如果“无”,将使用数据的最小值
../../_images/polar_mesh.png

示例:

In [1]: import numpy as np
In [2]: r, theta = np.mgrid[0:10, -np.pi:np.pi:10j]
In [3]: x = r * np.cos(theta)
In [4]: y = r * np.sin(theta)
In [5]: z = np.sin(r)/r
In [6]: from mayavi import mlab
In [7]: mlab.mesh(x, y, z, colormap='gist_earth', extent=[0, 1, 0, 1, 0, 1])
Out[7]: <mayavi.modules.surface.Surface object at 0xde6f08c>
In [8]: mlab.mesh(x, y, z, extent=[0, 1, 0, 1, 0, 1],
...: representation='wireframe', line_width=1, color=(0.5, 0.5, 0.5))
Out[8]: <mayavi.modules.surface.Surface object at 0xdd6a71c>

3.5.1.2.3. 装饰

小费

可以向图中添加不同的项目以携带额外的信息,例如彩色条或标题。

In [9]: mlab.colorbar(Out[7], orientation='vertical')
Out[9]: <tvtk_classes.scalar_bar_actor.ScalarBarActor object at 0xd897f8c>
In [10]: mlab.title('polar mesh')
Out[10]: <enthought.mayavi.modules.text.Text object at 0xd8ed38c>
In [11]: mlab.outline(Out[7])
Out[11]: <enthought.mayavi.modules.outline.Outline object at 0xdd21b6c>
In [12]: mlab.axes(Out[7])
Out[12]: <enthought.mayavi.modules.axes.Axes object at 0xd2e4bcc>
../../_images/decorations1.png

警告

extent:如果我们为绘图对象指定了区域,则默认情况下,mlab.outline'和`mlab.axes不会得到它们。

3.5.2. 互动工作

小费

使用Mayavi创建美观可视化的最快方法可能是交互式调整各种设置。

3.5.2.1. “管道对话框”

单击场景中的“Mayavi”按钮,您可以使用对话框控制对象的属性。

../../_images/pipeline.png
  • Mayavi Scene节点中设置图形的背景
  • 颜色和图例节点中设置颜色图
  • 右键单击节点以添加模块或过滤器

3.5.2.2. 脚本录制按钮

要找出哪些代码可用于编程这些更改,在修改这些属性时单击红色按钮,它将生成相应的代码行。

3.5.3. 切片和切片数据:源,模块和过滤器

3.5.3.1. 例如:检查磁场

假设我们模拟亥姆霍兹线圈产生的磁场。examples/compute_field.py脚本执行此计算并给出一个B数组,即(3 xn),其中第一个轴是字段的方向,By,Bz),第二轴为点的索引号。数组XYZ给出这些数据点的位置。

练习

可视化此字段。您的目标是确保模拟代码是正确的。

../../_images/visualize_field.png

建议

  • 如果计算矢量字段的范数,可以对其应用等值面。
  • 使用mayavi.mlab.quiver3d()可以绘制向量。您还可以使用'masking'选项(在GUI中)使绘图密度略小。

3.5.3.2. 关于数据的不同视图:源和模块

小费

如上所述,可能希望以不同的方式查看相同的数据。

通过将数据加载到数据 t> 中创建Mayavi可视化,然后使用modules在屏幕上显示。

这可以通过查看“管道”视图来看到。通过右键单击管道的节点,可以添加新模块。

测验

为什么不能向mayavi.mlab.quiver3d()创建的向量添加VectorCutPlane

3.5.3.2.1. 不同来源:分散和字段

小费

数据有不同的描述。

  • 规则间隔值的3D块被构造:很容易知道一个测量如何与另一个相邻值相关,以及如何在它们之间连续内插。我们可以调用这样的数据a 字段,借用物理中使用的术语,因为它在空间中连续定义。
  • 以随机顺序在随机位置处测量的一组数据点引起更加困难和不合理的插值问题:数据结构本身不告诉我们什么是数据点的邻居。我们将这样的数据称为scatter
非结构化和未连接数据:a scatter 结构化和连接的数据:a 字段
mlab.points3d mlab.contour3d

可以使用mayavi.mlab.pipeline.scalar_scatter()mayavi.mlab.pipeline.vector_scatter()创建与分散对应的数据源;可以使用mlab.pipeline.scalar_field()mlab.pipeline.vector_field()创建字段数据源。

练习:

  1. 通过使用这些函数之一创建轮廓(例如磁场范数),并通过单击GUI对话框添加右侧模块
  2. 创建正确的源以应用“vector_cut_plane”并再现先前示出的磁场的图片。

注意,困难之一是以正确的形式(数组数,形状)向函数提供数据。这通常是现实生活中的数据。

也可以看看

有关来源在Mayavi手册中有详细说明。

3.5.3.2.2. 转换数据:过滤器

如果创建矢量字段,您可能想要显示其幅度的等值线。但是等值面模块只能应用于标量数据,而不能应用于矢量数据。我们可以使用过滤器ExtractVectorNorm将该标量值添加到向量字段。

过滤器对数据应用转换,并且可以在源和模块之间添加

Excercice

使用GUI,添加ExtractVectorNorm过滤器以显示场强度的等值线。

3.5.3.2.3. mlab.pipeline:脚本化层

mlab脚本编制层为您构建管道。您可以使用mlab.pipeline接口以编程方式重现这些管道:每个步骤都有一个相应的mlab.pipeline函数(只需将步骤名称转换为小写下划线 - 分离:ExtractVectorNorm给出extract_vector_norm)。此函数将其应用于的节点以及可选参数作为参数,并返回新节点。

例如,幅度的等值线被编码为:

mlab.pipeline.iso_surface(mlab.pipeline.extract_vector_norm(field),
contours=[0.1*Bmax, 0.4*Bmax],
opacity=0.5)
../../_images/visualize_field.png

Excercice

使用mlab.pipeline界面,生成一个完整的可视化,具有场幅度的等高线和矢量切面。

(点击图中的解决方案)

3.5.4. 动画数据

小费

要制作电影或交互式应用程序,您可能需要更改给定可视化中呈现的数据。

如果已构建可视化,使用mlab绘图函数或mlab.pipeline函数,我们可以通过将新值分配给mlab_source

x , y , z = np.ogrid[-5:5:100j ,-5:5:100j, -5:5:100j]
scalars = np.sin(x * y * z) / (x * y * z)
iso = mlab.contour3d(scalars, transparent=True, contours=[0.5])
for i in range(1, 20):
scalars = np.sin(i * x * y * z) /(x * y * z)
iso.mlab_source.scalars = scalars

也可以看看

有关详细信息,请参阅Mayavi文档

事件循环

对于与用户的交互(例如用鼠标更改视图),Mayavi需要一些时间来处理这些事件。上面的for循环阻止了这一点。Mayavi文档详细信息一种解决方法

3.5.5. 制作互动对话框

使用Traits库与Mayavi进行交互式对话非常简单(参见专门的章节Traits: building interactive dialogs)。

3.5.5.1. 一个简单的对话框

from traits.api import HasTraits, Instance
from traitsui.api import View, Item, HGroup
from mayavi.core.ui.api import SceneEditor, MlabSceneModel
def curve(n_turns):
"The function creating the x, y, z coordinates needed to plot"
phi = np.linspace(0, 2*np.pi, 2000)
return [np.cos(phi) * (1 + 0.5*np.cos(n_turns*phi)),
np.sin(phi) * (1 + 0.5*np.cos(n_turns*phi)),
0.5*np.sin(n_turns*phi)]
class Visualization(HasTraits):
"The class that contains the dialog"
scene = Instance(MlabSceneModel, ())
def __init__(self):
HasTraits.__init__(self)
x, y, z = curve(n_turns=2)
# Populating our plot
self.plot = self.scene.mlab.plot3d(x, y, z)
# Describe the dialog
view = View(Item('scene', height=300, show_label=False,
editor=SceneEditor()),
HGroup('n_turns'), resizable=True)
# Fire up the dialog
Visualization().configure_traits()

小费

让我们读一下上面的代码(examples/mlab_dialog.py)。

首先,curve函数用于计算要绘制的曲线的坐标。

其次,对话框由从HasTraits继承的对象定义,如同Traits一样。这里的重点是将Mayavi场景添加为特定的Traits属性(Instance)。这对于将其嵌入对话框很重要。此对话框的视图由对象的view属性定义。在这个对象的init中,我们用一个曲线填充3D场景。

最后,configure_traits方法创建对话框并启动事件循环。

也可以看看

在与Mayavi进行对话时需要注意几件事情。请阅读Mayavi文档

3.5.5.2. 使其互动

我们可以将Traits events handlermlab_source组合,以使用对话框修改可视化。

我们将使用户能够改变曲线定义中的n_turns参数。为此,我们需要:

  • 在我们的可视化对象上定义一个n_turns属性,以便它可以出现在对话框中。我们使用Range类型。
  • 以将此属性的线修改重新计算曲线。为此,我们使用on_traits_change装饰器。
../../_images/mlab_interactive_dialog.png
from traits.api import Range, on_trait_change
class Visualization(HasTraits):
n_turns = Range(0, 30, 11)
scene = Instance(MlabSceneModel, ())
def __init__(self):
HasTraits.__init__(self)
x, y, z = curve(self.n_turns)
self.plot = self.scene.mlab.plot3d(x, y, z)
@on_trait_change('n_turns')
def update_plot(self):
x, y, z = curve(self.n_turns)
self.plot.mlab_source.set(x=x, y=y, z=z)
view = View(Item('scene', height=300, show_label=False,
editor=SceneEditor()),
HGroup('n_turns'), resizable=True)
# Fire up the dialog
Visualization().configure_traits()

小费

示例的完整代码:examples/mlab_dialog.py

3.5.6. 将它放在一起

行使

使用磁场模拟的代码,创建一个对话框,可以移动2个线圈:更改其参数。

提示:为维3的向量定义对话框条目

direction = Array(float, value=(0, 0, 1), cols=3, shape=(3,))

您可以查看example_coil_application.py以查看270行代码中完整的线圈设计应用程序。