2012-02-22 28 views
34

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 que tengo dos ndarray numpy con un valor de valor X e Y:Cómo animar un diagrama de dispersión?

data.shape = (ntime, npoint) 
x.shape = (npoint) 
y.shape = (npoint) 

Ahora quiero trazar un gráfico de dispersión del tipo

pylab.scatter(x,y,c=data[i,:]) 

y crear una animación sobre el índice de i. ¿Cómo hago esto?

Respuesta

64

Aquí hay un ejemplo rápido usando el nuevo módulo de animación.

Es un poco más complejo de lo que debe ser, pero esto debería darle un marco para hacer cosas más elegantes.

Si estás en OSX y usando el backend OSX, tendrá que cambiar blit=True a blit=False en el FuncAnimation inicialización a continuación. El backend de OSX no admite completamente Blitting. El rendimiento sufrirá, pero el ejemplo debería ejecutarse correctamente en OSX con Blitting desactivado.

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 __name__ == '__main__': 
    a = AnimatedScatter() 
    a.show() 

enter image description here

Para un ejemplo más simple, echar 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=xrange(numframes), 
            fargs=(color_data, scat)) 
    plt.show() 

def update_plot(i, data, scat): 
    scat.set_array(data[i]) 
    return scat, 

main() 
+0

Hola Joe He intentado con tu primer ejemplo pero no funciona, mientras que el segundo sí. Tal vez intente depurar la primera opción, esto me ayudará a mejorar mi conocimiento de Python. Gracias –

+0

El primer ejemplo funciona perfectamente (excepto para el manejo del tamaño) en la distribución de Enthought (Win7, matplotlib 1.2.0, numpy 1.4.). Código impresionante, Joe! Pude verlo durante horas :-). – Dave

+1

Desafortunadamente, el primer ejemplo no se muestra para mí, ya sea usando matplotlib 1.3.1 en OS X. Obtengo que el recuadro no muestra ningún punto. El segundo ejemplo funciona – JoshAdel

3

Aquí está la cosa. Solía ​​usar Qt y Matlab y no estoy muy familiarizado con el sistema de animación de matplotlib.

Pero tengo que encontrar la forma de hacer cualquier tipo de animación que desee tal como está en matlab. Es realmente poderoso. No es necesario verificar las referencias de los módulos y es bueno trazar todo lo que desee. Así que espero que pueda ayudar.

La idea básica es utilizar 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 al evento Timer de PyQt, actualizo todo el lienzo y vuelvo a dibujar toda la imagen, sé que la velocidad y el rendimiento pueden verse influenciados lentamente, pero no es mucho.

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_()) 

Se puede ajustar la velocidad de refresco en el

 self.timer = self.startTimer(100) 

Soy igual que lo que quieren utilizar la dispersión de animación trama para hacer una animación de clasificación. Pero simplemente no puedo encontrar una función llamada "establecer". Así que refresqué todo el canva.

Espero que ayude ..

+0

¡Muy bien! Sin embargo, no obtuve ningún cambio en la frecuencia de actualización al ajustar el valor 'self.startTimer' ... ¿algún consejo al respecto? (Sí, sé que ha pasado un tiempo ...) –

Cuestiones relacionadas