web-dev-qa-db-fra.com

Animations de dispersion 3D Matplotlib

Je représente graphiquement des positions dans un amas d'étoiles, mes données sont dans un cadre de données avec des positions x, y, z ainsi qu'un index de temps.

Je suis capable de produire un nuage de points 3D et j'essayais de produire un graphique rotatif - j'ai un peu réussi, mais j'ai du mal avec l'API d'animation.

Si ma fonction "update_graph" retourne juste un nouveau ax.scatter (), l'ancien reste tracé sauf si je reconstruis le graphique entier. Cela semble inefficace. De plus, je dois régler mon intervalle plutôt haut ou mon animation "saute" toutes les autres images, donc ça dit que mes performances sont plutôt mauvaises. Enfin, je suis obligé d'utiliser le "blit = False" car je ne peux pas obtenir d'itérateur pour un nuage de points 3D. Apparemment, le "graph.set_data ()" ne fonctionne pas, et je peux utiliser le "graph.set_3d_properties" mais cela ne me permet que de nouvelles coordonnées z.

J'ai donc bricolé un cluuge les données que j'ai utilisées sont à --- (https://www.kaggle.com/mariopasquato/star-cluster-simulations défiler vers le bas)

De plus, je ne trace que 100 points (data = data [data.id <100])

Mon code (de travail) est le suivant:

def update_graph(num):
     ax = p3.Axes3D(fig)
     ax.set_xlim3d([-5.0, 5.0])
     ax.set_xlabel('X')
     ax.set_ylim3d([-5.0, 5.0])
     ax.set_ylabel('Y')
     ax.set_zlim3d([-5.0, 5.0])
     ax.set_zlabel('Z')
     title='3D Test, Time='+str(num*100)
     ax.set_title(title)
     sample=data0[data0['time']==num*100]
     x=sample.x
     y=sample.y
     z=sample.z
     graph=ax.scatter(x,y,z)
     return(graph)

fig = plt.figure()
ax = p3.Axes3D(fig)

# Setting the axes properties
ax.set_xlim3d([-5.0, 5.0])
ax.set_xlabel('X')
ax.set_ylim3d([-5.0, 5.0])
ax.set_ylabel('Y')
ax.set_zlim3d([-5.0, 5.0])
ax.set_zlabel('Z')
ax.set_title('3D Test')
data=data0[data0['time']==0]
x=data.x
y=data.y
z=data.z
graph=ax.scatter(x,y,z)

# Creating the Animation object
line_ani = animation.FuncAnimation(fig, update_graph, 19, 
                               interval=350, blit=False)
plt.show()
10
RDS

Le nuage de points en 3D est un mpl_toolkits.mplot3d.art3d.Path3DCollection objet. Cela fournit un attribut _offsets3d qui héberge un Tuple (x,y,z) et peut être utilisé pour mettre à jour les coordonnées des points de dispersion. Par conséquent, il peut être avantageux de ne pas créer l'intégralité du tracé à chaque itération de l'animation, mais de mettre uniquement à jour ses points.

Voici un exemple pratique sur la façon de procéder.

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation
import pandas as pd


a = np.random.Rand(2000, 3)*10
t = np.array([np.ones(100)*i for i in range(20)]).flatten()
df = pd.DataFrame({"time": t ,"x" : a[:,0], "y" : a[:,1], "z" : a[:,2]})

def update_graph(num):
    data=df[df['time']==num]
    graph._offsets3d = (data.x, data.y, data.z)
    title.set_text('3D Test, time={}'.format(num))


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
title = ax.set_title('3D Test')

data=df[df['time']==0]
graph = ax.scatter(data.x, data.y, data.z)

ani = matplotlib.animation.FuncAnimation(fig, update_graph, 19, 
                               interval=40, blit=False)

plt.show()

Cette solution ne permet pas de blitting. Cependant, selon le cas d'utilisation, il peut ne pas être nécessaire du tout d'utiliser un nuage de points; l'utilisation d'un normal plot peut être également possible, ce qui permet le blitting - comme le montre l'exemple suivant.

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation
import pandas as pd


a = np.random.Rand(2000, 3)*10
t = np.array([np.ones(100)*i for i in range(20)]).flatten()
df = pd.DataFrame({"time": t ,"x" : a[:,0], "y" : a[:,1], "z" : a[:,2]})

def update_graph(num):
    data=df[df['time']==num]
    graph.set_data (data.x, data.y)
    graph.set_3d_properties(data.z)
    title.set_text('3D Test, time={}'.format(num))
    return title, graph, 


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
title = ax.set_title('3D Test')

data=df[df['time']==0]
graph, = ax.plot(data.x, data.y, data.z, linestyle="", marker="o")

ani = matplotlib.animation.FuncAnimation(fig, update_graph, 19, 
                               interval=40, blit=True)

plt.show()
13

Si vous utilisez Jupyter Notebook, n'oubliez pas d'utiliser %matplotlib notebook n'utilisez pas %matplotlib inline.

0
Kuifie