Trazado lento usando la función de animación en Matplotlib, Python

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.