166

私はmplot3dを使用して3dデータの素晴らしいプロットを作成する方法を学んでおり、これまでのところかなり満足しています。私が今やろうとしているのは、回転する表面の小さなアニメーションです。そのためには、3Dプロジェクション用のカメラ位置を設定する必要があります。matplotlibをインタラクティブに使用する場合、マウスを使用してサーフェスを回転できるため、これは可能であると思います。しかし、どうすればスクリプトからこれを行うことができますか?mpl_toolkits.mplot3d.proj3dで多くの変換を見つけましたが、これらを目的に使用する方法を見つけることができず、実行しようとしていることの例も見つかりませんでした。

4

4 に答える 4

202

「カメラの位置」とは、3Dプロットを表示するために使用する高度と方位角を調整したいように聞こえます。これはで設定できますax.view_init。以下のスクリプトを使用して最初にプロットを作成し、次にプロットを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)
于 2012-10-15T23:31:00.633 に答える
17

カメラの位置を新しいプロットに適用すると便利です。そこで、プロットしてから、マウスで距離を変えながらプロットを動かします。次に、別のプロットの距離を含むビューを複製してみてください。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

後で3Dグラフ...

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

編集1...OK、カメラの位置は.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])     #...
于 2015-09-15T23:25:25.227 に答える
6

変化する最小限の例azimdistおよびelev

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'
)

引数なしで実行すると、デフォルト値が得られます。

ax.azim = -60
ax.dist = 10
ax.elev = 30

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でテスト済み。

于 2020-11-15T20:22:33.857 に答える
3

次のコードを試して、最適なカメラ位置を見つけてください

if句に記載されているように、キーボードのキーを使用してプロットの表示角度を移動します

印刷を使用してカメラの位置を取得します

def move_view(event):
    ax.autoscale(enable=False, axis='both') 
    koef = 8
    zkoef = (ax.get_zbound()[0] - ax.get_zbound()[1]) / koef
    xkoef = (ax.get_xbound()[0] - ax.get_xbound()[1]) / koef
    ykoef = (ax.get_ybound()[0] - ax.get_ybound()[1]) / koef
    ## Map an motion to keyboard shortcuts
    if event.key == "ctrl+down":
        ax.set_ybound(ax.get_ybound()[0] + xkoef, ax.get_ybound()[1] + xkoef)
    if event.key == "ctrl+up":
        ax.set_ybound(ax.get_ybound()[0] - xkoef, ax.get_ybound()[1] - xkoef)
    if event.key == "ctrl+right":
        ax.set_xbound(ax.get_xbound()[0] + ykoef, ax.get_xbound()[1] + ykoef)
    if event.key == "ctrl+left":
        ax.set_xbound(ax.get_xbound()[0] - ykoef, ax.get_xbound()[1] - ykoef)
    if event.key == "down":
        ax.set_zbound(ax.get_zbound()[0] - zkoef, ax.get_zbound()[1] - zkoef)
    if event.key == "up":
        ax.set_zbound(ax.get_zbound()[0] + zkoef, ax.get_zbound()[1] + zkoef)
    # zoom option
    if event.key == "alt+up":
        ax.set_xbound(ax.get_xbound()[0]*0.90, ax.get_xbound()[1]*0.90)
        ax.set_ybound(ax.get_ybound()[0]*0.90, ax.get_ybound()[1]*0.90)
        ax.set_zbound(ax.get_zbound()[0]*0.90, ax.get_zbound()[1]*0.90)
    if event.key == "alt+down":
        ax.set_xbound(ax.get_xbound()[0]*1.10, ax.get_xbound()[1]*1.10)
        ax.set_ybound(ax.get_ybound()[0]*1.10, ax.get_ybound()[1]*1.10)
        ax.set_zbound(ax.get_zbound()[0]*1.10, ax.get_zbound()[1]*1.10)
    
    # Rotational movement
    elev=ax.elev
    azim=ax.azim
    if event.key == "shift+up":
        elev+=10
    if event.key == "shift+down":
        elev-=10
    if event.key == "shift+right":
        azim+=10
    if event.key == "shift+left":
        azim-=10

    ax.view_init(elev= elev, azim = azim)

    # print which ever variable you want 

    ax.figure.canvas.draw()

fig.canvas.mpl_connect("key_press_event", move_view)

plt.show()

于 2020-08-19T12:04:38.810 に答える