2011-03-03 23 views
9

Tengo una simulación que calcula los datos de superficie para cada iteración de la simulación. Me gustaría trazar continuamente esos datos como un gráfico de superficie en la misma ventana (actualizando la gráfica en cada iteración) para ver cómo evoluciona y para verificar el algoritmo.trazado en 3D continuo (es decir, actualización de figura) usando python-matplotlib?

Mi idea era crear una clase que inicializara la ventana/trama y luego volver a dibujar en esa ventana desde el interior del ciclo de simulación. Aquí está la clase que se me ocurrió:

import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
from matplotlib import cm 
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter 
import matplotlib 
matplotlib.interactive(False) 

class plot3dClass(object): 

    def __init__(self, systemSideLength, lowerCutoffLength): 
     self.systemSideLength = systemSideLength 
     self.lowerCutoffLength = lowerCutoffLength 
     self.fig = plt.figure() 
     self.ax = self.fig.add_subplot(111, projection='3d') 
     self.ax.set_zlim3d(-10e-9, 10e9) 

     X = np.arange(0, self.systemSideLength, self.lowerCutoffLength) 
     Y = X 
     self.X, self.Y = np.meshgrid(X, Y) 

     self.ax.w_zaxis.set_major_locator(LinearLocator(10)) 
     self.ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f')) 

     heightR = np.zeros(self.X.shape) 
     self.surf = self.ax.plot_surface(self.X, self.Y, heightR, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False) 
     #~ self.fig.colorbar(self.surf, shrink=0.5, aspect=5) 

     plt.show() 


    def drawNow(self, heightR): 

     self.surf = self.ax.plot_surface(self.X, self.Y, heightR, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=False) 
     plt.draw()      # redraw the canvas 

     time.sleep(1) 

El problema que tengo con este código, es que el código se detiene en el 'plt.show()' y sólo continúa, cuando cierro la trama ventana. Además, no estoy seguro de si las llamadas de 'self.ax.plot_surface (...)' y 'plt.draw()' actualizarían la figura como me gustaría.

¿Es esta clase la dirección correcta?

En caso afirmativo: ¿Qué modificaciones son necesarias?

Si no: ¿Podría alguien darme consejos cómo lograr lo que quiero?

que se dan cuenta de que este problema podría parecer trivial a los demás, pero yo (honestamente) hicieron pasar todo el día de ayer en Google y tratando y estoy en una pérdida ...

Cualquier ayuda sería muy apreciada, para que pueda volver a mi trabajo real.

Tanques con mucha antelación.

Como referencia:

también encontré el siguiente código que no, lo que quiero, pero es en 2D, por lo que no me ayuda directa:

from pylab import * 
import time 

ion() 

tstart = time.time()    # for profiling 
x = arange(0,2*pi,0.01)   # x-array 
line, = plot(x,sin(x)) 

for i in arange(1,200): 
    line.set_ydata(sin(x+i/10.0)) # update the data 
    draw()       # redraw the canvas 

print 'FPS:' , 200/(time.time()-tstart) 

Respuesta

7

No es necesario a plt.show() si se trata de un gráfico animado (interactivo). También quiere que el conjunto interactivo sea True, not False, que es lo mismo que llamar al ion() en su 2do ejemplo. Además, necesita remove() los gráficos de superficie de marcos anteriores si no desea verlos todos.

De lo contrario, usted estuvo muy cerca.

Esto funciona para mí:

import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
from matplotlib import cm 
from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter 
import matplotlib, time 

class plot3dClass(object): 

    def __init__(self, systemSideLength, lowerCutoffLength): 
     self.systemSideLength = systemSideLength 
     self.lowerCutoffLength = lowerCutoffLength 
     self.fig = plt.figure() 
     self.ax = self.fig.add_subplot(111, projection='3d') 
     self.ax.set_zlim3d(-10e-9, 10e9) 

     rng = np.arange(0, self.systemSideLength, self.lowerCutoffLength) 
     self.X, self.Y = np.meshgrid(rng,rng) 

     self.ax.w_zaxis.set_major_locator(LinearLocator(10)) 
     self.ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f')) 

     heightR = np.zeros(self.X.shape) 
     self.surf = self.ax.plot_surface( 
      self.X, self.Y, heightR, rstride=1, cstride=1, 
      cmap=cm.jet, linewidth=0, antialiased=False) 
     # plt.draw() maybe you want to see this frame? 

    def drawNow(self, heightR): 
     self.surf.remove() 
     self.surf = self.ax.plot_surface( 
      self.X, self.Y, heightR, rstride=1, cstride=1, 
      cmap=cm.jet, linewidth=0, antialiased=False) 
     plt.draw()      # redraw the canvas 
     time.sleep(1) 

matplotlib.interactive(True) 

p = plot3dClass(5,1) 
for i in range(2): 
    p.drawNow(np.random.random(p.X.shape)) 
+0

esto no funciona en mi computadora (Win XP, python 2.7.3): todo lo que veo es el gráfico final –

+0

Necesita self.fig.cances.flush_events() después de la línea plt.draw(). (crédito http://stackoverflow.com/a/4098938/415551) –

1

estoy agradecido por la respuesta de Pablo, aunque no tengo que intentó descubierto todavía.

Mientras tanto, había encontrado otra solución que funciona y se procesa con OpenGL usando MayaVI, lo cual está bien ya que solo necesito retroalimentación visual rápida en tiempo real. Sin embargo tuve que instalar los siguientes paquetes bajo Ubuntu: Pitón-enthoughtbase y mayavi2

Aquí está el código:

import numpy as np 
import time 
from enthought.mayavi import mlab 
from enthought.tvtk.tools import visual 

    class plot3dClass(object): 

     def __init__(self, systemSideLength, lowerCutoffLength): 
      self.systemSideLength = systemSideLength 
      self.lowerCutoffLength = lowerCutoffLength 

      rangeMax = self.systemSideLength 
      X = np.arange(0, self.systemSideLength, self.lowerCutoffLength) 
      Y = X 

      matrixSize = int(round(self.systemSideLength/self.lowerCutoffLength)) 
      heightR = np.zeros((matrixSize, matrixSize)) 

      fig = mlab.figure(size=(500,500)) 
      visual.set_viewer(fig) 
      self.surf = mlab.surf(X, Y, heightR, warp_scale = 1e1) # NOTE: the warp_scale factor is relative to the scale of the x- and y-axes 
      box_extent = (0,rangeMax, 0,rangeMax, -1e-7,1e-7) # NOTE: the extent options refers to the size and position in the 3D space relative to the origin 

      mlab.outline(self.surf, color=(0.7, .7, .7), extent = box_extent) 

     def drawNow(self, heightR): 
      self.surf.mlab_source.scalars = heightR 
      time.sleep(0.033) 

Esta clase no es exactamente donde me gustaría que fuera y tengo dos problemas inmediatos con it:

  1. Después de un rato, la ventana aparecerá en gris por Ubuntu como (supongo) Ubuntu piensa que la aplicación no responde.Tal vez más bien un problema de Ubuntu, pero molesto.
  2. He estado tratando de descubrir cómo puedo rotar la trama con el mouse mientras estoy animando.

Voy a intentar obtener estas respuestas en otro hilo.

EDITAR: Ok. Acabo de probar el código como lo sugirió Paul y también funciona para mí. Sin embargo, al intentarlo me di cuenta de que MatPlotLib probablemente no sea la mejor opción para hacer animaciones en tiempo real. Al menos para mí es extremadamente lento (¿quizás solo en 3D?).

Así que al final me quedaré con la implementación de MayaVI desde arriba, que a excepción de los dos puntos mencionados, funciona muy bien.

EDIT: Si vas con la solución matplotlib, he encontrado que se puede poner la línea matplotlib.interactive(True) dentro de la declaración de la clase de trazado. De esta forma, puede hacer que MatPlotLib solo se defina dentro de la clase de trazado.

+1

no se está dando una respuesta útil para usted. El título OP fue: Cómo lograr un trazado 3D continuo (es decir, actualizar una figura) usando Python y ** MatPlotLib ** ?. Y te das a ti mismo y respondes que usa MayaVI en lugar de matplotlib. Por otro lado, obtuviste una respuesta válida usando matplotlib y no lo intentaste lo primero ... – joaquin

0

que tenía un problema similar y esto funcionó para mí:

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

plt.ion() 
fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 

for k in xrange(0,X_range): 
    ax.plot(x_input, y_input, z_input) 
    plt.draw() 
    plt.pause(0.02) 
    ax.cla() 

Para usted, me imagino que la solución sea algo similar a the top answer excepto reemplazando time.sleep() con plt.pause(), lo que terminar el dibujo de la figura antes dormido.

Cuestiones relacionadas