python - font - Actualización dinámica de la parcela en matplotlib
subplot title python (3)
¿Hay alguna manera de actualizar la trama simplemente añadiéndole más puntos [...]?
Hay varias maneras de animar datos en matplotlib, dependiendo de la versión que tenga. ¿Has visto los ejemplos de libros de cocina matplotlib ? Además, consulte los ejemplos de animación más modernos en la documentación de matplotlib. Finalmente, la API de animación define una función FuncAnimation que anima una función en el tiempo. Esta función podría ser simplemente la función que usa para adquirir sus datos.
Cada método básicamente establece la propiedad de los data
del objeto que se está dibujando, por lo que no es necesario borrar la pantalla o figura. La propiedad de data
simplemente se puede extender, por lo que puede mantener los puntos anteriores y simplemente seguir agregando a su línea (o imagen o lo que sea que esté dibujando).
Dado que usted dice que su hora de llegada de datos es incierta, su mejor opción probablemente sea hacer algo como:
import matplotlib.pyplot as plt
import numpy
hl, = plt.plot([], [])
def update_line(hl, new_data):
hl.set_xdata(numpy.append(hl.get_xdata(), new_data))
hl.set_ydata(numpy.append(hl.get_ydata(), new_data))
plt.draw()
Luego, cuando reciba datos del puerto serie, simplemente llame a update_line
.
Estoy haciendo una aplicación en Python que recopila datos de un puerto en serie y traza un gráfico de los datos recolectados con respecto al tiempo de llegada. La hora de llegada de los datos es incierta. Quiero que la trama se actualice cuando se reciban los datos. Busqué cómo hacer esto y encontré dos métodos:
- Borre la trama y vuelva a dibujar la trama con todos los puntos nuevamente.
- Anima la trama cambiándola después de un intervalo particular.
No prefiero la primera porque el programa se ejecuta y recopila datos durante mucho tiempo (un día por ejemplo), y redibujar la trama será bastante lento. El segundo tampoco es preferible ya que el tiempo de llegada de los datos es incierto y quiero que el diagrama se actualice solo cuando se reciban los datos.
¿Hay alguna manera de actualizar el gráfico solo añadiéndole más puntos solo cuando se reciben los datos?
Para hacer esto sin FuncAnimation (por ejemplo, si desea ejecutar otras partes del código mientras se produce el gráfico o si desea actualizar varios gráficos al mismo tiempo), llamar solo al draw
no genera el gráfico (al menos con el backend qt).
Lo siguiente funciona para mí:
import matplotlib.pyplot as plt
plt.ion()
class DynamicUpdate():
#Suppose we know the x range
min_x = 0
max_x = 10
def on_launch(self):
#Set up plot
self.figure, self.ax = plt.subplots()
self.lines, = self.ax.plot([],[], ''o'')
#Autoscale on unknown axis and known lims on the other
self.ax.set_autoscaley_on(True)
self.ax.set_xlim(self.min_x, self.max_x)
#Other stuff
self.ax.grid()
...
def on_running(self, xdata, ydata):
#Update data (with the new _and_ the old points)
self.lines.set_xdata(xdata)
self.lines.set_ydata(ydata)
#Need both of these in order to rescale
self.ax.relim()
self.ax.autoscale_view()
#We need to draw *and* flush
self.figure.canvas.draw()
self.figure.canvas.flush_events()
#Example
def __call__(self):
import numpy as np
import time
self.on_launch()
xdata = []
ydata = []
for x in np.arange(0,10,0.5):
xdata.append(x)
ydata.append(np.exp(-x**2)+10*np.exp(-(x-7)**2))
self.on_running(xdata, ydata)
time.sleep(1)
return xdata, ydata
d = DynamicUpdate()
d()
Sé que llego tarde para responder a esta pregunta, pero para su problema, puede consultar el paquete "joystick". Lo diseñé para trazar una secuencia de datos desde el puerto serie, pero funciona para cualquier transmisión. También permite el registro de texto interactivo o el trazado de imágenes (además del trazado gráfico). No es necesario hacer sus propios bucles en un hilo separado, el paquete se encarga de ello, simplemente proporcione la frecuencia de actualización que desee. Además, el terminal permanece disponible para monitorear comandos durante el trazado. Vea http://www.github.com/ceyzeriat/joystick/ o https://pypi.python.org/pypi/joystick (use el joystick de instalación de pip para instalarlo)
Simplemente reemplace np.random.random () por su punto de datos reales leídos del puerto serie en el siguiente código:
import joystick as jk
import numpy as np
import time
class test(jk.Joystick):
# initialize the infinite loop decorator
_infinite_loop = jk.deco_infinite_loop()
def _init(self, *args, **kwargs):
"""
Function called at initialization, see the doc
"""
self._t0 = time.time() # initialize time
self.xdata = np.array([self._t0]) # time x-axis
self.ydata = np.array([0.0]) # fake data y-axis
# create a graph frame
self.mygraph = self.add_frame(jk.Graph(name="test", size=(500, 500), pos=(50, 50), fmt="go-", xnpts=10000, xnptsmax=10000, xylim=(None, None, 0, 1)))
@_infinite_loop(wait_time=0.2)
def _generate_data(self): # function looped every 0.2 second to read or produce data
"""
Loop starting with the simulation start, getting data and
pushing it to the graph every 0.2 seconds
"""
# concatenate data on the time x-axis
self.xdata = jk.core.add_datapoint(self.xdata, time.time(), xnptsmax=self.mygraph.xnptsmax)
# concatenate data on the fake data y-axis
self.ydata = jk.core.add_datapoint(self.ydata, np.random.random(), xnptsmax=self.mygraph.xnptsmax)
self.mygraph.set_xydata(t, self.ydata)
t = test()
t.start()
t.stop()