mplot3d 视图角度#

如何定义视图角度#

3D 绘图中视口“相机”的位置由三个角度定义:仰角(elevation)、方位角(azimuth)和翻滚角(roll)。从该位置,它始终指向绘图框体的中心。角度方向是常见约定,与 PyVistaMATLAB 相同。请注意,正翻滚角会顺时针旋转视图平面,因此 3D 坐标轴将看起来逆时针旋转。

../../../_images/mplot3d_view_angles.png

使用鼠标旋转绘图将控制方位角、仰角和翻滚角,并且所有这三个角度都可以通过编程设置

import matplotlib.pyplot as plt
ax = plt.figure().add_subplot(projection='3d')
ax.view_init(elev=30, azim=45, roll=15)

主要视图平面#

要直接查看主要视图平面,所需的仰角、方位角和翻滚角如下面“展开”的绘图所示。这些在 mplot3d.axes3d.Axes3D.view_init API 中有进一步说明。

(源代码, 2x.png, png)

鼠标旋转#

3D 绘图可以通过拖动鼠标进行重新定位。有多种方法可以实现这一点;鼠标旋转的样式可以通过设置 rcParams["axes3d.mouserotationstyle"](默认值:'arcball')来指定,详见使用样式表和 rcParams 定制 Matplotlib

在 v3.10 之前,2D 鼠标位置直接对应于方位角和仰角;MATLAB 也是这样做的。要保持这种方式,请设置 mouserotationstyle: azel。这种方法对于球坐标图(其中 z 轴是特殊轴)效果很好;但是,当沿着 z 轴向下看时,它会导致一种“万向节锁死”现象:绘图对鼠标移动的反应会因当前具体方向而异。此外,“翻滚角”无法控制。

作为替代方案,有多种鼠标旋转样式,其中鼠标操控虚拟“轨迹球”。最简单的形式(mouserotationstyle: trackball)是轨迹球围绕与鼠标运动垂直的平面内轴旋转(就像轨迹球上放着一个板子;板子本身的朝向是固定的,但你可以用鼠标拖动板子,从而旋转球体)。这种方式比 azel 样式更自然;但是,绘图不能轻易围绕视图方向旋转——必须以与所需旋转方向相反的手性圆周移动鼠标,这与直觉相悖。

另一种轨迹球类型是沿着虚拟球体上的最短弧线旋转(mouserotationstyle: sphere)。使用它,围绕视图方向旋转非常简单:抓住球体边缘而不是中心。

Ken Shoemake 的 ARCBALL [Shoemake1992] 也可用(mouserotationstyle: Shoemake);它类似于 sphere 样式,但没有滞后现象,即,将鼠标返回到原始位置,图形也会返回到其原始方向;旋转与鼠标移动路径的细节无关,这可能是理想的。然而,Shoemake 的 arcball 以鼠标移动角速度的两倍旋转(这非常明显,尤其是在调整翻滚角时),并且它缺乏明显的机械对应物;可以说,与路径无关的旋转并不自然(尽管方便),可能需要一些时间来适应。因此,这是一个权衡。

Henriksen 等人 [Henriksen2002] 提供了概述。总结如下:

样式

传统 [1]

包含翻滚角 [2]

均匀 [3]

路径无关 [4]

机械对应物 [5]

azel

✔️

✔️

✔️

trackball

[6]

✔️

✔️

sphere

✔️

✔️

✔️

arcball

✔️

✔️

✔️

您可以使用以下方法尝试各种鼠标旋转样式之一:

import matplotlib as mpl
mpl.rcParams['axes3d.mouserotationstyle'] = 'trackball'  # 'azel', 'trackball', 'sphere', or 'arcball'

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm

ax = plt.figure().add_subplot(projection='3d')

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)

plt.show()

或者,创建一个名为 matplotlibrc 的文件,其内容为:

axes3d.mouserotationstyle: trackball

(或任何其他样式,而不是 trackball),然后运行任何 3D 绘图 示例。

虚拟轨迹球、球体或弧球的大小可以通过设置 rcParams["axes3d.trackballsize"](默认值:0.667)来调整。这指定了获得给定旋转角度(靠近中心时)所需的鼠标移动量,并控制球体或弧球的边缘位置(距离中心多远,从而距离绘图边缘多近)。大小以坐标轴边界框的单位指定,即,要使弧球覆盖整个边界框,请将其设置为 1。大约 2/3 的大小似乎效果不错;这是默认值。

两种弧球(mouserotationstyle: spheremouserotationstyle: arcball)都有明显的边缘;可以通过指定边框宽度 rcParams["axes3d.trackballborder"](默认值:0.2)来使其边缘不那么突兀。这有点像 Gavin Bell 的弧球,它最初是为 OpenGL [Bell1988] 编写的,并用于 Blender 和 Meshlab。Bell 的弧球通过一个双曲线扩展了弧球的球面控制表面;两者平滑连接。然而,双曲线一直延伸到绘图的边缘之外。在 mplot3d 的球体和弧球样式中,边框延伸到半径为 trackballsize/2 + trackballborder 的位置。超出边框后,样式像原始样式一样工作:它只控制翻滚角。大约 0.2 的边框宽度似乎效果不错;这是默认值。要获得原始 Shoemake 的带尖锐边框的弧球,请将边框宽度设置为 0。对于类似于 Bell 弧球的扩展边框,其中从弧球到边框的过渡发生在 45°,将边框宽度设置为 \(\sqrt 2 \approx 1.414\)。边框是一个圆弧,像甜甜圈一样圆柱形地环绕在弧球球体周围,与球体平滑连接,非常类似于 Bell 的双曲线。

[Shoemake1992]

Ken Shoemake,《ARCBALL:一种使用鼠标指定三维旋转的用户界面》,载于 Graphics Interface '92 会议论文集,1992,第 151-156 页,https://doi.org/10.20380/GI1992.18

[Bell1988]

Gavin Bell,在 GLUT (OpenGL Utility Toolkit) 库随附的示例中,markkilgard/glut

[Henriksen2002]

Knud Henriksen, Jon Sporring, Kasper Hornbæk,《虚拟轨迹球再探》,载于 IEEE Transactions on Visualization and Computer Graphics, 第 10 卷,第 2 期,2004 年 3-4 月,第 206-216 页,https://doi.org/10.1109/TVCG.2004.1260772 [全文]