12 Gráficos en tiempo real Matplotlib

publicado por: Anonymous

El objetivo es captar 12 datos que llegan desde un serial a python y graficarlos en tiempo real. He conseguido con exito graficar hasta 3 sin ningun problema sin embargo, despues de 4 el tiempo de procesamiento es alto y no obtengo los fps necesarios para que sea agradable. Alguien sabe una mejor forma de optimizar u otro forma alternativa de lograr esto. Practicamente empeze hoy con la libreria matplotlib asi que cualquier sugerencia es bienvenida.

Este es el codigo:

    import serial,time # import Serial Library
    import numpy as np # Import numpy
    import matplotlib.pyplot as plt #import matplotlib library
    import matplotlib.animation as animation
    fig = plt.figure(1)
    fig2= plt.figure(2)
    ax1 = fig.add_subplot(221)
    ax2 = fig.add_subplot(222)
    ax3 = fig.add_subplot(223)
    ax4 = fig.add_subplot(224)
    ax5 = fig2.add_subplot(211)
    ax6 = fig2.add_subplot(212)
    xs = []
    ys = []
    ys2= []
    ys3= []
    ys4= []
    ys5= []
    ys6= []
    cnt=0

    try:
        arduino =serial.Serial('COM4',9600)
        print('Se conecto correctamente')
    except:
        print("Conecte el Arduino en el COM designado")
        print("Terminando programa...")
        try:
            arduino.close()
        except:
            print('No se cerro el puerto correctamente')
            pass
        sys.exit()

    def animate(i):
        datos = arduino.readline()
        datosarray=datos.split(',')
        try:
            y=float(datosarray[0])
            y2=float(datosarray[1])
            y3=float(datosarray[2])
            y4=float(datosarray[3])
            y5=float(datosarray[4])
            y6=float(datosarray[5])

        except:
            y=float(datosarray[0])
            y2=float(datosarray[1])
            y3=float(datosarray[2])
            y4=float(datosarray[3])
            y5=float(datosarray[4])
            y6=float(datosarray[5])

        x= time.clock()
        xs.append(x)

        ys.append(y)
        ys2.append(y2)
        ys3.append(y3)
        ys4.append(y4)
        ys5.append(y5)
        ys6.append(y6)


        ax1.clear()
        ax2.clear()
        ax3.clear()
        ax4.clear()
        ax5.clear()
        ax6.clear()

        ax1.plot(xs,ys)
        ax2.plot(xs,ys2)
        ax3.plot(xs,ys3)
        ax4.plot(xs,ys4)
        ax5.plot(xs,ys5)
        ax6.plot(xs,ys6)

        global cnt
        cnt=cnt+1
        if cnt > 50:
            xs.pop(0)
            ys.pop(0)
            ys2.pop(0)
            ys3.pop(0)
            ys4.pop(0)
            ys5.pop(0)
            ys6.pop(0)


    while(arduino.inWaiting()==0):
        pass
    ani = animation.FuncAnimation(fig,animate, interval = 100)
    ani2 = animation.FuncAnimation(fig2,animate, interval = 100)
    plt.show()

Gracias!

solución

El uso principal de matplotlib ha sido desde su origen la generación de figuras de alta calidad para publicaciones y, por lo tanto, estáticas.

No obstante, aquí tienes un ejemplo completo con la aplicación que buscas descrita en español.

El código completo, disponible en el GitHub del autor con licencia MIT, es el siguiente:

import serial
import json
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import threading
import numpy as np

# Puerto Serial
port = serial.Serial('/dev/ttyACM0', 115200, timeout = 1.)

# Creemos los ejes y la figura donde graficaremos.
fig, ax = plt.subplots()

# Este diccionario almacenara los datos del sensor.
signal = {'x': [], 'y': [], 'z': []}

# Estas lineas dibujaran los datos en la figura.
lines = [ax.plot([], [])[0] for _ in signal.iterkeys()]

# Usaremos esta variable para detectar autoescalado de la grafica.
ylim = ()


# La funcion stream sera llamada periodicamente por el timer
# cada numero determinado de milisegundos definido por la variable
# rate.
def stream():
    # Esta es la cadena de caracteres leida por el puerto serial
    # en formato JSON.
    raw_data = port.readline()
    try:
        # El modulo json permite convertir un string en formato JSON a
        # diccionarios de Python. Si el string no viene en el formato adecuado
        # o la informacion se corrompe, el programa nos lo reporta en
        # el bloque de excepcion ValueError;.
        json_data = json.loads(raw_data)
        for k in signal.iterkeys():
            signal[k].append(json_data[k])
    except ValueError:
        print('Could not read data: %s', raw_data)
    # Si el puerto sigue abierto, programamos otra llamada a la funcion para
    # volver a leer el puerto serial.
    if port.is_open:
        threading.Timer(10 / 1000., stream).start()
    else:
        print('Not streaming anymore!')

def animate(i):
    # Las siguientes dos lineas de codigo auto ajustan el eje
    # de las Y en funcion del contenido de la grafica. Me tomo
    # algo de tiempo encontrar estas funciones. Cuidenlo con su
    # alma y compartanlo!
    global ylim
    ax.relim()
    ax.autoscale_view()
    if ax.get_ylim() != ylim:
        # Esta parte del codigo lo que hace es monitorear los valores
        # del limite del eje Y para detectar cuando la grafica ha sido
        # reajustada. Esto para redibujar las etiquetas del eje Y a
        # medida que se reajusta. Si no, las etiquetas permanecen mientras
        # el eje se reajusta. Por lo que los valores no coinciden con lo
        # desplegado en el eje. Los invito a removerlo para que vean a
        # lo que me refiero.
        ylim = ax.get_ylim()
        fig.canvas.draw()
    for name, line in zip(signal.keys(), lines):
    # Si no hay datos nuevos, ni siquiera nos molestamos en intentar
    # graficar.
        if len(signal[name]) > 0:
            _, ly = line.get_data()
            ly = np.append(ly, signal[name])
            _xdata = np.arange(ly.size)
            line.set_data(_xdata, ly)
            # La informacion ha sido graficada. Ya nos podemos deshacer
            # de ella.
            signal[name] = []
        else:
            print('Signal has no data')
    return lines

if __name__ == '__main__':
    ani = animation.FuncAnimation(fig, animate, interval=50, blit=True)
    stream()
    plt.show(block = False)
    while raw_input('Hit Q to exit.nr> ').lower() != 'q':
        pass
    port.close()

Para representar figuras en tiempo real tienes otras soluciones que quizás te sean más sencillas:

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *