วิธีตั้งค่า "ตำแหน่งกล้อง" สำหรับพล็อต 3 มิติโดยใช้ python / matplotlib


140

ฉันกำลังเรียนรู้วิธีใช้ mplot3d เพื่อสร้างพล็อตข้อมูล 3 มิติที่ดีและตอนนี้ฉันก็มีความสุขมาก สิ่งที่ฉันพยายามทำในขณะนี้คือภาพเคลื่อนไหวเล็กน้อยของพื้นผิวที่หมุนได้ เพื่อจุดประสงค์นั้นฉันต้องตั้งตำแหน่งกล้องสำหรับการฉายภาพสามมิติ ฉันเดาว่าสิ่งนี้ต้องเป็นไปได้เนื่องจากพื้นผิวสามารถหมุนได้โดยใช้เมาส์เมื่อใช้ matplotlib แบบโต้ตอบ แต่ฉันจะทำสิ่งนี้จากสคริปต์ได้อย่างไร? ฉันพบการเปลี่ยนแปลงมากมายใน mpl_toolkits.mplot3d.proj3d แต่ฉันไม่พบวิธีใช้สิ่งเหล่านี้ตามวัตถุประสงค์ของฉันและฉันไม่พบตัวอย่างใด ๆ สำหรับสิ่งที่ฉันพยายามทำ


2
หมายเหตุด้านข้างสำหรับผู้ที่สงสัยว่าจะหมุนแบบโต้ตอบในสมุดบันทึก jupyter ได้อย่างไร: คุณสามารถใช้ได้%matplotlib notebook
YvesgereY

นอกจากนี้การลากในขณะที่กดปุ่มเมาส์ขวาค้างไว้จะเปลี่ยนระยะห่างของกล้อง
LoMaPh

สำหรับความแปลกใหม่แบบนี้ฉันจะลองมายาวี
Tactopoda

คำตอบ:


168

ตาม "ตำแหน่งกล้อง" ดูเหมือนว่าคุณต้องการปรับระดับความสูงและมุมราบที่คุณใช้เพื่อดูพล็อต 3 มิติ คุณสามารถตั้งค่านี้ด้วยax.view_init. ฉันใช้สคริปต์ด้านล่างเพื่อสร้างพล็อตก่อนจากนั้นฉันจึงพิจารณาระดับความสูงที่ดีหรือelevจากที่จะดูพล็อตของฉัน จากนั้นฉันปรับมุมราบหรือazimเปลี่ยน 360deg เต็มรูปแบบรอบ ๆ พล็อตของฉันบันทึกรูปในแต่ละอินสแตนซ์ (และสังเกตว่ามุมราบที่ฉันบันทึกพล็อต) สำหรับการแพนกล้องที่ซับซ้อนมากขึ้นคุณสามารถปรับทั้งมุมเงยและมุมเพื่อให้ได้เอฟเฟกต์ที่ต้องการ

    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)

28
เอาชนะฉันให้ได้! หมายเหตุด้านข้างสิ่งเหล่านี้มีให้ในรูปแบบax.elevและax.azimคุณสมบัติ คุณยังสามารถเขียนax.azim = iiหรือแม้แต่ax.azim += 1เพื่อให้ได้ผลเช่นเดียวกัน
Joe Kington

1
ขอโทษที่ฉันเอาชนะคุณ แต่คะแนนยุติธรรมรอบด้าน นี่เป็นเพียงข้อความที่ตัดตอนมาจากการเข้ารหัสของฉันมีสิ่งที่อยู่ภายใน for-loop มากกว่าแค่ view_init และ savefig =)
จักรวาล

4
ขอบคุณคอสโมซิสและโจนั่นคือสิ่งที่ฉันกำลังมองหา เนื่องจากตอนนี้ฉันรู้แล้วว่าต้องค้นหาอะไรฉันจึงพบ ax.dist ซึ่ง - ร่วมกับ ax.azim และ ax.elev - อนุญาตให้ตั้งค่าตำแหน่งกล้องในพิกัดเชิงขั้ว
Andreas Bleuler

ถ้านี่คือคำตอบคุณช่วยทำเครื่องหมายได้ไหม ขอบคุณ.
Cosmosis

12
คุณยังสามารถกำหนดระยะห่างระหว่างกล้องและจุดวัตถุได้โดย ax.dist = 15 (ค่าเริ่มต้นคือ 10)
Tim

15

สิ่งที่จะมีประโยชน์คือการนำตำแหน่งกล้องไปใช้กับพล็อตใหม่ ดังนั้นฉันจึงวางพล็อตแล้วเลื่อนพล็อตไปรอบ ๆ โดยใช้เมาส์เปลี่ยนระยะทาง จากนั้นลองจำลองมุมมองรวมถึงระยะทางบนพล็อตอื่น ฉันพบว่า axx.ax.get_axes () ทำให้ฉันได้วัตถุที่มี. azim และ. elev เก่า

ในไพทอน ...

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

ต่อมากราฟ 3 มิติ ...

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

1
+1 สำหรับการเรียกการคูณสเกลาร์ที่แฮ็ก มันน่ารำคาญมากถ้าคุณหวังมุมมอง
user5920660

1

ลองใช้รหัสต่อไปนี้เพื่อค้นหาตำแหน่งกล้องที่เหมาะสมที่สุด

ย้ายมุมมองของพล็อตโดยใช้แป้นคีย์บอร์ดตามที่กล่าวไว้ในประโยค 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()

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.