J'essaie de faire une animation d'un nuage de points où les couleurs et la taille des points changent à différentes étapes de l'animation. Pour les données, j'ai deux numpy ndarray avec une valeur x et une valeur y:
data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
Maintenant, je veux tracer un diagramme de dispersion du type
pylab.scatter(x,y,c=data[i,:])
et créez une animation sur l'index i
. Comment puis-je faire cela?
Voici un exemple rapide utilisant le nouveau module d'animation.
C'est un peu plus complexe que cela ne devrait être, mais cela devrait vous donner un cadre pour faire des choses plus sophistiquées.
Si vous utilisez OSX et utilisez le système d’exécution OSX, vous devrez remplacer blit=True
par blit=False
dans l’initialisation FuncAnimation
ci-dessous. Le backend OSX ne supporte pas totalement le blitting. Les performances vont en souffrir, mais l'exemple doit fonctionner correctement sous OSX avec le blitting désactivé.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
class AnimatedScatter(object):
"""An animated scatter plot using matplotlib.animations.FuncAnimation."""
def __init__(self, numpoints=50):
self.numpoints = numpoints
self.stream = self.data_stream()
# Setup the figure and axes...
self.fig, self.ax = plt.subplots()
# Then setup FuncAnimation.
self.ani = animation.FuncAnimation(self.fig, self.update, interval=5,
init_func=self.setup_plot, blit=True)
def setup_plot(self):
"""Initial drawing of the scatter plot."""
x, y, s, c = next(self.stream)
self.scat = self.ax.scatter(x, y, c=c, s=s, animated=True)
self.ax.axis([-10, 10, -10, 10])
# For FuncAnimation's sake, we need to return the artist we'll be using
# Note that it expects a sequence of artists, thus the trailing comma.
return self.scat,
def data_stream(self):
"""Generate a random walk (brownian motion). Data is scaled to produce
a soft "flickering" effect."""
data = np.random.random((4, self.numpoints))
xy = data[:2, :]
s, c = data[2:, :]
xy -= 0.5
xy *= 10
while True:
xy += 0.03 * (np.random.random((2, self.numpoints)) - 0.5)
s += 0.05 * (np.random.random(self.numpoints) - 0.5)
c += 0.02 * (np.random.random(self.numpoints) - 0.5)
yield data
def update(self, i):
"""Update the scatter plot."""
data = next(self.stream)
# Set x and y data...
self.scat.set_offsets(data[:2, :])
# Set sizes...
self.scat._sizes = 300 * abs(data[2])**1.5 + 100
# Set colors..
self.scat.set_array(data[3])
# We need to return the updated artist for FuncAnimation to draw..
# Note that it expects a sequence of artists, thus the trailing comma.
return self.scat,
def show(self):
plt.show()
if __== '__main__':
a = AnimatedScatter()
a.show()
Pour un exemple plus simple, examinez les éléments suivants:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
def main():
numframes = 100
numpoints = 10
color_data = np.random.random((numframes, numpoints))
x, y, c = np.random.random((3, numpoints))
fig = plt.figure()
scat = plt.scatter(x, y, c=c, s=100)
ani = animation.FuncAnimation(fig, update_plot, frames=xrange(numframes),
fargs=(color_data, scat))
plt.show()
def update_plot(i, data, scat):
scat.set_array(data[i])
return scat,
main()
Voici la chose. J'avais l'habitude d'utiliser un utilisateur de Qt et Matlab et je ne suis pas très familiarisé avec le système d'animation de matplotlib.
Mais j’ai trouvé un moyen de créer tout type d’animation que vous souhaitez, comme dans Matlab. C'est vraiment puissant. Pas besoin de vérifier les références des modules et vous êtes prêt à tracer ce que vous voulez. J'espère donc que cela peut aider.
L'idée de base est d'utiliser l'événement time dans PyQt (je suis sûr que d'autres systèmes Gui sur le Python, tels que wxPython et TraitUi, ont le même mécanisme interne pour générer une réponse à un événement. Mais je ne sais pas comment. Chaque fois que l'on appelle un événement PyQt Timer, j'actualise l'ensemble de la toile et redessine l'image entière, je sais que la vitesse et les performances peuvent être lentement influencées, mais ce n'est pas beaucoup.
En voici un petit exemple:
import sys
from PyQt4 import QtGui
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
class Monitor(FigureCanvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
self.x = np.linspace(0,5*np.pi,400)
self.p = 0.0
self.y = np.sin(self.x+self.p)
self.line = self.ax.scatter(self.x,self.y)
self.fig.canvas.draw()
self.timer = self.startTimer(100)
def timerEvent(self, evt):
# update the height of the bars, one liner is easier
self.p += 0.1
self.y = np.sin(self.x+self.p)
self.ax.cla()
self.line = self.ax.scatter(self.x,self.y)
self.fig.canvas.draw()
if __== "__main__":
app = QtGui.QApplication(sys.argv)
w = Monitor()
w.setWindowTitle("Convergence")
w.show()
sys.exit(app.exec_())
Vous pouvez régler la vitesse de rafraîchissement dans le
self.timer = self.startTimer(100)
Je suis comme vous qui souhaitez utiliser le diagramme de dispersion animé pour créer une animation de tri. Mais je ne peux tout simplement pas trouver une fonction dite "set". J'ai donc rafraîchi toute la toile.
J'espère que ça aide..
J'ai écrit celluloïd pour rendre cela plus facile. Il est probablement plus facile de montrer par l'exemple:
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from celluloid import Camera
numpoints = 10
points = np.random.random((2, numpoints))
colors = cm.Rainbow(np.linspace(0, 1, numpoints))
camera = Camera(plt.figure())
for _ in range(100):
points += 0.1 * (np.random.random((2, numpoints)) - .5)
plt.scatter(*points, c=colors, s=100)
camera.snap()
anim = camera.animate(blit=True)
anim.save('scatter.mp4')
Il utilise ArtistAnimation
sous le capot. camera.snap
capture l'état actuel de la figure utilisée pour créer les images dans l'animation.
Edit: Pour quantifier la quantité de mémoire utilisée, je l’ai exécutée dans memory_profiler .
Line # Mem usage Increment Line Contents
================================================
11 65.2 MiB 65.2 MiB @profile
12 def main():
13 65.2 MiB 0.0 MiB numpoints = 10
14 65.2 MiB 0.0 MiB points = np.random.random((2, numpoints))
15 65.2 MiB 0.1 MiB colors = cm.Rainbow(np.linspace(0, 1, numpoints))
16 65.9 MiB 0.6 MiB fig = plt.figure()
17 65.9 MiB 0.0 MiB camera = Camera(fig)
18 67.8 MiB 0.0 MiB for _ in range(100):
19 67.8 MiB 0.0 MiB points += 0.1 * (np.random.random((2, numpoints)) - .5)
20 67.8 MiB 1.9 MiB plt.scatter(*points, c=colors, s=100)
21 67.8 MiB 0.0 MiB camera.snap()
22 70.1 MiB 2.3 MiB anim = camera.animate(blit=True)
23 72.1 MiB 1.9 MiB anim.save('scatter.mp4')
Pour résumer ceci: