我绘制了一个3D图,并使用quiver
绘制x,y和z轴。
在matplotlib的交互式绘图中,我可以拖动和旋转3D绘图,但有一个问题:
拖动绘图时,Z轴似乎被限制在一个平面内,无论我如何拖动绘图,Z轴只能以有限的方式旋转(在平面内),而X轴和Y轴可以自由旋转。
我的问题是:这是matplotlib的一个限制,还是有什么方法可以配置x,y和z轴如何旋转?
任何建议都很感激。
附上一个最小可重复的示例以供参考:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
n_radii = 8
n_angles = 36
# Make radii and angles spaces (radius r=0 omitted to eliminate duplication).
radii = np.linspace(0.125, 1.0, n_radii)
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)
# Repeat all angles for each radius.
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
# Convert polar (radii, angles) coords to cartesian (x, y) coords.
# (0, 0) is manually added at this stage, so there will be no duplicate
# points in the (x, y) plane.
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())
# Compute z to make the pringle surface.
z = np.sin(-x*y)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_trisurf(x, y, z, linewidth=0.2, antialiased=True)
steps = 100
theta = np.linspace(0, 2 * np.pi, steps)
r_max = 1.2
x = np.zeros_like(theta)
y = r_max * np.cos(theta)
z = r_max * np.sin(theta)
ax.plot(x, y, z, 'r')
ax.plot(y, x, z, 'g')
ax.plot(z, y, x, 'b')
scale = 1.08
ax.quiver((0,), (0), (0),
(0), (0), (r_max), color=('c'))
ax.text(0, 0, r_max * scale, 'Z Theta', weight='bold')
ax.quiver((0), (0), (0),
(0), (r_max), (0), color=('m'))
ax.text(0, r_max * scale, 0, 'Y', weight='bold')
ax.quiver((0), (0), (0),
(r_max), (0), (0), color=('y'))
ax.text(r_max * scale, 0, 0, 'X', weight='bold')
plt.show()
2条答案
按热度按时间9gm1akwq1#
我的第一个建议是这样的。
但如果这根本不可能,我找到了一个可行的解决方案。
Axes3D
中的方法_on_move
负责处理鼠标事件和旋转绘图。正如你所看到的,这个函数只考虑方位角和仰角,这就是为什么它的行为方式。
可以重新绑定默认的
_on_move
,如在Axes3D
的构造函数中调用的方法mouse_init()
中所示。假设我们的自定义鼠标交互样式定义在
这不起作用:
因为
_my_on_move
是一个函数,但我们需要它是一个绑定方法,这样self
才可用。解决方案是将函数绑定为方法,这在here中有详细描述:然后重新运行鼠标初始化:
原始
_on_move
中的这一部分将设置elev
和azim
,然后get_proj()
使用它们来设置figure.canvas.draw_idle()
中使用的变换矩阵:不知何故,我们必须偷偷地修改转换矩阵。我不确定是否有更好的方法,但我们可以只传入
elev
和azim
的修改值。既然我们想要更聪明的东西,我们应该切换到四元数。我建议使用transformations.py,但也有一个模块称为
mathutils
从Blender与工程罚款。现在到有趣的部分:
你必须得到当前视图(当前变换矩阵),并根据鼠标的移动旋转它。然后从旋转的矩阵中提取等价的
elev
和azim
。有趣的任务,一些数学,但它应该是可能的。但我会把它留给别人:)
也许在VTK的interactors或Blender中发现了一些错误。
如果你想尝试Mayavi / VTK的交互器:
pip install mayavi
(或pip3 install mayavi
,取决于您的版本和虚拟环境)。然后运行
lvjbypge2#
从Matplotlib 3.6.0开始,通过添加第三个“滚动”Angular ,可以通过编程方式更改此视图Angular ,请参见:https://matplotlib.org/stable/users/prev_whats_new/whats_new_3.6.0.html#d-plots-gained-a-3rd-roll-viewing-angle
然而,使用鼠标进行交互式旋转仍然仅限于改变方位角和仰角。这里有一个问题要讨论其他方法:https://github.com/matplotlib/matplotlib/issues/26492