三流Mayavi操作-Mayav-2.1.2-mesh、triangular_mesh绘制

秉着边学边写边折腾的原则,开始粗糙的工作。真正掌握还是得讲解给别人听。 先给出网课
https://www.icourse163.org/course/BIT-1001871001 Mayavi官方
http://docs.enthought.com/mayavi/mayavi/index.html
(有时候这网站会装死,一般过几个小时就会活过来)

mesh节分成两段,一段是mesh的例子开始,第二段讲解各个参数

1.mesh

http://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#mesh
先引用官方实例,官方的代码又有点小问题,已调整。

import numpy as np
from mayavi.mlab import *
pi = np.pi
cos = np.cos
sin = np.sin

#数据处理
dphi, dtheta = pi / 250.0, pi / 250.0
[phi, theta] = np.mgrid[0:pi + dphi * 1.5:dphi, 0:2 * pi + dtheta * 1.5:dtheta]
m = [4,3,2,3,6,2,6,4]
r = sin(m[0] * phi) ** m[1] + cos(m[2] * phi) ** m[3] + \
    sin(m[4] * theta) ** m[5] + cos(m[6] * theta) ** m[7]
    
# 这里做了座标系变换,需要注意一下
x = r * sin(phi) * cos(theta)		
y = r * cos(phi)
z = r * sin(phi) * sin(theta)

mesh(x, y, z, colormap="bone")
show()

在这里插入图片描述
这段代码很关键的两个地方

1.mgrid 将数据全部离散成网格
2.座标系变换

mgrid做了什么呢
在这里插入图片描述
这样可以把 (0,0)–(4,3)离散成20个网格点,网格的分辨率默认为1,也就是他的间隔
s1,s2的对应位置匹配,就是座标位置s1对应x,s2对应y,s1,s2的维度必然一致。
[phi, theta] = np.mgrid[0:pi + dphi * 1.5:dphi, 0:2 * pi + dtheta * 1.5:dtheta]
案例中的写法,设定了步长,步长有两种设定
在这里插入图片描述
还有一种设定就是划分数量
在这里插入图片描述
s1在纵向被拆成4段,横向拆成3段

文档中,对于.mesh的描述如下:

For mesh defined by triangles rather than regular implicit
connectivity, see the triangular_mesh function.

也就是说,它用三角形网格进行了绘制,现在我们来放大图像的细节。
现在我们修改了它的线框为wireframe

mesh(x, y, z, colormap="bone",representation='wireframe')	#representation的默认值是'surface'

也修改代码的管线部分,在show()之前我们插入以下代码片段,关于管线配置的代码以后会专门讲。

scene = gcf()
surface = scene.children[0].children[0].children[0].children[0]
surface.actor.property.representation = 'wireframe'

也可以直接进行配置
三者效果相同,效果如下
在这里插入图片描述
这里就很明显地看得到绘制的方式,是三角形网格。

有心的朋友注意到这句话,
For simple structures (such as orthogonal grids) prefer the surf
function, as it will create more efficient data structures.
对于简易的常规结构,如正交网格,尽量用surf函数,因为它能生成更高效的数据结构。(原谅我的翻译)
surf用于绘制正交网格
在这里插入图片描述
那么现在有两个问题:
1.如果修改上面的代码将绘制方式mesh换成surf会不会一样的效果?会不会效率更高?
2.这个效率问题,怎么说,(我也不知道别打我,我只能简单猜一下计算量,以后来填坑)

The connectivity between these points is implied by the connectivity on the arrays. From data points to surfaces.

mesh绘制中,点与点之间的连接关系由向量决定,(数据在向量中的位置来确定连接顺序)也就是连通是隐式地表达在array中。这是和triangular_mesh最大的不同。

2.triangular_mesh

triangular_meshmesh更具有一般性,triangular_mesh需要定义连通方式。这是最大的不同
triangular_mesh的讲解分成三部分,第一部分需要说明这种显性连通方式是什么,怎么回事,通过官方的一个实例来说明。第二部分分析它的代码,它是怎么实现这种显式定义的,先分析第一个实例,只展示部分代码。第三部分就是,最后一个实例,文档中给出的triangular_mesh实例,展示全部代码。

For mesh defined by triangles rather than regular implicit connectivity, see the triangular_mesh function.
Knowing the positions of data points is not enough to define a surface, connectivity information is also required. With the functions surf() and mesh(), this connectivity information is implicitly extracted from the shape of the input arrays: neighboring data points in the 2D input arrays are connected, and the data lies on a grid. With the function triangular_mesh(), connectivity is explicitly specified. Quite often, the connectivity is not regular, but is not known in advance either. The data points lie on a surface, and we want to plot the surface implicitly defined. The delaunay2d filter does the required nearest-neighbor matching, and interpolation, as shown in the (Surface from irregular data example).

相对于隐式连通的网格而言,有些是常规绘制(比如上面的surf常为正交网格),mesh是用三角网格进行绘制。对于triangular_mesh的绘制方式而言,仅仅获得数据点的位置是不足以确定一个曲面的,还需要取得它的连通方式。在surf()mesh()的表达中,连通方式隐含在了2D数组中,相邻的数据点之间相互连接成为网格。而在triangular_mesh()中,数据点的连接方式不再是隐式,而是需要明确规定。而且经常都不是常规的连通方式,甚至预先无法确认。这些数据将以一定方式以曲面呈现,并且以我们期望的隐式连通方式显示这个曲面。delaunay2d filter(这个属于管线)确实是需要就近匹配,以及插值,如例子。(后面这两句话我自己都没读懂

下面将举出一个例子,为了防止我翻译的误导,我把它原封不动地摘过来,方便阅读。
例子的网址完整代码(我不写代码,我只是代码的搬运工)

An example which shows how to plot a surface from data acquired irregularly.
Data giving the variation of a parameter ‘z’ as a function of two others (‘x’ and ‘y’) is often plotted as a carpet plot, using a surface to visualize the underlying function. when the data has been acquired on a regular grid for parameters ‘x’ and ‘y’, it can simply be view with the mlab.surf function. However, when there are some missing points, or the data has been acquired at random, the surf function cannot be used.
The difficulty stems from the fact that points positionned in 3D do not define a surface if no connectivity information is given. With the surf function, this information is implicite from the shape of the input arrays.
In this example, randomly-positionned points in the (x, y) plane are embedded in a surface in the z axis. We first visualize the points using mlab.points3d. We then use the delaunay2d filter to extract the mesh by nearest-neighboor matching, and visualize it using the surface module.

以下的例子将展示如何绘制一个由非常规的数据集绘制的面,数据中给定了变量’z’作为另外两个参数’x’,'y’的函数,并将以可视化的三维面展示给定的函数。对于常规网格,给定参数x,y结合mlab.surf函数很容易完成可视化。但是,当网格中出现很多缺失的数据点,或者数据的提取方式是随机的,surf并不能达到目的。
其核心原因在于,如果没有给定连通方式,3维座标点是无法确定一个曲面的。而在surf中,连通方式包含在数组信息里。
在下面的例子中,选取xoy平面,随机分布的座标点将嵌入平面。(这里翻译是有问题的,有能力请阅读上面的英语文献,告知我的翻译问题)
首先,我们使用mlab.points3d呈现这些点,然后我们使用delaunay2d filter通过就近匹配来绘制网格,用面来呈现可视化。
关于delaunay2d filter

上面那个链接中的图像进行一些处理,在原有基础上,我们设置representation='wireframe'可以看到连通方式,一目了然,对于nearest-neighboor matching可以有一个直观的印象。

在这里插入图片描述

再来一张更全面的图像,图像是立体的。

在这里插入图片描述

再来一张充满细节的图像,所谓的nearest-neighboor matching是怎么回事

在这里插入图片描述

可以自行查看更多细节,每一个点的连接了周围所有最近的点,这个连通构成了一张网,即所谓的grid,大家应该玩过太空网,只不过这不是一个规则的网格。这张网一旦填充颜色成为网格更像是具有一定分辨率的多面体,分辨率足够高的时候看起来就像是曲面了,这跟折线图是一致的,将相邻、离散的数据用直线连接起来,只不过这里用的是平面,以直代曲。以平面代曲面。这就是上面英文文献所说,需要显式来明确定义不规则网格数据,irregular data

然后我们再来看看代码里面,它是怎样给出显式数据的连通方式的。

pts = mlab.points3d(x, y, z, z, scale_mode='none', scale_factor=0.2) #绘制点,并把z作为标量值
mesh = mlab.pipeline.delaunay2d(pts)
surf = mlab.pipeline.surface(mesh)

第1行代码绘制了点 ,2.3行利用了pipeline配置了管线,对于delaunay2d()方法的解释如下。此时定义了网格的连通方式,然后在第三行代码,对这个网格进行了可视化,并且可以观察到管线中的filters是有两项的。当注释掉2.3行代码的时候,只能得到数据点,仅注释第三行,可以通过配置管线来得到这个图像,也就是说,网格的信息已经被delaunay2d()方法导入,仅注释第二行, 修改为
surf = mlab.pipeline.surface(pts)
会发现SurfaceGlyph置于同一个filtersScalarScatter之下,而对GlyphActorvisibility选项去除掉,将其可视化的点集隐藏,会发现Surface中是没有数据的,是空的。如此一对比,结论就是delaunay2d()处理了pts的空间点集数据,给定了连接方式,而surface()方法添加了filter下面的Surface可视化模块,把上面定义连通mesh呈现出来。

delaunay2d:Perform a 2D Delaunay triangulation for the given data.
delaunay3d:Perform a 3D Delaunay triangulation for the given data.

将给定的数据进行Delaunay狄式二维三角化处理.另一个是三维。
我们来对比一下。

在这里插入图片描述

很显然delaunay2ddelaunay3d有不同的连通方式,这就是为什么要显式来定义,必须明确的指出连通方式。进一步观察delaunay3d的细节。

在这里插入图片描述

观察到连接方式已经不是就近连接了,如果再仔细一点,delaunay2d的连接方式是忽略z的座标仅仅连接的是2维空间里相邻的点,delaunay3d是考虑的三维空间里相邻的点,连接的线由此构成网格,这两者难说谁更好,在这里例子中,2d连接方式更优,不容易遮挡。不过挺有意思的,如果是图论中的一些问题,很有启发性。

上面仅仅说明一下连通方式,下面一个例子是triangular_mesh()的绘制,终于进入主题了,敲黑板!
代码这里,不过官方代码有点小瑕疵
这里为了节约篇幅降低了可读性,调整之后的代码如下

import numpy as np
from mayavi.mlab import *
n = 8
t = np.linspace(-np.pi, np.pi, n);z = np.exp(1j * t)
x = z.real.copy();y = z.imag.copy();z = np.zeros_like(x)
triangles = [(0, i, i + 1) for i in range(1, n)]
x = np.r_[0, x];y = np.r_[0, y];z = np.r_[1, z];t = np.r_[0, t]
triangular_mesh(x, y, z, triangles, scalars=t)	#这里是关键点
show()

这段代码最关键的地方就是triangular_mesh(x, y, z, triangles, scalars=t)
我们来看看它的语法 triangular_mesh(x, y, z, triangles ...),它比mesh额外要求了一个triangles参数用来描述连通方式,我们继续看下去,对于函数的说明如下

x, y, z are arrays giving the positions of the vertices of the surface. triangles is a list of triplets (or an array) list the vertices in each triangle. Vertices are indexes by their appearance number in the position arrays.
For simple structures (such as rectangular grids) prefer the surf or mesh functions, as they will create more efficient data structures.

给定的x,y,z必须是array类型,一组x,y,z代表了平面中的一个点. triangles参数为一个3维triplet或者array类型,列举所要绘制的三角面的三个点。列举规则是,列出他们在x,y,z列表中,他们的index索引。

简单说一下,比如
x=[1,5,7,4,2];y=[85,74,41,2,65];z=[74,1,45,8,0]
连通的3个点分别是1,4,5,对于索引而言是0,3,4
triplet=(0,3,4)
(1,85,74),(4,2,8),(2,65,0)三个点将会连接成一个面

我们可以通过断点调试的方式来获得例子中间量
t被离散成8段,t=[-3.14159265 -2.24399475 -1.34639685 -0.44879895 0.44879895 1.34639685 2.24399475 3.14159265]
此后各种操作之后,最关键的我们的triangles
这里给出x方便对照,x=[0.00,-1.00,-0.62,0.22,0.90,0.90,0.22,-0.62,-1.00]
triangles=[(0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 5), (0, 5, 6), (0, 6, 7), (0, 7, 8)]
如(0, 1, 2)这个元组,分别取了xyz的索引(0,0,0)(1,1,1),(2,2,2)
对应:[0.0, 0.0, 1.0], [-1.0, -1.22e-16, 0.0], [-0.62, -0.78, 0.0],三个点构成了一个面
我们可以用point3d()将这三个点描出来,如下图:
在这里插入图片描述
插入以下代码片段即可,不再说明了

xp = [x[0],x[1],x[2]]
yp = [y[0],y[1],y[2]]
zp = [z[0],z[1],z[2]]
points3d(xp,yp,zp,scale_factor=0.1)

总结以上,xyz里面存放座标点,由第4个参数来传递连通方式,连接成为三角形的面。

最后提醒一下,scalars=t这里,t是一个列表传递给了scalars参数,代表每个点的标量值,本例中t的数目为9,底面8个,顶点一个,如果不设置它,将会以z的值作为默认标量进行映射

3 .mesh和triangular_mesh的参数

另外mesh有很多省略参数,现在一一说明
9个通用参数,见这里

extent

[xmin, xmax, ymin, ymax, zmin, zmax] Default is the x, y, z arrays extent. Use this to change the extent of the object created.
这个原本以为只是过滤一些值,但是不是,它修改了原数据。
原图
在这里插入图片描述

对代码进行一些修改如下:
extent =[-1,1,-0.9,0.8,-2,2]
mesh(x, y, z, representation='wireframe',colormap='Wistia',color=(1,1,0),extent=sph)
outline() #绘制外框
xlabel('x') #绘制座标轴
ylabel('y')
.
为了方便对比。增设xlabelylabeloutline做一个外框
增设extent = [-1,1,-0.9,0.8,-2,2]之后
在这里插入图片描述
然后我吃了一惊,extent应该是在某个范围里面进行了整体放缩。瘦身大法好啊

figure

Figure to populate.
这个还没用过。。。。。。。。

line_width

The width of the lines, if any used. Must be a float. Default: 2.0
线宽,处于Actor下,默认值是2.0,我们来试试0.1线宽效果
mesh(x, y, z, representation='wireframe',colormap='Wistia',line_width = 0.1)
在这里插入图片描述
是不是很se.qing,sexy!敲漂亮!蝉翼般的效果。

mode

the mode of the glyphs. Must be ‘2darrow’ or ‘2dcircle’ or ‘2dcross’ or ‘2ddash’ or ‘2ddiamond’ or ‘2dhooked_arrow’ or ‘2dsquare’ or ‘2dthick_arrow’ or ‘2dthick_cross’ or ‘2dtriangle’ or ‘2dvertex’ or ‘arrow’ or ‘axes’ or ‘cone’ or ‘cube’ or ‘cylinder’ or ‘point’ or ‘sphere’. Default: sphere
符号模式,默认值sphere
这个图不起效果,这是个问题。

representation

the representation type used for the surface. Must be ‘surface’ or ‘wireframe’ or ‘points’ or ‘mesh’ or ‘fancymesh’. Default: surface
这个是设置绘制的样式,有几种形态, ‘surface’ 、 ‘wireframe’ 、 ‘points’ 、 ‘mesh’、 ‘fancymesh’.
最常用的就是surfacewireframe,比较特殊的就是fancymesh,这个我尝试过一下,它改变了管线,同时带来了Glyph,使mask_points,mode,同时起效果了。
mesh(x,y,z,representation='fancymesh',colormap='Wistia',line_width=2,mask_points=100,mode='2ddiamond', name = '修改的是这个位置')
在这里插入图片描述
这图很多地方也长了点’2ddiamond’,二维钻石??Emmm
另外一个representation='mesh'参数的效果是这样的:
在这里插入图片描述
两者的管线配置是不一样的,但并非是mask_pointsmode触发了Glyph的建立,两者同时缺省的时候,Glyph还是建立了,fancymesh反而让它们有了效果。
另外,不推荐用这两个,很烧显卡,跑起来很卡。

resolution

The resolution of the glyph created. For spheres, for instance, this is the number of divisions along theta and phi. Must be an integer (int or long). Default: 8
这个参数是用来设置Glyph分辨率的,后面说points3d会讲到。比如球体的细分数,默认值是8.
引用一个例子
http://docs.enthought.com/mayavi/mayavi/auto/example_flight_graph.html (链接有时候会死)

sphere = mlab.points3d(0, 0, 0, scale_mode='none',
                                scale_factor=2,
                                color=(0.67, 0.77, 0.93),
                                resolution=50,	#注意这个位置
                                opacity=0.7,
                                name='Earth') 

截取上面这段代码,这段代码是很有意思的,我大致解释一下,points3d它是在一个点上面画大洲的线条。只不过这个点很有意思,它有大小的,就是scale_factor=2,默认值是0.05,它放大了40倍。
我贴两个图,自行感受一下resolution
左边:resolution=5
右边:resolution=50
在这里插入图片描述
右边的像一个球了,然而并不是,只是近似,它仍然是个多面体

顺带一提,这不是正n面体,正n面体,n只能取得4,6,8,12,20.据说resolution取默认值8的时候,会有82个顶点,所谓细分数,看翻译应该能获知一二,如果要计算,可能会用一下拓扑V+F-E=2那个公式,详细不展开了。
scale_factor
scale factor of the glyphs used to represent the vertices, in fancy_mesh mode. Must be a float. Default: 0.05
这个参数在上面那个例子中用到了,scale_factor=2将点进行了放大,这个参数就是放大系数,我们尝试修改一下看看效果。
左图:scale_factor=3
右图:scale_factor=2
在这里插入图片描述

tube_radius

radius of the tubes used to represent the lines, in mesh mode. If None, simple lines are used.
继续借用上面的例子,原来的例子中有一项设置,代码太长,不贴了,只说明这个参数的效果
mlab.plot3d(x, y, z, color=(1, 1, 1),opacity=0.2,tube_radius=None)#在最后几行
这里栗子中使用的值是tube_radius=None,后者去掉了这个参数
这个设置与否的效果完全不同,一是图像不同,本身性质也不一样。
设置之后,放大若干倍,回归线和赤道的线不会被放大,它的本质是线,没有粗细,而不设置,他们的大小会随着放大而放大,它是管,是有粗细概念的!!
所以当我们要得到的是线的时候,需要增设tube_radius的参数。
在这里插入图片描述
而在管线的配置中,None的效果使得StripperTube两个层级消失了。
在这里插入图片描述

注意一个细节,文档中提到绘制模式用的是mesh,设置representation='wireframe'之后可以观察到三角形网格
在这里插入图片描述

tube_sides

number of sides of the tubes used to represent the lines. Must be an integer (int or long). Default: 6
设置构成tube的线条数目,默认为6,有点像resolution,分辨率。
修改第二条Tubetube_sides也就是赤道那一条的值为25,设置为wireframe可观察到如下:
在这里插入图片描述
赤道的这条管子分辨率很高25,对比回归线的6。

scale_mode

the scaling mode for the glyphs (‘vector’, ‘scalar’, or ‘none’).
http://docs.enthought.com/mayavi/mayavi/auto/example_surface_from_irregular_data.html
然后用这个例子来进行一点简单的说明,(为防止打不开,我还是贴一下代码部分,去掉注释减小行数)
这段代码不必太纠结,这里面涉及了图像控制函数figure,管线pipeline后续都会专门写,此处只需要留意scale_mode的效果即可。

import numpy as np
    np.random.seed(12345)
    x = 4 * (np.random.random(500) - 0.5);y = 4 * (np.random.random(500) - 0.5)
    def f(x, y):
        return np.exp(-(x ** 2 + y ** 2))
    z = f(x, y)
    from mayavi import mlab
    mlab.figure(1, fgcolor=(0, 0, 0), bgcolor=(1, 1, 1))
    pts = mlab.points3d(x, y, z, z, scale_mode='scalar', scale_factor=0.2)		#scale_mode在这个位置
    mesh = mlab.pipeline.delaunay2d(pts)
    surf = mlab.pipeline.surface(mesh)
    mlab.view(47, 57, 8.2, (0.1, 0.15, 0.14))
    mlab.show() 

此时执行效果如下:
在这里插入图片描述
观察管线里面的Scale mode配置,对应的是scale_by_scalar
以下是三个参数的对比
管线里面的对应关系
data_scaling_off——none 显示颗粒
scale_by_scalar——scalar 按照标量值的大小显示颗粒
scale_by_vector——vector 按照矢量值的大小显示颗粒
在这里插入图片描述

调过管线的朋友会发现,其实里面不止三个选项
最后一个scale_by_vector_components似乎没有效果,
查询了一下文档,可自行阅读
28 Jun, 2009 (PR):
BUG: Mlab’s barchart uses the scale_by_vector_components which was not exposed by the glyph component leading to update problems reported by Christian Vollmer. This is now fixed along with a simple test case. There are deeper problems with barchart that do need attention though - if a user changes the data inplace and calls the mlab_source.update() nothing updates correctly since the data is really copied over to the vector components. This can be fixed with a callback and will be done later. [23980]

mask_points

If supplied, only one out of ‘mask_points’ data point is displayed. This option is useful to reduce the number of points displayed on large datasets Must be an integer (int or long) or None.
这个用于降采样,只接受整形、长整型,或者缺省,每N个点取一个,可以增设选取原则为随机。
还是用这个图,对这行代码追加一个mask_points参数得到下面的图。
pts = mlab.points3d(x, y, z, z, scale_mode='scalar', scale_factor=0.2,mask_points=5)
在这里插入图片描述
察看管线配置里面发生的变化
在这里插入图片描述
mask_points=5为例,增设之后的变化就是Mask input points被自动勾选了,On ratio被设置好了,意为每N个点取一个,其次需要注意的是蓝色框Random mode选项也被自动勾选了,选取的点是随机的。

scalars

optional scalar data.
为座标点设置标量,座标点的长度和scalars被传递的列表长度应该相同。这个值不设置,默认采用z的值作为标量值。

mask

boolean mask array to suppress some data points. Note: this works based on colormapping of scalars and will not work if you specify a solid color using the color keyword.
这个没查到相关实例,只有surfmesh含有这个参数。

如果谁知道这个有什么效果记得告诉我一下,还有上面的scalars。(已解决)

这篇小文快结束了,顺带说一下手动设置几个小细节让图完整一点

1.一般会添加一个outline()放在最外面和IsoSurface处于一个层级,做个外框,方便看值域范围
2.会添加Legend在右边,并且对这个bar设置一定的透明度、title的大小的样式以及标量值的步长。
3.在图像中再添加xlabelylabelzlabel进去把值也标定
在这里插入图片描述
.colorbar.scalarbar可以实现相同的效果。

后期会讲设置一个可移动的平面来获得各个面上的值,作为辅助观察手段。哦对,顺带一说,那个bar是可以移动的。
2.2会完整地讲管线里面的所有设置


今天10.07,明天要上课,有空会继续添加例子。
.
.
.
.
.

填坑区:

1.多图显示可以尝试一下,分屏还是一屏多图,

分屏的话不容易,一屏多图可以实现,配置多个数据源即可。

2.meshsurf的效率怎么解释?
3.reset_zoom()上面举例的时候的一个报错问题
4.maskscalars的效果不知

scalars参数已补充

更新(18.10.6已更完)
2018.09-30.——写到reset_zoom停下
2018.10-02.——补充参数reset_zoomtransparent的例子
———————文末的bar小技巧
2018.10.06. ——补充参数scale_factorresolutionmask_pointsscale_modetube_radiustube_sides的例子
2018.10.07.——大幅度调整,去掉了color,colormap,line_width,name,opacity,reset_zoom,transparent,vmax,vmin,共9个通用参数部分。通用参数独立成一篇,增加triangular_mesh部分。
2018.10.08.——triangular_mesh未更完,缺少triangular_mesh的文档翻译和例子的说明、需要再补充实例、必要需要补充网格知识点插入1.0-2.0直接的VTK数据集解说
2018.10.09.——triangular_mesh未更完,补充了显式连通的实例,做部分翻译,补充triangular_mesh的实例,对比delaunay2ddelaunay3d
2018.10.09.——triangular_mesh更完,补充翻译,补充scalars参数。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章