comment définir la «position de la caméra» pour les tracés 3D en utilisant python / matplotlib?

134

J'apprends à utiliser mplot3d pour produire de jolis graphiques de données 3D et je suis assez content jusqu'à présent. Ce que j'essaye de faire en ce moment, c'est une petite animation d'une surface en rotation. Pour cela, je dois définir une position de caméra pour la projection 3D. Je suppose que cela doit être possible car une surface peut être tournée à l'aide de la souris lors de l'utilisation interactive de matplotlib. Mais comment puis-je faire cela à partir d'un script? J'ai trouvé beaucoup de transformations dans mpl_toolkits.mplot3d.proj3d mais je n'ai pas pu trouver comment les utiliser pour mon objectif et je n'ai trouvé aucun exemple de ce que j'essaie de faire.

Andreas Bleuler
la source
2
Note d'accompagnement pour ceux qui se demandent comment faire une rotation interactive dans le notebook Jupyter: vous pouvez utiliser%matplotlib notebook
YvesgereY
Le fait de faire glisser tout en maintenant le bouton droit de la souris modifie la distance de la caméra.
LoMaPh
Pour ce genre de visualisations, j'essaierais mayavi.
Tactopoda

Réponses:

158

Par «position de la caméra», il semble que vous vouliez ajuster l'élévation et l'angle azimutal que vous utilisez pour visualiser le tracé 3D. Vous pouvez définir cela avec ax.view_init. J'ai utilisé le script ci-dessous pour créer d'abord le tracé, puis j'ai déterminé une bonne élévation, ou elev, à partir de laquelle afficher mon tracé. J'ai ensuite ajusté l'angle d'azimut, ou azim, pour faire varier les 360 degrés autour de mon tracé, en enregistrant la figure à chaque instance (et en notant quel angle d'azimut lorsque j'ai enregistré le tracé). Pour un panoramique de caméra plus compliqué, vous pouvez ajuster à la fois l'élévation et l'angle pour obtenir l'effet souhaité.

    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)
cosmose
la source
26
Battez-moi! Sur une note latérale, ceux-ci sont disponibles en tant ax.elevque ax.azimpropriétés et . Vous pourriez aussi avoir juste écrit ax.azim = iiou même ax.azim += 1obtenir le même effet.
Joe Kington
1
Désolé je vous ai battu mais juste des points tout autour. C'est aussi juste un extrait de codage de moi, il y avait plus dans cette boucle for que juste view_init et savefig. =)
cosmose
4
Merci Cosmosis et Joe, c'était exactement ce que je cherchais. Puisque je savais maintenant quoi chercher, j'ai également trouvé ax.dist qui - avec ax.azim et ax.elev - permet de définir la position de la caméra en coordonnées polaires.
Andreas Bleuler
Si telle est la réponse, pourriez-vous la cocher? Merci.
cosmosis
12
Vous pouvez également définir la distance entre la caméra et le point de l'objet par ax.dist = 15 (la valeur par défaut est 10)
Tim
14

Ce qui serait pratique serait d'appliquer la position de la caméra à un nouveau tracé. Je trace donc, puis déplace le tracé avec la souris en changeant la distance. Essayez ensuite de reproduire la vue en incluant la distance sur un autre tracé. Je trouve que axx.ax.get_axes () me donne un objet avec les anciens .azim et .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

Graphique 3D plus tard ...

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

EDIT 1 ... OK, la position de la caméra est une mauvaise façon de penser concernant la valeur .dist. Il chevauche tout comme une sorte de multiplicateur scalaire de hackey pour l'ensemble du graphique.

Cela fonctionne pour le grossissement / zoom de la vue:

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

Graphique ultérieur ...

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])     #...
user1469620
la source
+1 pour appeler la multiplication scalaire hacky. C'est très ennuyeux si vous espériez une perspective.
user5920660