如何设置;“摄像机位置”;对于使用python/matplotlib的三维绘图?

如何设置;“摄像机位置”;对于使用python/matplotlib的三维绘图?,python,matplotlib,mplot3d,Python,Matplotlib,Mplot3d,我正在学习如何使用mplot3d生成漂亮的3d数据图,到目前为止我非常高兴。我现在想做的是一个旋转曲面的小动画。为此,我需要为3D投影设置相机位置。我想这一定是可能的,因为当以交互方式使用matplotlib时,可以使用鼠标旋转曲面。但是我怎样才能从脚本中做到这一点呢? 我在mpl_toolkits.mplot3d.proj3d中找到了很多变换,但我找不到如何使用这些变换来实现我的目的,也找不到任何示例来说明我正在尝试做什么。通过“摄影机位置”,听起来你想调整用来查看3D绘图的仰角和方位角。您可

我正在学习如何使用mplot3d生成漂亮的3d数据图,到目前为止我非常高兴。我现在想做的是一个旋转曲面的小动画。为此,我需要为3D投影设置相机位置。我想这一定是可能的,因为当以交互方式使用matplotlib时,可以使用鼠标旋转曲面。但是我怎样才能从脚本中做到这一点呢? 我在mpl_toolkits.mplot3d.proj3d中找到了很多变换,但我找不到如何使用这些变换来实现我的目的,也找不到任何示例来说明我正在尝试做什么。

通过“摄影机位置”,听起来你想调整用来查看3D绘图的仰角和方位角。您可以将此设置为。我已经使用下面的脚本首先创建了绘图,然后我确定了一个良好的标高,或
elev
,从中可以查看我的绘图。然后,我调整方位角,或
azim
,以改变绘图周围的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)

将相机位置应用到新的绘图上会很方便。 所以我绘制,然后用鼠标改变距离来移动绘图。然后尝试复制视图,包括另一个绘图上的距离。 我发现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
稍后的三维图形

ax2.view_init(elev=ele, azim=azm) #Works!
ax2.dist=dst                       # works but always 10 from axx
编辑1。。。 好的,相机位置是关于.dist值的错误思维方式。它作为整个图形的哈奇标量乘法器,凌驾于一切之上

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

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
稍后的图表

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])     #...

请尝试以下代码以找到最佳相机位置

使用if子句中提到的键盘键移动绘图的视角 使用“打印”获取相机位置


最小示例变化
azim
dist
elev

要将一些简单的示例图像添加到上的说明中,请执行以下操作:

这是我的测试程序:

#!/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'
)

在不带参数的情况下运行它将提供默认值:

ax.azim = -60
ax.dist = 10
ax.elev = 30
main_u-60_10_30.png

改变
azim

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

  • 0表示“从+x看”
  • 90表示“从+y看”
main_u-60_10_30.png

main_0_10_30.png

main_60_10_30.png

变化
dist

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

main_u-60_10_30.png

main_u-60_5_30.png

main_u-60_u-20_u-30.png

变化
elev

由此我们了解到,
elev
是眼睛和xy平面之间的角度

main_u-60_10_60.png

main_u-60_10_30.png

main_u-60_10_0.png

main_u-60_u-10_u-30.png


在matpotlib==3.2.2上测试。

比我强!在旁注中,它们作为
ax.elev
ax.azim
属性提供。你也可以写
ax.azim=ii
或者甚至
ax.azim+=1
来达到同样的效果。对不起,我打败了你,但总分都很公平。这也是我的一段代码摘录,for循环中的内容不仅仅是view_init和savefig谢谢cosmosis和Joe,这正是我想要的。因为我现在知道要寻找什么了,我还找到了ax.dist,它与ax.azim和ax.elev一起,允许在极坐标系中设置相机位置。这将为轴“添加”一个新的绘图。因此,如果将“transparent=True”传递给savefig,您将看到前面的所有视图重叠。从文件大小来看,这一点也很明显。我仍在寻找一种方法来改变视图而不重置轴…您还可以通过ax.dist=15(默认为10)设置相机和对象点之间的距离想知道如何在jupyter笔记本中交互旋转的人的旁注:你可以使用
%matplotlib笔记本
,同时按住鼠标右键拖动也会改变相机距离。对于这种可视化,我想让mayavi尝试一下。+1调用hacky标量乘法。如果你希望透视,那就很烦人了。这很有效,谢谢
ax.azim = -60
ax.dist = 10
ax.elev = 30