簡體   English   中英

如何更改 Matplotlib 3d 旋轉(mplot3d)的鼠標交互風格?

[英]How to change the mouse interaction style for Matplotlib 3d rotation (mplot3d)?

我繪制了一個 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()

在此處輸入圖片說明

在此處輸入圖片說明

我的第一個建議是這個

但如果這根本不可能,我找到了一個可行的解決方案。

_on_move中的Axes3D方法負責處理鼠標事件並旋轉繪圖。

正如你所看到的,這個函數只考慮方位角和仰角。 這就是為什么它的行為方式如此。

可以重新綁定默認_on_move如在mouse_init()的構造函數中調用的方法mouse_init()Axes3D

假設我們的自定義鼠標交互樣式定義在

def _my_on_move(self, event):
    print('my custom mouse style', event)

這不起作用:

ax._on_move = _my_on_move

因為_my_on_move是一個函數,但我們需要它是一個綁定方法,以便self可用。 該解決方案是結合該功能的方法,這將詳細描述這里

import types
ax._on_move = types.MethodType(_my_on_move, ax)

並重新運行鼠標初始化:

ax.mouse_init()

這部分在原_on_move將設置elevazim然后用於通過get_proj()設置中所使用的變換矩陣figure.canvas.draw_idle()

self.elev = art3d._norm_angle(self.elev - (dy/h)*180)
self.azim = art3d._norm_angle(self.azim - (dx/w)*180)
self.get_proj() 
self.figure.canvas.draw_idle()

不知何故,我們必須潛入修改后的變換矩陣。 我不知道是否有更好的辦法,但我們可以只通過在修改的值elevazim

既然我們想要更智能的東西,我們應該切換到四元數。 我建議使用transformations.py,但也有一個來自Blender的名為mathutils的模塊,工作正常。

現在到有趣的部分:

您必須獲取當前視圖(當前轉換矩陣)並根據鼠標移動對其進行旋轉。 然后提取相當於elevazim從旋轉矩陣。 有趣的任務,一些數學,但應該是可能的。

但我會把它留給別人:)

也許在 VTK 的 交互器或 Blender 的 交互器中發現了一些靈感。

如果您想嘗試 Mayavi / VTK 的交互器:

pip install mayavi (或pip3 install mayavi取決於您的版本和虛擬環境)。

然后運行

from mayavi import mlab
from tvtk.api import tvtk

for i in [tvtk.InteractorStyleTerrain(),
          tvtk.InteractorStyleJoystickActor(),
          tvtk.InteractorStyleTrackballActor(),
          tvtk.InteractorStyleTrackball()]:

    mlab.test_surf()
    fig = mlab.gcf()
    fig.scene.interactor.interactor_style = i
    mlab.show()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM