如何使用python/matplotlib为3d绘图设置"相机位置"?

And*_*ler 120 python matplotlib mplot3d

我正在学习如何使用mplot3d来生成漂亮的三维数据图表,到目前为止我非常高兴.我此刻想做的是一个旋转表面的小动画.为此,我需要为3D投影设置摄像机位置.我想这一定是可行的,因为在交互式使用matplotlib时可以使用鼠标旋转表面.但是如何从脚本中执行此操作?我在mpl_toolkits.mplot3d.proj3d中发现了很多变换,但是我无法找到如何将这些变换用于我的目的,而我没有找到任何我想要做的例子.

cos*_*sis 140

通过"摄像机位置",您可能会想要调整用于查看3D绘图的高程和方位角.我已经使用下面的脚本来创建情节,然后我确定了一个很好的高度,或者ax.view_init,从中查看我的情节.然后,我调整了方位角,或者elev,改变了我的绘图周围的整个360度,在每个实例中保存了数字(并且在我保存绘图时注意了哪个方位角).对于更复杂的摄像机平移,您可以调整高度和角度以获得所需的效果.

    from mpl_toolkits.mplot3d import Axes3D
    ax = Axes3D(fig)
    ax.scatter(xx,yy,zz, marker='o', s=20, c="goldenrod", alpha=0.6)
    for ii in xrange(0,360,1):
        ax.view_init(elev=10., azim=ii)
        savefig("movie%d.png" % ii)
Run Code Online (Sandbox Code Playgroud)

  • 打败我吧!另外,它们可以作为`ax.elev`和`ax.azim`属性使用.你也可以写'ax.azim = ii`甚至`ax.azim + = 1`来达到同样的效果. (23认同)
  • 您还可以通过ax.dist = 15设置摄像机和对象点之间的距离(默认为10) (12认同)
  • 感谢cosmosis和Joe,这正是我想要的.由于我现在知道要查找什么,我还发现了ax.dist,它与ax.azim和axelev一起允许在极坐标中设置摄像机位置. (3认同)

use*_*620 13

将相机位置应用于新绘图将会更方便.所以我绘制,然后用鼠标改变距离移动图表.然后尝试复制包含另一个图上距离的视图.我发现axx.ax.get_axes()通过旧的.azim和.elev获取了一个对象.

在PYTHON ......

axx=ax1.get_axes()
azm=axx.azim
ele=axx.elev
dst=axx.dist       # ALWAYS GIVES 10
#dst=ax1.axes.dist # ALWAYS GIVES 10
#dst=ax1.dist      # ALWAYS GIVES 10
Run Code Online (Sandbox Code Playgroud)

后来的3d图...

ax2.view_init(elev=ele, azim=azm) #Works!
ax2.dist=dst                       # works but always 10 from axx
Run Code Online (Sandbox Code Playgroud)

编辑1 ...好的,相机位置是关于.dist值的错误思考方式.它作为整个图形的一种hackey标量乘数而在所有东西之上.

这适用于视图的放大/缩放:

xlm=ax1.get_xlim3d() #These are two tupples
ylm=ax1.get_ylim3d() #we use them in the next
zlm=ax1.get_zlim3d() #graph to reproduce the magnification from mousing
axx=ax1.get_axes()
azm=axx.azim
ele=axx.elev
Run Code Online (Sandbox Code Playgroud)

后来的图...

ax2.view_init(elev=ele, azim=azm) #Reproduce view
ax2.set_xlim3d(xlm[0],xlm[1])     #Reproduce magnification
ax2.set_ylim3d(ylm[0],ylm[1])     #...
ax2.set_zlim3d(zlm[0],zlm[1])     #...
Run Code Online (Sandbox Code Playgroud)

  • +1 用于调用 hacky 标量乘法。如果您希望获得透视图,那将非常烦人。 (2认同)

Cir*_*四事件 5

最小示例变化azimdistelev

将一些简单的示例图像添加到解释的内容中:https : //stackoverflow.com/a/12905458/895245

这是我的测试程序:

#!/usr/bin/env python3

import sys

import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')

if len(sys.argv) > 1:
    azim = int(sys.argv[1])
else:
    azim = None
if len(sys.argv) > 2:
    dist = int(sys.argv[2])
else:
    dist = None
if len(sys.argv) > 3:
    elev = int(sys.argv[3])
else:
    elev = None

# Make data.
X = np.arange(-5, 6, 1)
Y = np.arange(-5, 6, 1)
X, Y = np.meshgrid(X, Y)
Z = X**2

# Plot the surface.
surf = ax.plot_surface(X, Y, Z, linewidth=0, antialiased=False)

# Labels.
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

if azim is not None:
    ax.azim = azim
if dist is not None:
    ax.dist = dist
if elev is not None:
    ax.elev = elev

print('ax.azim = {}'.format(ax.azim))
print('ax.dist = {}'.format(ax.dist))
print('ax.elev = {}'.format(ax.elev))

plt.savefig(
    'main_{}_{}_{}.png'.format(ax.azim, ax.dist, ax.elev),
    format='png',
    bbox_inches='tight'
)

Run Code Online (Sandbox Code Playgroud)

不带参数运行它会给出默认值:

ax.azim = -60
ax.dist = 10
ax.elev = 30
Run Code Online (Sandbox Code Playgroud)

main_-60_10_30.png

在此处输入图片说明

各不相同 azim

方位角是绕 z 轴的旋转,例如:

  • 0 表示“从 +x 看”
  • 90 的意思是“从 +y 看”

main_-60_10_30.png

在此处输入图片说明

main_0_10_30.png

在此处输入图片说明

main_60_10_30.png

在此处输入图片说明

各不相同 dist

dist 似乎是距数据坐标中心可见点的距离。

main_-60_10_30.png

在此处输入图片说明

main_-60_5_30.png

在此处输入图片说明

main_-60_20_-30.png

在此处输入图片说明

各不相同 elev

由此我们理解elev为眼睛与 xy 平面之间的夹角。

main_-60_10_60.png

在此处输入图片说明

main_-60_10_30.png

在此处输入图片说明

main_-60_10_0.png

在此处输入图片说明

main_-60_10_-30.png

在此处输入图片说明

在 matpotlib==3.2.2 上测试。