Necesito tu ayuda para un problema que estoy tratando estos días. Puedo trazar una serie de datos que se transfirieron desde mi teléfono celular Bluetooth y recibí por el puerto COM de mi computadora portátil. A primera vista parece estar bien, pero a lo sumo puede trazar cada 260 ms (~ 3 fps). Sin embargo el teléfono móvil envía datos cada 100 ms. Estoy bastante seguro de que el problema proviene del comando “plot” y “figure” que me confunde. Aprecio si alguien puede corregir mi código:
from Tkinter import * import serial import matplotlib.pyplot as plt import matplotlib.animation as animation fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) ser = serial.Serial("COM4", baudrate=115200, timeout=0.1) cnt=0 xComponent=[] plt.ylim(0,30) while (ser.inWaiting() == 0): # Wait here until there is data pass def animate(i): BluetoothString = ser.readline() ser.flush() dataArray = BluetoothString.split(',') x = float(dataArray[2]) # we only need 3rd component xComponent.append(x) print xComponent ax1.clear() ax1.plot(xComponent) plt.ylim(0,25) global cnt if (cnt > 16): xComponent.pop(0) else: cnt = cnt + 1 ani = animation.FuncAnimation(fig, animate, interval=0) plt.show()
Es difícil decir algo sobre su caso especial, ya que no tenemos la parte de conexión en serie que está utilizando.
Sin embargo, el trazado debe ser mucho más rápido que 3 fps en matplotlib si esto es solo un trazado de línea con algunos puntos en él. Puede intentar directamente una cosa para no volver a contabilizar todo en cada paso de la iteración, sino trazarlo una vez y luego solo actualizar los datos utilizando .set_data()
El siguiente ejemplo está estrechamente relacionado con su código y se ejecuta con 90 fps en mi máquina. Así que tal vez lo intentes y veas si ayuda a acelerar tu caso.
import matplotlib.pyplot as plt import matplotlib.animation as animation import time fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) cnt=0 xComponent=[] line, = ax1.plot([0], [0]) text = ax1.text(0.97,0.97, "", transform=ax1.transAxes, ha="right", va="top") plt.ylim(0,25) plt.xlim(0,100) last_time = {0: time.time()} def animate(i): if len(xComponent)>100: xComponent.pop(0) y = i % 25 xComponent.append(y) line.set_data(range( len(xComponent) ) ,xComponent) new_time = time.time() text.set_text("{0:.2f} fps".format(1./(new_time-last_time[0]))) last_time.update({0:new_time}) ani = animation.FuncAnimation(fig, animate, interval=0) plt.show()
No quiero pisar a nadie por aquí, porque @ImportanceOfBeingErnest lo clavó, pero al añadirle una nota a su ejemplo, salté mi tasa de fotogtwigs de 50 a 300. aquí hay cómo hacerlo en su ejemplo: Dejé comentarios donde hice cambios.
import matplotlib.pyplot as plt import matplotlib.animation as animation import time fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) cnt=0 xComponent=[] line, = ax1.plot([0], [0]) text = ax1.text(0.97,0.97, "", transform=ax1.transAxes, ha="right", va="top") plt.ylim(0,25) plt.xlim(0,100) last_time = {0: time.time()} def animateinit(): #tells our animator what artists will need re-drawing every time return line,text def animate(i): if len(xComponent)>100: xComponent.pop(0) y = i % 25 xComponent.append(y) line.set_data(range( len(xComponent) ) ,xComponent) new_time = time.time() text.set_text("{0:.2f} fps".format(1./(new_time-last_time[0]))) last_time.update({0:new_time}) return line,text #return the updated artists #inform the animator what our init_func is and enable blitting ani = animation.FuncAnimation(fig, animate, interval=0,init_func=animateinit, blit=True) plt.show()
Cada sorteo en mpl es bastante caro, por lo que si podemos dibujar lo menos posible, vemos una gran aceleración. Al decirle al animador que solo re-dibuje ciertos elementos, evitamos tener que volver a dibujar cosas como marcadores de ejes, tags de ejes, cálculos de escalado, etc. esas cosas parecen simples, pero hay muchas de ellas, y la sobrecarga se acumula rápidamente.