Estoy tratando de hacer una animación de un diagrama de dispersión donde los colores y el tamaño de los puntos cambian en diferentes etapas de la animación. Para los datos, tengo dos ndarray numpy con un valor xy un valor y:
data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
Ahora quiero trazar un diagrama de dispersión del tipo
pylab.scatter(x,y,c=data[i,:])
y cree una animación sobre el índice i
. ¿Cómo hago esto?
python
matplotlib
Nicola Vianello
fuente
fuente
Respuestas:
Suponga que tiene un diagrama de dispersión
scat = ax.scatter(...)
, entonces puedecambiar las posiciones
donde
array
es unaN x 2
matriz con forma de coordenadas xey.cambiar los tamaños
donde
array
es una matriz 1D de tamaños en puntos.cambiar el color
donde
array
es una matriz 1D de valores que se mapearán en color.Aquí hay un ejemplo rápido usando el módulo de animación .
Es un poco más complejo de lo que debería ser, pero esto debería darte un marco para hacer cosas más elegantes.
(Código editado en abril de 2019 para que sea compatible con las versiones actuales. Para el código anterior, consulte el historial de revisiones )
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).T self.scat = self.ax.scatter(x, y, c=c, s=s, vmin=0, vmax=1, cmap="jet", edgecolor="k") 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.""" xy = (np.random.random((self.numpoints, 2))-0.5)*10 s, c = np.random.random((self.numpoints, 2)).T while True: xy += 0.03 * (np.random.random((self.numpoints, 2)) - 0.5) s += 0.05 * (np.random.random(self.numpoints) - 0.5) c += 0.02 * (np.random.random(self.numpoints) - 0.5) yield np.c_[xy[:,0], xy[:,1], s, c] 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.set_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, if __name__ == '__main__': a = AnimatedScatter() plt.show()
Si está en OSX y usa el backend de OSX, deberá cambiar
blit=True
ablit=False
en laFuncAnimation
inicialización a continuación. El backend de OSX no es totalmente compatible con blitting. El rendimiento se verá afectado, pero el ejemplo debería ejecutarse correctamente en OSX con blitting desactivado.Para ver un ejemplo más simple, que solo actualiza los colores, eche un vistazo a lo siguiente:
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=range(numframes), fargs=(color_data, scat)) plt.show() def update_plot(i, data, scat): scat.set_array(data[i]) return scat, main()
fuente
.set_array()
actualizaría el color de los puntos ?!self.Scat.set_offsets(data[:2, :])
aself.scat.set_offsets(data[:2, :].reshape(self.numpoints, 2))
Escribí celuloide para hacerlo más fácil. Probablemente sea más fácil de mostrar con un ejemplo:
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')
Se usa
ArtistAnimation
debajo del capó.camera.snap
captura el estado actual de la figura que se utiliza para crear los fotogramas en la animación.Editar: Para cuantificar cuánta memoria usa esto, lo ejecuté a través de 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')
Para resumir esto:
fuente
FuncAnimation
? ¿Cuáles son las diferencias?Aquí está la cosa. Solía ser un usuario de Qt y Matlab y no estoy muy familiarizado con el sistema de animación en matplotlib.
Pero he encontrado una manera de hacer cualquier tipo de animación que desees, como en matlab. Es realmente poderoso. No es necesario verificar las referencias del módulo y está listo para trazar cualquier cosa que desee. Así que espero que pueda ayudar.
La idea básica es usar el evento de tiempo dentro de PyQt (estoy seguro de que otro sistema Gui en Python como wxPython y TraitUi tiene el mismo mecanismo interno para hacer una respuesta de evento. Pero no sé cómo). Cada vez que se llama un evento de temporizador de PyQt, actualizo todo el lienzo y vuelvo a dibujar la imagen completa, sé que la velocidad y el rendimiento pueden verse influenciados lentamente, pero no tanto.
Aquí hay un pequeño ejemplo de ello:
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 __name__ == "__main__": app = QtGui.QApplication(sys.argv) w = Monitor() w.setWindowTitle("Convergence") w.show() sys.exit(app.exec_())
Puede ajustar la velocidad de actualización en el
Soy como tú que quieres usar el diagrama de dispersión animado para hacer una animación de clasificación. Pero simplemente no puedo encontrar una función llamada "set". Así que refresqué todo el canva.
Espero eso ayude..
fuente
self.startTimer
valor ... ¿algún consejo al respecto? (Sí, sé que ha pasado un tiempo ...)¿Por qué no probar esto?
import numpy as np import matplotlib.pyplot as plt x=np.random.random() y=np.random.random() fig, ax = plt.subplots() ax.scatter(x,y,color='teal') ax.scatter(y,x,color='crimson') ax.set_xlim([0,1]) ax.set_ylim([0,1]) for i in np.arange(50): x=np.random.random() y=np.random.random() bha=ax.scatter(x,y) plt.draw() plt.pause(0.5) bha.remove() plt.show()
fuente