2012-07-07 13 views
10

Sto cercando di ottenere un'animazione 3D di un grafico a dispersione in matplotlib, in base all'animazione 2d scatterplot pubblicata here e il grafico a linee 3d pubblicato here.Animazione 3d scatterplot in matplotlib

I problemi sorgono da set_data e set_offsets non funzionano in 3D, quindi è necessario utilizzare set_3d_properties per virare sulle informazioni z. Giocare con questo di solito soffoca, ma con il codice pubblicato di seguito viene eseguito. Tuttavia, la trasparenza aumenta abbastanza che i punti svaniscono dopo alcuni fotogrammi. Cosa sto facendo di sbagliato qui? Voglio che i punti saltino all'interno dei limiti della scatola per un po '. Anche la regolazione delle dimensioni del passo su qualcosa di molto piccolo non rallenta la trasparenza.

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

capito, se qualcuno ha bisogno di questo rimuovi tutte le righe su set_offsets e set_3d_properties e usa semplicemente: self.scat._offsets3d = (x, y, z), in questo codice ovviamente estraendo x, yez dai dati. –

+0

È possibile utilizzare plot() con punti invece di un grafico a dispersione? A proposito, la tua soluzione ha funzionato per me. –

+1

@ericp Dovresti pubblicare la tua soluzione come risposta ... –

risposta

3

ho trovato questo, e più generico, soluzione: È shold aggiungere np.ma.ravel(x_data) ... prima di inserire i vostri dati nella collezione.

Ma la trama a dispersione non sembra essere destinata alle animazioni; è troppo 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

trovato la soluzione, infine, ecco come aggiornare punti w/o colori toccano:

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

questo è fatto internamente da set_3d_properties con i colori re-inizializzazione