Bagaimana cara mengatur "posisi kamera" untuk plot 3d menggunakan python / matplotlib?

140

Saya belajar bagaimana menggunakan mplot3d untuk menghasilkan plot data 3d yang bagus dan sejauh ini saya cukup senang. Apa yang saya coba lakukan saat ini adalah sedikit animasi dari permukaan yang berputar. Untuk tujuan itu, saya perlu menetapkan posisi kamera untuk proyeksi 3D. Saya rasa ini harus dimungkinkan karena permukaan dapat diputar menggunakan mouse saat menggunakan matplotlib secara interaktif. Tapi bagaimana saya bisa melakukan ini dari skrip? Saya menemukan banyak transformasi di mpl_toolkits.mplot3d.proj3d tetapi saya tidak dapat menemukan cara menggunakan ini untuk tujuan saya dan saya tidak menemukan contoh apa pun untuk apa yang saya coba lakukan.

Andreas Bleuler
sumber
2
Catatan tambahan untuk mereka yang bertanya-tanya bagaimana cara memutar secara interaktif di notebook jupyter: Anda dapat menggunakan%matplotlib notebook
YvesgereY
Juga menyeret sambil menahan tombol kanan mouse akan mengubah jarak kamera.
LoMaPh
Untuk vizualisasi semacam ini, saya akan mencoba mayavi.
Tactopoda

Jawaban:

168

Dengan "posisi kamera", sepertinya Anda ingin menyesuaikan ketinggian dan sudut azimuth yang Anda gunakan untuk melihat plot 3D. Anda dapat mengatur ini dengan ax.view_init. Saya telah menggunakan skrip di bawah ini untuk pertama-tama membuat plot, kemudian saya menentukan ketinggian yang baik, atau elev, untuk melihat plot saya. Saya kemudian menyesuaikan sudut azimuth, atau azim, untuk memvariasikan 360deg penuh di sekitar plot saya, menyimpan gambar di setiap contoh (dan mencatat sudut azimuth mana saat saya menyimpan plot). Untuk pan kamera yang lebih rumit, Anda dapat menyesuaikan elevasi dan sudut untuk mendapatkan efek yang diinginkan.

    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)
cosmosis
sumber
28
Pukul aku untuk itu! Di samping catatan, ini tersedia sebagai properti ax.elevdan ax.azim. Anda juga bisa saja menulis ax.azim = iiatau bahkan ax.azim += 1mendapatkan efek yang sama.
Joe Kington
1
Maaf saya mengalahkan Anda tetapi poin adil di sekitar. Ini juga hanya kutipan pengkodean saya, ada lebih banyak di dalam for-loop daripada hanya view_init dan savefig. =)
cosmosis
4
Terima kasih cosmosis dan Joe, itulah yang saya cari. Karena sekarang saya tahu apa yang harus dicari, saya juga menemukan ax.dist yang - bersama dengan ax.azim dan ax.elev - memungkinkan untuk mengatur posisi kamera dalam koordinat kutub.
Andreas Bleuler
Jika ini jawabannya - dapatkah Anda mencentangnya? Terima kasih.
cosmosis
12
Anda juga dapat mengatur jarak antara kamera dan titik objek dengan ax.dist = 15 (defaultnya 10)
Tim
15

Apa yang berguna adalah menerapkan posisi Kamera ke plot baru. Jadi saya plot, lalu pindahkan plot dengan mouse mengubah jarak. Kemudian coba untuk meniru tampilan termasuk jarak di plot lain. Saya menemukan bahwa axx.ax.get_axes () memberi saya objek dengan .azim dan .elev lama.

DI 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

Kemudian grafik 3d ...

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

EDIT 1 ... Oke, posisi Kamera adalah cara berpikir yang salah tentang nilai .dist. Ini naik di atas segalanya sebagai semacam pengganda skalar hackey untuk seluruh grafik.

Ini berfungsi untuk perbesaran / zoom tampilan:

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

Grafik Selanjutnya ...

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])     #...
snaxxus.dll
sumber
1
1 untuk memanggil perkalian skalar hacky. Sangat menjengkelkan jika Anda mengharapkan perspektif.
pengguna5920660
1

Coba kode berikut untuk menemukan posisi kamera yang optimal

Pindahkan sudut pandang plot menggunakan tombol keyboard seperti yang disebutkan dalam klausa if

Gunakan print untuk mendapatkan posisi kamera

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

Bharath C
sumber