2012-07-07 44 views
10

Estoy tratando de obtener una animación en 3D de un diagrama de dispersión en matplotlib, basado en la animación de diagrama de dispersión 2d publicado here y el gráfico de línea 3d publicado here.Animación de diagrama de dispersión 3d en matplotlib

Los problemas surgen de set_data y set_offsets que no funcionan en 3D, por lo que se supone que debe utilizar set_3d_properties para virar en la información z. Jugar con eso por lo general se ahoga, pero con el código publicado a continuación se ejecuta. Sin embargo, la transparencia aumenta lo suficiente como para que los puntos simplemente se desvanezcan después de algunos fotogramas. ¿Qué estoy haciendo mal aquí? Quiero que los puntos salten dentro de los límites de la caja por un tiempo. Incluso ajustar el tamaño del paso a algo muy pequeño no ralentiza la transparencia.

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

FLOOR = -10 
CEILING = 10 

class AnimatedScatter(object): 
    def __init__(self, numpoints=5): 
     self.numpoints = numpoints 
     self.stream = self.data_stream() 
     self.angle = 0 

     self.fig = plt.figure() 
     self.ax = self.fig.add_subplot(111,projection = '3d') 
     self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, 
              init_func=self.setup_plot, blit=True) 

    def change_angle(self): 
     self.angle = (self.angle + 1)%360 

    def setup_plot(self): 
     x, y, z = next(self.stream) 
     c = ['b', 'r', 'g', 'y', 'm'] 
     self.scat = self.ax.scatter(x, y, z,c=c, s=200, animated=True) 

     self.ax.set_xlim3d(FLOOR, CEILING) 
     self.ax.set_ylim3d(FLOOR, CEILING) 
     self.ax.set_zlim3d(FLOOR, CEILING) 

     return self.scat, 

    def data_stream(self): 
     data = np.zeros((3, self.numpoints)) 
     xyz = data[:3, :] 
     while True: 
      xyz += 2 * (np.random.random((3, self.numpoints)) - 0.5) 
      yield data 

    def update(self, i): 
     data = next(self.stream) 
     data = np.transpose(data) 

     self.scat.set_offsets(data[:,:2]) 
     #self.scat.set_3d_properties(data) 
     self.scat.set_3d_properties(data[:,2:],'z') 

     self.change_angle() 
     self.ax.view_init(30,self.angle) 
     plt.draw() 
     return self.scat, 

    def show(self): 
     plt.show() 

if __name__ == '__main__': 
    a = AnimatedScatter() 
    a.show() 
+3

lo descubrió, si alguien necesita esto elimine todas las líneas sobre set_offsets y set_3d_properties y solo use esto: self.scat._offsets3d = (x, y, z), en este código, obviamente extrayendo los datos de x, y y z. –

+0

¿Es posible usar plot() con puntos en lugar de un diagrama de dispersión? Por cierto, tu solución funcionó para mí. –

+1

@ericp Debería publicar su solución como una respuesta ... –

Respuesta

3

he encontrado esto, y más genérico, solución: Usted no debe dejar de agregar np.ma.ravel(x_data) ... antes de introducir sus datos en la colección.

Pero el diagrama de dispersión no parece ser para animaciones; es muy lento

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

FLOOR = -10 
CEILING = 10 

class AnimatedScatter(object): 
    def __init__(self, numpoints=5): 
     self.numpoints = numpoints 
     self.stream = self.data_stream() 
     self.angle = 0 

     self.fig = plt.figure() 
     self.ax = self.fig.add_subplot(111,projection = '3d') 
     self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, 
              init_func=self.setup_plot, blit=True) 

    def change_angle(self): 
     self.angle = (self.angle + 1)%360 

    def setup_plot(self): 
     X = next(self.stream) 
     c = ['b', 'r', 'g', 'y', 'm'] 
     self.scat = self.ax.scatter(X[:,0], X[:,1], X[:,2] , c=c, s=200, animated=True) 

     self.ax.set_xlim3d(FLOOR, CEILING) 
     self.ax.set_ylim3d(FLOOR, CEILING) 
     self.ax.set_zlim3d(FLOOR, CEILING) 

     return self.scat, 

    def data_stream(self): 
     data = np.zeros((self.numpoints , 3)) 
     xyz = data[:,:3] 
     while True: 
      xyz += 2 * (np.random.random((self.numpoints,3)) - 0.5) 
      yield data 

    def update(self, i): 
     data = next(self.stream) 
     data = np.transpose(data) 

     self.scat._offsets3d = (np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,0])) 

     self.change_angle() 
     self.ax.view_init(30,self.angle) 
     plt.draw() 
     return self.scat, 

    def show(self): 
     plt.show() 

if __name__ == '__main__': 
    a = AnimatedScatter() 
    a.show() 
4

encontrado la solución por último, aquí es cómo actualizar puntos w/o tocan colores:

from mpl_toolkits.mplot3d.art3d import juggle_axes 
scat._offsets3d = juggle_axes(xs, ys, zs, 'z') 

esto se hace internamente por set_3d_properties junto con re-inicialización de colores

Cuestiones relacionadas