WxGL是一个基于PyOpenGL的三维数据可视化库,以wx为显示后端,提供Matplotlib风格的交互式应用模式,同时,也可以和wxPython无缝结合,在wx的窗体上绘制三维模型。
WxGL遵循MIT开源软件许可协议,任何人都可以使用、复制和修改本软件,甚至出版发行、再授权以及贩售本软件。唯一的限制是,必须附有MIT授权协议。WxGL的源码和本文的示例代码、资源,都可以从https://github.com/xufive/wxgl下载。
从V0.6.2开始,WxGL新增了交互式绘图子模块wxplot,提供类似Matplotlib风格的2D/3D绘图函数。如果熟悉NumPy和Matplotlib的话,只需要几分钟时间就可以学会使用WxGL的交互式绘图。
WxGL提供了一套简洁易用、对用户友好的API,将OpenGL的复杂概念全部封装起来,使得用户可以专注于数据的处理,而无需将更多精力用在3D显示方面。可以说,WxGL是为实现数据快速可视化而诞生的。下面这个例子可以告诉你,WxGL究竟有多简洁。
>>> import numpy as np
>>> import wxgl.wxplot as plt
>>> vs = np.array([
[1,-1,1], [1,-1,-1], [1,1,-1], [1,1,1],
[-1,1,1], [-1,1,-1], [-1,-1,-1], [-1,-1,1],
[-1,-1,1], [-1,-1,-1], [1,-1,-1], [1,-1,1],
[1,1,1], [1,1,-1], [-1,1,-1], [-1,1,1]
])
>>> plt.surface(vs, texture=r'example\res\girl.jpg', alpha=False)
>>> plt.show(rotation='h+')
前两行代码导入NumPy和WxGL模块,第3行构造数据,第4行绘制,第5行显示并增加旋转效果。只要5行代码,就可以实现下面的效果。
和其他的Python模块一样,WxGL模块也使用pip命令安装。
pip install wxgl
WxGL依赖以下模块,如果当前运行环境没有安装这些模块,安装程序将会自动安装它们。如果安装过程出现问题,或者安装完成后无法正常使用,请尝试手动安装WxGL的依赖模块。
下面例子中用到的绘图函数,在本文第3部分“交互式绘图函数”中均有详细的使用说明。
>>> import numpy as np
>>> import wxgl.wxplot as plt
>>> x = np.linspace(0, 2*np.pi, 361)
>>> y = np.sin(x) * 3
>>> plt.plot(x, y)
>>> plt.show()
上面这几行代码,画出了一条正弦曲线。如果忽略模块名的话,这些代码和Matplotlib是完全一样的。除去导入模块和数据准备,真正的绘图语句只有最后两行。执行最后一句show()命令后,将弹出GUI窗口,同时程序将阻塞,直至关闭GUI窗口。
对于2D数据来说,使用2D模式绘制,看起来会更习惯一点。
>>> theta = np.linspace(0, 2*np.pi, 361)
>>> x = 3 * np.cos(theta)
>>> y = 3 * np.sin(theta)
>>> fig = plt.figure(mode='2D')
>>> plt.plot(x, y)
>>> plt.show()
这段代码,首先准备绘制圆的数据,然后使用wxplot.figure()生成画布,同时指定使用2D绘图模式。
WxGL支持在一张画布上画多张子图,创建子图的方式也非常类似Matplotlib。下面使用wxplot.sphere()函数绘制两个球体。
>>> plt.subplot(121) # 一行两列的第一个位置
>>> plt.sphere((0,0,0), 3, 'green')
>>> plt.subplot(122) # 一行两列的第二个位置
>>> plt.sphere((0,0,0), 3, '#00FFFF', mode='FCBC')
>>> plt.show()
>>> ax1 = plt.subplot(121) # 一行两列的第一个位置
>>> ax1.sphere((0,0,0), 3, 'green')
>>> ax2 = plt.subplot(122) # 一行两列的第二个位置
>>> ax2.sphere((0,0,0), 3, '#00FFFF', mode='FCBC')
>>> plt.show()
>>> fig = plt.figure()
>>> ax1 = fig.add_axes(121) # 一行两列的第一个位置
>>> ax1.sphere((0,0,0), 3, 'green')
>>> ax2 = fig.add_axes(122) # 一行两列的第二个位置
>>> ax2.sphere((0,0,0), 3, '#00FFFF', mode='FCBC')
>>> plt.show()
上面三种方式创建的子图,绘制效果是完全一致的。图中的网格线和标注,是通过点击工具栏上的工具按钮生成的,再次点击则可以隐藏。工具栏按钮从左至右,分别是:恢复初始姿态、显示/隐藏坐标轴、显示/隐藏网格刻度、设置配色方案、保存为文件。
除了可以接受3位数字的参数外,subplot()和add_axes()还可以接受4元组参数,用来指定子图左下角在画布上的位置,以及子图的宽度和高度。
和Matplotlib类似,wxplot也提供了title()和text()两个函数来绘制标题和文本。除了文本内容,这两个函数还可以接受文本大小、位置、颜色、字体、对齐方式等若干参数。
>>> plt.cube((0,0,0), 3, 'cyan') # 绘制六面体,cyan是颜色,十六进制表示为#00FFFF
>>> plt.sphere((0,0,0), 1.5, 'orange') # 绘制球
>>> plt.cylinder((0,0,-2), (0,0,2), 0.5, 'green') # 绘制圆柱
>>> plt.cone((0,-2,0), (0,2,0), 0.5, 'purple') # 绘制圆锥,purple是颜色,十六进制表示为#F020F0
>>> plt.title('六面体、圆锥、圆柱和球的组合') # 绘制标题
>>> plt.text('这是锥尖', size=40, pos=(0,2,0), align='left') # 绘制文本
>>> plt.show()
绘制六面体、圆锥、圆柱和球的函数将在本文的第3部分给出详细的API说明。
只需要提供值域范围、颜色映射表名字,wxplot.colorbar()就可以轻松画出Colorbar,默认位置在画布或子图的右侧。使用参数loc可以指定Colorbar的位置。
>>> x, y = np.mgrid[-1:1:20j,-1:1:20j]
>>> z = x*x + y*y
>>> plt.mesh(x, y, z, mode='FLBL', cmap='hsv') # 其实,mesh()函数默认使用的颜色映射表就是hsv
>>> plt.colorbar((z.min(), z.max()), 'hsv') # colorbar()的颜色映射表要和要和绘图函数一致
>>> plt.show()
这段代码使用wxplot.mesh()函数画出了曲面 z = x 2 + y 2 z = x^2 + y^2 z=x2+y2的样子(x和y取值均在在[-1,1]之间)。mesh()函数默认使用的颜色映射表是hsv,因此,colorbar的颜色映射表也使用相同的名字
表示多个颜色时,WxGL限定使用NumPy数组,也就是numpy.ndarray类型,颜色数组的最后一个维度表示颜色通道,可以是RGB模式,也可以是RGBA模式。各个颜色通道的值域范围在[0,1]之间。
表示单个颜色时,WxGL支持列表、元组或数组的表示形式(值域范围限定在[0,1]之间),也支持类似"#FF00FF"的十六进制表示法。此外,WxGL还提供了若干预定义的颜色,使用plt.fig.cm.colors可以查看所有的预定义颜色。
>>> plt.fig.cm.colors
{
'red': '#FF0000', 'red_dark': '#C00000', 'green': '#00C000', 'green_dark': '#008000', 'blue': '#0000FF', 'blue_dark': '#0000C0', 'yellow': '#FFFF00', 'orange': '#FFA500', 'purple': '#F020F0', 'purple_dark': '#C000C0', 'cyan': '#00FFFF', 'cyan_dark': '#00C0C0', 'gray': '#C0C0C0', 'dark': '#808080', 'black': '#000000', 'white': '#FFFFFF'}
WxGL预定了若干颜色映射方案,使用plt.fig.cm.cms.keys()可以查看所有的预定义颜色映射表。
dict_keys([
'autumn', 'brg', 'CMRmap', 'cool', 'cubehelix',
'gist_earth', 'gist_rainbow', 'gist_stern',
'gnuplot', 'gray', 'gray_r', 'hsv', 'jet',
'ocean', 'rainbow', 'spring', 'summer',
'terrain', 'winter', 'Wistia', 'wind'
])
wxplot函数自带完备的文档说明,只需要使用__doc__查看即可。
>>> print(plt.figure.__doc__)
新建画布
Useage: figure(*args, **kwds)
----------------------------------------------------
size - 画布分辨率,默认800x600
kwds - 关键字参数
head - 定义方向:'x+'|'y+'|'z+'
zoom - 视口缩放因子
mode - 2D/3D模式
elevation - 仰角
azimuth - 方位角
style - 配色方案,'black'|'white'|'gray'|'blue'
>>> print(plt.savefig.__doc__)
保存画布为文件
Useage: savefig(fn, alpha=False)
----------------------------------------------------
fn - 文件名
alpha - 透明通道开关
>>> print(plt.savefig.__doc__)
显示画布
Useage: show(rotation=None, **kwds)
----------------------------------------------------
rotation - 旋转模式
None - 无旋转
'h+' - 水平顺时针旋转(默认方式)
'h-' - 水平逆时针旋转
'v+' - 垂直前翻旋转
'v-' - 垂直后翻旋转
kwds - 关键字参数
elevation - 初始仰角,以度(°)为单位,默认值为0
azimuth - 初始方位角以度(°)为单位,默认值为0
step - 帧增量,以度(°)为单位,默认值为5
interval - 帧间隔,以ms为单位,默认值为20
>>> print(plt.cmap.__doc__)
数值颜色映射
Useage: cmap(data, cm, **kwds)
----------------------------------------------------
data - 数据
cm - 颜色映射表名
kwds - 关键字参数
invalid - 无效数据的标识
invalid_c - 无效数据的颜色
datamax - 数据最大值,默认为None
datamin - 数据最小值,默认为None
alpha - 透明度,None表示返回RGB格式
>>> print(plt.subplot.__doc__)
添加子图
Useage: subplot(pos, padding=(20,20,20,20))
----------------------------------------------------
pos - 子图在画布上的位置和大小
三位数字 - 指定分割画布的行数、列数和子图序号。例如,223表示两行两列的第3个位置
四元组 - 以画布左下角为原点,宽度和高度都是1。四元组分别表示子图左下角在画布上的水平、垂直位置和宽度、高度
padding - 四元组,上、右、下、左四个方向距离边缘的留白像素
>>> print(plt.plot.__doc__)
绘制点和线
Useage: plot(xs, ys, zs=None, color=None, size=0.0, width=1.0, style='solid', cmap='hsv', caxis='z')
----------------------------------------------------
xs/ys/zs - 顶点的x/y/z坐标集,元组、列表或一维数组类型,长度相等。若zs为None,则自动补为全0的数组
color - 全部或每一个顶点的颜色。None表示使用cmap参数映射颜色
size - 顶点的大小,整型或浮点型。若为0,则表示不绘制点,只绘制线
width - 线宽,0.0~10.0之间的浮点数。若为0,则表示不绘制线,只绘制点
style - 线型
'solid' - 实线
'dashed' - 虚线
'dotted' - 点线
'dash-dot' - 虚点线
cmap - 颜色映射表,color为None时有效
caxis - 用于颜色映射的坐标轴数据,2D模式下自动转为'y'
>>> print(plt.scatter.__doc__)
绘制散点图
Useage: scatter(vs, color=None, size=1.0, cmap='hsv', caxis='z')
----------------------------------------------------
vs - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
size - 顶点的大小,整型或浮点型
cmap - 颜色映射表,color为None时有效。使用vs的z坐标映射颜色
caxis - 用于颜色映射的坐标轴数据,2D模式下自动转为'y'
>>> print(plt.mesh.__doc__)
绘制mesh
Useage: mesh(xs, ys, zs, color=None, mode='FCBC', cmap='hsv', caxis='z', light=None)
----------------------------------------------------
xs/ys/zs - 顶点的x/y/z坐标集,二维数组
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
cmap - 颜色映射表,color为None时有效。使用zs映射颜色
caxis - 用于颜色映射的坐标轴数据,2D模式下自动转为'y'
light - 材质灯光颜色,None表示关闭材质灯光
>>> print(plt.surface.__doc__)
绘制surface
Useage: surface(vs, color=None, method='Q', mode='FCBC', texture=None, alpha=True, light=None)
----------------------------------------------------
vs - 顶点坐标集,二维数组类型,shape=(n,3)
color - 顶点颜色或颜色集,可以混合使用纹理。None表示仅使用纹理
method - 绘制方法
'Q' - 四边形
0--3 4--7
| | | |
1--2 5--6
'T' - 三角形
0--2 3--5
\/ \/
1 4
'Q+' - 边靠边的连续四边形
0--2--4
| | |
1--3--5
'T+' - 边靠边的连续三角形
0--2--4
\/_\/_\
1 3 5
'F' - 扇形
'P' - 多边形
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
texture - 用于纹理的图像文件,仅当method为Q时有效
alpha - 纹理是否使用透明通道,仅当texture存在时有效
light - 材质灯光颜色,None表示关闭材质灯光
>>> print(plt.pipe.__doc__)
绘制圆管
Useage: pipe(vs, radius, color=None, slices=36, mode='FCBC', cmap='hsv', caxis='z')
----------------------------------------------------
vs - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
radius - 圆管半径,浮点型
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
slices - 圆管面分片数(数值越大越精细)
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
cmap - 颜色映射表,color为None时有效。使用vs的z坐标映射颜色
caxis - 用于颜色映射的坐标轴数据,2D模式下自动转为'y'
>>> print(plt.sphere.__doc__)
绘制球体
Useage: sphere(center, radius, color, slices=60, mode='FLBL')
----------------------------------------------------
center - 球心坐标,元组、列表或数组
radius - 半径,浮点型
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
slices - 球面分片数(数值越大越精细)
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
>>> print(plt.cube.__doc__)
绘制六面体
Useage: cube(center, side, color, mode='FLBL')
----------------------------------------------------
center - 中心坐标,元组、列表或数组
side - 棱长,整型、浮点型,或长度为3的元组、列表数组
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
>>> print(plt.cylinder.__doc__)
绘制圆柱体
Useage: cylinder(v_top, v_bottom, radius, color, slices=60, mode='FCBC')
----------------------------------------------------
v_top - 圆柱上端面的圆心坐标,元组、列表或numpy数组
v_bottom - 圆柱下端面的圆心坐标,元组、列表或numpy数组
radius - 半径,浮点型
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
slices - 圆柱面分片数(数值越大越精细)
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
>>> print(plt.cone.__doc__)
绘制圆锥体
Useage: cone(center, spire, radius, color, slices=60, mode='FCBC')
----------------------------------------------------
center - 锥底圆心坐标,元组、列表或数组
spire - 锥尖坐标,元组、列表或数组
radius - 半径,浮点型
color - 顶点颜色或颜色集,None表示使用cmap参数映射颜色
slices - 锥面分片数(数值越大越精细)
mode - 显示模式
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
>>> print(plt.capsule.__doc__)
绘制囊(三维等值面)
Useage: capsule(data, threshold, color, r_x=None, r_y=None, r_z=None, mode='FCBC', **kwds)
----------------------------------------------------
data - 数据集,numpy.ndarray类型,shape=(layers,rows,cols)
threshold - 阈值,浮点型
color - 表面颜色
r_x - x的动态范围,元组
r_y - y的动态范围,元组
r_z - z的动态范围,元组
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
>>> print(plt.flow.__doc__)
绘制流体
Useage: flow(ps, us, vs, ws, **kwds)
----------------------------------------------------
ps - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
us - 顶点u分量集,numpy.ndarray类型,shape=(n,)
vs - 顶点v分量集,numpy.ndarray类型,shape=(n,)
ws - 顶点w分量集,numpy.ndarray类型,shape=(n,)
kwds - 关键字参数
color - 轨迹线颜色,None表示使用速度映射颜色
actor - 顶点模型类型,'point'|'line'两个选项
size - point大小
width - line宽度
length - 轨迹线长度,以速度矢量的模为单位
duty - 顶点line模型长度与轨迹线长度之比(占空比),建议值为0.4
frames - 总帧数
interval - 帧间隔,以ms为单位
threshold - 高通阈值,滤除速度小于阈值的数据点
name - 模型名
>>> print(plt.title.__doc__)
绘制标题
Useage: title(text, size=96, color=None, pos=(0,0,0), **kwds)
----------------------------------------------------
text - 文本字符串
size - 文字大小,整形
color - 文本颜色,预定义的颜色,或长度为3的列表或元组
pos - 文本位置,list或numpy.ndarray类型,shape=(3,)
kwds - 关键字参数
align - left/right/center分别表示左对齐、右对齐、居中(默认)
valign - top/bottom/middle分别表示上对齐、下对齐、垂直居中(默认)
family - (系统支持的)字体
weight - light/bold/normal分别表示字体的轻、重、正常(默认)
>>> print(plt.text.__doc__)
绘制文本
Useage: text(text, size=64, color=None, pos=(0,0,0), **kwds)
----------------------------------------------------
text - 文本字符串
size - 文字大小,整形
color - 文本颜色,预定义的颜色,或长度为3的列表或元组
pos - 文本位置,list或numpy.ndarray类型,shape=(3,)
kwds - 关键字参数
align - left/right/center分别表示左对齐、右对齐、居中(默认)
valign - top/bottom/middle分别表示上对齐、下对齐、垂直居中(默认)
family - (系统支持的)字体
weight - light/bold/normal分别表示字体的轻、重、正常(默认)
>>> print(plt.colorbar.__doc__)
绘制colorbar
Useage: colorbar(drange, cmap, loc, **kwds)
----------------------------------------------------
drange - 值域范围,tuple类型
cmap - 调色板名称
loc - 位置,top|bottom|left|right
kwds - 关键字参数
length - ColorBar所在视区的长边长度,默认短边长度为1
subject - 标题
subject_size - 标题字号
label_size - 标注字号
label_format - 标注格式化所用lambda函数
tick_line - 刻度线长度
endpoint - 刻度是否包含值域范围的两个端点值
name - 模型名
inside - 是否数据动态范围
visible - 是否显示
>>> print(plt.ticks.__doc__)
绘制网格和刻度
Useage: subplot(**kwds)
----------------------------------------------------
kwds - 关键字参数
segment_min - 标注最少分段数量
segment_max - 标注最多分段数量
label_2D3D - 标注试用2D或3D文字
label_size - 标注字号
xlabel_format - x轴标注格式化所用lambda函数
ylabel_format - y轴标注格式化所用lambda函数
zlabel_format - z轴标注格式化所用lambda函数
虽然前面给出了很多几何体的绘制函数,但三维绘图绝不只是绘制规则的几何体,而是要表现纷繁复杂的现实的和虚拟的空间。在三维绘图函数中,最重要、最常用、同时也是最难以理解的是surface()函数和mesh()函数。
OpenGL总共有10种图元绘制方法,如下表所示。其中的前4种方式用于绘制点和线,后6种方式用于绘制面。surface()函数整合了后面的6种图元绘制方法,使用method参数可以指定绘制方法(详见3.9节)。
参数 | 说明 |
---|---|
GL_POINTS | 绘制一个或多个顶点 |
GL_LINES | 绘制线段 |
GL_LINE_STRIP | 绘制连续线段 |
GL_LINE_LOOP | 绘制闭合的线段 |
GL_POLYGON | 绘制多边形 |
GL_TRIANGLES | 绘制一个或多个三角形 |
GL_TRIANGLE_STRIP | 绘制连续三角形 |
GL_TRIANGLE_FAN | 绘制多个三角形组成的扇形 |
GL_QUADS | 绘制一个或多个四边形 |
GL_QUAD_STRIP | 绘制连续四边形 |
使用原生的OpenGL绘图时,通常需要先准好一组顶点,然后指定使用哪一种方式绘制,这里边暗含着顶点顺序的重要性。以画扇面为例,需要在15°到165°之间生成弧线上的一组点。假设扇面在 y o z yoz yoz平面上,这些点的x坐标则上下交替。将扇面的圆心点(0,0,0)加到刚才生成的一组点的起始位置,也就是第1个顶点。
>>> theta = np.linspace(np.pi/12, 11*np.pi/12, 21) # 在15°到165°之间生成21个点
>>> y = np.cos(theta) * 10 # 弧线上点的y坐标
>>> z = np.sin(theta) * 10 # 弧线上点的y坐标
>>> x = np.array([i%2-0.5 for i in range(21)]) # 弧线上点的x坐标,上下交替
>>> vs = np.stack((x,y,z), axis=1) # 组合成顶点坐标,此时vs的shape是(21,3)
>>> vs = np.vstack((np.array([0,0,0]), vs)) # 将原点加到vs的首位,此时vs的shape是(22,3)
绘制扇面,就是绘制连续三角形,第1个三角形由顶点1、顶点2、顶点3组成,第2个三角形由顶点1、顶点3、顶点4组成,……,以此类推。
>>> cs = plt.cmap(vs[:,0], 'wind') # 将x的值映射为颜色,使用wind映射表
>>> plt.surface(vs, color=cs, method='F', mode='FLBC')
>>> plt.show(rotation='h+')
这里surface()函数,参数method为’F’,也就是GL_TRIANGLE_FAN的方法,绘制多个三角形组成的扇形;参数mode为’FLBC’,意为前面渲染线条后面渲染颜色,呈现出前后不同的视觉效果。show()函数也使用了自动旋转参数(详见3.3节)。
surface()函数支持使用纹理,使用默认参数的话,只需要传入纹理图片路径就可以了。
>>> vs = np.array([
[1,-1,1], [1,-1,-1], [1,1,-1], [1,1,1],
[-1,1,1], [-1,1,-1], [-1,-1,-1], [-1,-1,1],
[-1,-1,1], [-1,-1,-1], [1,-1,-1], [1,-1,1],
[1,1,1], [1,1,-1], [-1,1,-1], [-1,1,1]
])
>>> plt.surface(vs, texture=r'example\res\girl.jpg', alpha=False)
>>> plt.show(rotation='h+')
只要你有女朋友的照片,只需要三行代码就可以做一个这样的礼物送给她了。如果你有多位女朋友也没关系,你可以每4个顶点调用一次surface()函数,最多可以将6位女朋友的照片贴到一个六面体上。不过,多位女朋友照片组成的六面体,只能自己欣赏,不适合送给女朋友哦。你若因此被某位女朋友揍得鼻青脸肿,可别怪我没有提前警告过你。
mesh()函数也是用来绘制曲面的,它和surface()函数的不同之处在于,mesh()函数的顶点是基于一个假象的二维网格。surface()函数需要传入一组顶点,mesh()函数则需要分别传入一组顶点的x、y、z坐标,并且对应着假象的二维网格的x、y、z坐标。 mesh()函数之所以令人困惑,是因为这个假象的二维网格有时候是真正的数据是重合的。
先生成一个二维网格的x坐标和y坐标。
>>> y, x = np.mgrid[-2:2:50j,-2:2:50j]
>>> x.shape
(50, 50)
>>> y.shape
(50, 50)
显然,这是一个50x50的二维网格,x和y的值域范围都是 [ − 2 , 2 ] [-2,2] [−2,2]。分别令网格的每个点的z坐标都是0,以及 z = 2 x e − ( x 2 + y 2 ) z=2xe^{-(x^2+y^2)} z=2xe−(x2+y2),绘制两个曲面。
>>> z1 = np.zeros_like(x)
>>> z2 = 2*x*np.exp(-x**2-y**2)
>>> ax1 = plt.subplot(121)
>>> ax1.mesh(x, y, z1, mode='FLBL')
>>> ax2 = plt.subplot(122)
>>> ax2.mesh(x, y, z2, mode='FLBC')
>>> plt.show()
左侧网格和假象的网格是一致的,右侧则是我们真正想要绘制的网格
先生成球面数据。
>>> lats, lons = np.mgrid[-np.pi/2:np.pi/2:91j, 0:2*np.pi:181j]
>>> xs = np.cos(lats)*np.cos(lons)
>>> ys = np.cos(lats)*np.sin(lons)
>>> zs = np.sin(lats)
>>> xs.shape, ys.shape, zs.shape
((91, 181), (91, 181), (91, 181))
这里,xs、ys、zs分别是球面上点的x、y、z坐标集,同时又都是二维的数组,对应着一个假象的二维网格。
>>> plt.mesh(xs, ys, zs, color=(0,1,0), light=(0,1,0))
>>> plt.show()
因为使用了灯光参数,所以绘制出的球面有亮暗变化,效果如下。
如果将假象的网格视为如下所示的等经纬地图,就可以将这张图映射到球面上。
地图的分辨率是1000x500,因此假象的网格也是1000x500的分辨率。
lats, lons = np.mgrid[-np.pi/2:np.pi/2:500j, 0:2*np.pi:1000j]
xs = np.cos(lats)*np.cos(lons)
ys = np.cos(lats)*np.sin(lons)
zs = np.sin(lats)
im = Image.open(=r'example\res\earth.png')
cs = np.array(im)/255 # 图像颜色值域范围是[0,255],需要变为[0,1]
plt.mesh(xs, ys, zs, color=cs[::-1]) # 颜色逆序
plt.show(rotation='h-')
我们假象的网格,北极为+90°,南极为-90°,从上而下是递减的,而上面的地图数据,行号从上而下是递增的,因此在传参是需要逆序。最终效果如下图所示。
先来构造一个30层高、水平分辨率是50x50的数据体,每个格点的数据随机生成;然后在其中隐藏一个空心圆椎面,设置圆椎面上的格点值为10。
>>> theta = np.linspace(0, 2*np.pi, 180)
>>> _x = np.cos(theta)
>>> _y = np.sin(theta)
>>> data = np.random.random((30,50,50))
>>> for i in range(30):
>>> x = _x*i/2 + 25
>>> x = x.astype(np.int)
>>> y = _y*i/2 + 25
>>> y = y.astype(np.int)
>>> data[i][(x,y)] = 10
调用capsule()函数,即可从数据体找出数据值为10的等值面。
plt.capsule(data, 10, '#C020C0', r_x=(0,50), r_y=(0,50), r_z=(0,30), mode='FCBC')
plt.show()
如果数据体分辨率足够高,等值面就会足够光滑。
从网上可以下载到地形地貌数据,这些数据一般包括经度数据集、纬度数据集、高度数据集和地貌数据集。landforms.npz保存了济南地区(东经116.65°-117.65°、北纬36.25°-37.00°)的地形地貌数据,使用np.load()可以直接加载。
>>> data = np.load(=r'example\res\landforms.npz')
>>> lon = data['lon']
>>> lat = data['lat']
>>> height = data['height']
>>> landforms = data['landforms']
>>> lons, lats = np.meshgrid(lon, lat) # 生成经纬度网格
>>> plt.mesh(lons, lats, height/50000, color=landforms/255)
>>> plt.show()
高度数据的单位是米,经纬度的单位是度,每度相当于100千米,因此高度数据需要除以100000。这里只除以50000,是为了有更好的视觉效果。地貌数据的值域范围是[0,255],除以255变成[0,1]。下图中济南市北部(下方)的黄河、南部(上方)的群山都清晰可见。
WxGL尝试使用flow()函数展示粒子系统的部分功能,并使用了可编程管线技术(但并未开放接口)。下面的代码,前半部分是地形绘制,然后在4500米~5000米的高度上随机生成了500个雪花初始点,并使用u/v/w分量形式指定雪花的降落速度,最后使用flow()函数绘制出雪花飘落的样子。使用flow()函数需要仔细斟酌各个参数,具体细节详见3.16节。
>>> data = np.load(=r'example\res\landforms.npz')
>>> lon = data['lon']
>>> lat = data['lat']
>>> height = data['height']
>>> landforms = data['landforms']
>>> lons, lats = np.meshgrid(lon, lat) # 生成经纬度网格
>>> plt.mesh(lons, lats, height/50000, color=landforms/255)
>>> x = 116.65 + np.random.random(500) * (117.65-116.65) # 随机生成500个雪花点x坐标
>>> y = 36.25 + np.random.random(500) * (37.00-36.25) # 随机生成500个雪花点y坐标
>>> z = 4500 + np.random.random(500) * 500 # 随机生成500个雪花点z坐标(4500米~5000米)
>>> vs = np.stack((x,y,z/10000), axis=1) # 合并成500个顶点坐标
>>> u = np.sin(3*x) # 雪花在东西方的速度分量
>>> v = np.cos(4*y) # 雪花在南北方的速度分量
>>> w = -10 - np.random.random(500) # 雪花垂直方向的速度分量
>>> plt.flow(vs, u/100, v/100, w/100, length=4, frames=30, interval=50, color=(0.8,0.8,0.8), actor='point', size=3)
>>> plt.ticks(zlabel_format=lambda z:'%0.1fkm'%(z*10))
>>> plt.show()
需要特别指出,这段代码还使用了ticks()函数设置网格和标注。ticks()函数接受lambda函数作为坐标轴标注的格式化函数。这里仅演示了如何格式化z轴的标注。
WxGL的容器名为WxGLScene,称为场景。WxGLScene是wx.glcanvas.GLCanvas的派生类,因此WxGL和wxPython的集成是天然无缝的,不存在任何障碍。
每个场景可以使用add_region()生成多个WxGLRegion对象,称为视区。在视区内可以创建模型,每个模型由一个或多个组件构成——所谓组件,可以理解为子模型。
WxGLScene.__init__(parent, head=‘z+’, zoom=1.0, proj=‘cone’, mode=‘3D’, style=‘black’, **kwds)
parent - 父级窗口对象
head - 观察者头部的指向,字符串
'x+' - 头部指向x轴正方向
'y+' - 头部指向y轴正方向
'z+' - 头部指向z轴正方向
zoom - 视口缩放因子
proj - 投影模式,字符串
'ortho' - 平行投影
'cone' - 透视投影
mode - 2D/3D模式,字符串
style - 场景风格
'black' - 背景黑色,文本白色
'white' - 背景白色,文本黑色
'gray' - 背景浅灰色,文本深蓝色
'blue' - 背景深蓝色,文本淡青色
kwds - 关键字参数
elevation - 仰角
azimuth - 方位角
WxGLScene.set_posture(elevation=None, azimuth=None, dist=None, save=False)
elevation - 仰角(度)
azimuth - 方位角(度)
dist - 相机位置与目标点位之间的距离
save - 是否保存相机姿态
WxGLScene.reset_posture()
无参数
WxGLScene.save_scene(fn, alpha=True, buffer=‘FRONT’)
fn - 保存的文件名
alpha - 是否使用透明通道
buffer - 显示缓冲区。默认使用前缓冲区(当前显示内容)
WxGLScene.add_region(box, fixed=False)
box - 四元组,元素值域[0,1]。四个元素分别表示视区左下角坐标、宽度、高度
fixed - 是否锁定旋转缩放
WxGLScene.add_axes(pos, padding=(20,20,20,20))
pos - 三个数字组成的字符串或四元组,表示子图在场景中的位置和大小
padding - 四元组,上、右、下、左四个方向距离边缘的留白像素
WxGLScene.auto_rotate(rotation=‘h+’, **kwds)
rotation - 旋转模式
'h+' - 水平顺时针旋转(默认方式)
'h-' - 水平逆时针旋转
'v+' - 垂直前翻旋转
'v-' - 垂直后翻旋转
kwds - 关键字参数
elevation - 初始仰角,以度(°)为单位,默认值为0
azimuth - 初始方位角以度(°)为单位,默认值为0
step - 帧增量,以度(°)为单位,默认值为5
interval - 帧间隔,以ms为单位,默认值为20
WxGLScene.stop_rotate()
无参数
WxGLRegion.__init__(scene, rid, box, fixed=False)
scene - 所属场景对象
rid - 唯一标识
box - 四元组,元素值域[0,1]。四个元素分别表示视区左下角坐标、宽度、高度
fixed - 是否锁定旋转缩放
WxGLRegion.reset_box(box, clear=False)
box - 四元组,元素值域[0,1]。四个元素分别表示视区左下角坐标、宽度、高度
clear - 是否清空所有模型
WxGLRegion.set_data_range(r_x=None, r_y=None, r_z=None)
r_x - 二元组,x坐标轴范围
r_y - 二元组,y坐标轴范围
r_z - 二元组,z坐标轴范围
WxGLRegion.delete_model(name)
name - 模型名
WxGLRegion.show_model(name)
name - 模型名
WxGLRegion.hide_model(name)
name - 模型名
WxGLRegion.refresh()
无参数
WxGLRegion.create_texture(img, alpha=True)
img - 纹理图片文件名或数据
alpha - 是否使用透明通道
WxGLRegion.text2d(text, size=32, color=None, pos=[0,0,0], **kwds)
text - 文本字符串
size - 文字大小,整型
color - 文本颜色
None表示使用场景对象scene的style风格提供的文本颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3,)
pos - 文本位置,元组、列表或numpy数组
kwds - 关键字参数
align - 兼容text3d(),并无实际意义
valign - 兼容text3d(),并无实际意义
family - (系统支持的)字体
weight - light/bold/normal分别表示字体的轻、重、正常(默认)
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.text3d(text, size=32, color=None, pos=[0,0,0], **kwds)
text - 文本字符串
size - 文字大小,整型
color - 文本颜色
None表示使用场景对象scene的style风格提供的文本颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3,)
pos - 文本位置,元组、列表或numpy数组
kwds - 关键字参数
align - left/right/center分别表示左对齐、右对齐、居中(默认)
valign - top/bottom/middle分别表示上对齐、下对齐、垂直居中(默认)
family - (系统支持的)字体
weight - light/bold/normal分别表示字体的轻、重、正常(默认)
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.point(vs, color, size=None, **kwds)
vs - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
color - 顶点或顶点集颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3,)|(4,)|(n,3)|(n,4)
size - 点的大小,整数,None表示使用当前设置
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
program - 着色器程序
WxGLRegion.line(vs, color, method=‘SINGLE’, width=None, stipple=None, **kwds)
vs - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
color - 顶点或顶点集颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3,)|(4,)|(n,3)|(n,4)
method - 绘制方法
'MULTI' - 线段
'SINGLE' - 连续线段
'LOOP' - 闭合线段
width - 线宽,0.0~10.0之间,None表示使用当前设置
stipple - 线型,整数和两字节十六进制整数组成的元组,形如(1,0xFFFF)。None表示使用当前设置
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
program - 着色器程序
WxGLRegion.surface(vs, color=None, texcoord=None, texture=None, method=‘Q’, mode=None, **kwds)
vs - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
color - 顶点或顶点集颜色
None表示仅使用纹理
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3|4,)|(n,3|4)
texcoord - 顶点的纹理坐标集,numpy.ndarray类型,shape=(n,2)
texture - 2D纹理对象
method - 绘制方法
'Q' - 四边形
0--3 4--7
| | | |
1--2 5--6
'T' - 三角形
0--2 3--5
\/ \/
1 4
'Q+' - 边靠边的连续四边形
0--2--4
| | |
1--3--5
'T+' - 边靠边的连续三角形
0--2--4
\/_\/_\
1 3 5
'F' - 扇形
'P' - 多边形
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
program - 着色器程序
light - 材质灯光颜色,None表示关闭材质灯光
WxGLRegion.mesh(xs, ys, zs, color, method=‘Q’, mode=None, **kwds)
xs - 顶点集的x坐标集,numpy.ndarray类型,shape=(rows,cols)
ys - 顶点集的y坐标集,numpy.ndarray类型,shape=(rows,cols)
zs - 顶点集的z坐标集,numpy.ndarray类型,shape=(rows,cols)
color - 顶点或顶点集颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3|4,)|(rows,cols,3|4)
method - 绘制方法:
'Q' - 四边形
'T' - 三角形
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
blc - 边框的颜色,None表示无边框
blw - 边框宽度
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
program - 着色器程序
light - 材质灯光颜色,None表示关闭材质灯光
WxGLRegion.sphere(center, radius, color, mode=‘FLBL’, slices=60, **kwds)
center - 球心坐标,元组、列表或numpy数组
radius - 半径,浮点型
color - 表面颜色
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
slices - 锥面分片数(数值越大越精细)
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
light - 材质灯光开关
WxGLRegion.cube(center, side, color, mode=‘FLBL’, **kwds)
center - 中心坐标,元组、列表或numpy数组
side - 棱长,整型、浮点型,或长度为3的元组、列表、numpy数组
color - 顶点或顶点集颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3|4,)|(rows,cols,3|4)
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
light - 材质灯光开关
WxGLRegion.cone(center, spire, radius, color, slices=50, mode=‘FCBC’, **kwds)
center - 锥底圆心坐标,元组、列表或numpy数组
spire - 锥尖坐标,元组、列表或numpy数组
radius - 锥底半径,浮点型
color - 圆锥颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3,)
slices - 锥面分片数(数值越大越精细)
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
light - 材质灯光开关
WxGLRegion.cylinder(v_top, v_bottom, radius, color, slices=50, mode=‘FCBC’, **kwds)
v_top - 圆柱上端面的圆心坐标,元组、列表或numpy数组
v_bottom - 圆柱下端面的圆心坐标,元组、列表或numpy数组
radius - 圆柱半径,浮点型
color - 圆柱颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3|4,)|(2,3|4)
slices - 圆柱面分片数(数值越大越精细)
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
headface - 是否显示圆柱端面
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.pipe(vs, radius, color, slices=36, mode=‘FCBC’, **kwds)
vs - 圆管中心点坐标集,numpy.ndarray类型,shape=(n,3)
radius - 圆管半径,浮点型
color - 圆管颜色
预定义的颜色,或形如'#FF0000'的十六进制表示的颜色
浮点型的元组或列表,值域范围:[0,1],长度:3
numpy.ndarray类型,shape=(3|4,)|(n,3|4)
slices - 圆管面分片数(数值越大越精细)
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.capsule(data, threshold, color, r_x=None, r_y=None, r_z=None, mode=‘FLBL’, **kwds)
data - 数据集,numpy.ndarray类型,shape=(layers,rows,cols)
threshold - 阈值,浮点型
color - 表面颜色
r_x - x的动态范围,元组
r_y - y的动态范围,元组
r_z - z的动态范围,元组
mode - 显示模式
None - 使用当前设置
'FCBC' - 前后面填充颜色FCBC
'FLBL' - 前后面显示线条FLBL
'FCBL' - 前面填充颜色,后面显示线条FCBL
'FLBC' - 前面显示线条,后面填充颜色FLBC
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
light - 材质灯光开关
WxGLRegion.volume(data, x=None, y=None, z=None, method=‘Q’, **kwds)
data - 顶点的颜色集,numpy.ndarray类型,shape=(layers,rows,cols,4)
x - 顶点的x坐标集,numpy.ndarray类型,shape=(rows,cols)。缺省则使用volume的2轴索引构造
y - 顶点的y坐标集,numpy.ndarray类型,shape=(rows,cols)。缺省则使用volume的1轴索引构造
z - 顶点的z坐标集,numpy.ndarray类型,shape=(layers,)。缺省则使用volume的0轴索引构造
method - 绘制方法:
'Q' - 四边形
'T' - 三角形
kwds - 关键字参数
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.coordinate(length=1.0, xlabel=None, ylabel=None, zlabel=None, **kwds)
length - 坐标轴半轴长度,从-length到length
xlabel - x轴标注
ylabel - y轴标注
zlabel - z轴标注
kwds - 关键字参数
half - 是否画半轴
slices - 锥面分片数(数值越大越精细)
label_size - 标注文本的字号
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.colorbar(drange, cmap, loc=‘right’, **kwds)
drange - 值域范围,tuple类型
cmap - 调色板名称
loc - 位置,top|bottom|left|right
kwds - 关键字参数
length - ColorBar所在视区的长边长度,默认短边长度为1
subject - 标题
subject_size - 标题字号
label_size - 标注字号
label_format - 标注格式化所用lambda函数
tick_line - 刻度线长度
endpoint - 刻度是否包含值域范围的两个端点值
name - 模型名
inside - 是否更新数据动态范围
visible - 是否显示
WxGLRegion.ticks(**kwds)
kwds - 关键字参数
segment_min - 标注最少分段数量
segment_max - 标注最多分段数量
label_2D3D - 标注试用2D或3D文字
label_size - 标注字号
xlabel_format - x轴标注格式化所用lambda函数
ylabel_format - y轴标注格式化所用lambda函数
zlabel_format - z轴标注格式化所用lambda函数
WxGLRegion.hide_ticks()
无参数
WxGLRegion.ticks2d(**kwds)
kwds - 关键字参数
segment_min - 标注最少分段数量
segment_max - 标注最多分段数量
label_2D3D - 标注试用2D或3D文字
label_size - 标注字号
xlabel_format - x轴标注格式化所用lambda函数
ylabel_format - y轴标注格式化所用lambda函数
WxGLRegion.flow(ps, us, vs, ws, **kwds)
ps - 顶点坐标集,numpy.ndarray类型,shape=(n,3)
us - 顶点u分量集,numpy.ndarray类型,shape=(n,)
vs - 顶点v分量集,numpy.ndarray类型,shape=(n,)
ws - 顶点w分量集,numpy.ndarray类型,shape=(n,)
kwds - 关键字参数
color - 轨迹线颜色,None表示使用速度映射颜色
actor - 顶点模型类型,'point'|'line'两个选项
size - point大小
width - line宽度
length - 轨迹线长度,以速度矢量的模为单位
duty - 顶点line模型长度与轨迹线长度之比(占空比),建议值为0.4
frames - 总帧数
interval - 帧间隔,以ms为单位
threshold - 高通阈值,滤除速度小于阈值的数据点
name - 模型名
代码部分请从GitHub下载,这里只给出一个界面截图。