Actualización dinámica de un gráfico de barras en matplotlib

Tengo una serie de sensores conectados a mi Raspberry Pi; Estoy enviando sus datos a mi PC dos veces por segundo usando TCP. Me gustaría graficar continuamente estos valores utilizando matplotlib.

El método que estoy usando actualmente parece ineficiente (estoy borrando la ttwig secundaria y redibujándola cada vez) y tiene algunos inconvenientes no deseados (la escala se reajusta cada vez; me gustaría que permanezca entre 0.0 y 5.0). Sé que hay una manera de hacer esto sin tener que limpiar y volver a dibujar, pero parece que no puede resolverlo. El siguiente es mi código actual:

import socket import sys import time from matplotlib import pyplot as plt # Create a TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Connect the socket to the port where the server is listening server_address = ('192.168.0.10', 10000) print >>sys.stderr, 'connecting to %s port %s' % server_address sock.connect(server_address) # Initial setup for the bar plot plt.ion() fig = plt.figure() ax = fig.add_subplot(1,1,1) x = [1,2,3] labels = ['FSR', 'Tilt', 'IR'] ax.set_xticklabels(labels) y = [5.0,5.0,5.0] ax.bar(x,y) fig.autofmt_xdate() plt.draw() #Grab and continuously plot sensor values try: for i in range(300): amount_received = 0 amount_expected = len("0.00,0.00,0.00") # Receive data from RasPi while amount_received >sys.stderr, 'received "%s"' % data # Plot received data y = [float(datum) for datum in data.split(',')] ax.clear() ax.bar(x,y) plt.draw() time.sleep(0.5) #Close the socket finally: print >>sys.stderr, 'closing socket' sock.close() 

Podrías usar animation.FuncAnimation . Traza el gráfico de barras una vez y guarda el valor de retorno, que es una colección de rectas:

 rects = plt.bar(range(N), x, align='center') 

Luego, para cambiar la altura de una barra, llame a rect.set_height :

  for rect, h in zip(rects, x): rect.set_height(h) 

 import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation def animate(frameno): x = mu + sigma * np.random.randn(N) n, _ = np.histogram(x, bins, normed=True) for rect, h in zip(patches, n): rect.set_height(h) return patches N, mu, sigma = 10000, 100, 15 fig, ax = plt.subplots() x = mu + sigma * np.random.randn(N) n, bins, patches = plt.hist(x, 50, normed=1, facecolor='green', alpha=0.75) frames = 100 ani = animation.FuncAnimation(fig, animate, blit=True, interval=0, frames=frames, repeat=False) plt.show() 

Si matplotlib no es una opción forzada, recomendaría un sistema Push basado en Web Socket en el servidor y un trazado basado en Javascript para el lado del cliente. Primero enumeraré algunas ventajas:

  1. El cliente (su otra PC) solo debe tener un navegador web moderno instalado y puede ejecutar cualquier sistema operativo y no necesita tener instalado Python, Matplotlib
  2. Dado que WebSockets funcionaría de manera transmitida, puede hacer que cualquier número de clientes use la misma fuente de información, lo que puede ser muy útil a la vez que permite a los usuarios tener una demostración de su sistema.
  3. El código del lado del cliente también es eficiente, retiene los últimos valores de ‘x’ y funciona bien en tiempo real, por lo que no es necesario volver a dibujar todo

Ya que estoy haciendo algo muy similar con mi Raspberry Pi, puedo compartir mis detalles de la misma. Está inspirado en esta entrada de blog. El código para el lado del servidor que empuja los datos se puede encontrar aquí . Probablemente pueda ver que después de instalar las dependencias, es muy similar a su código y eventualmente encontrará un socket.send() incluso en mi código. Para el lado del cliente, este es el enlace al archivo HTML y este es el JS que se ejecuta en el navegador, que utiliza la biblioteca Flot Plotting. Estoy seguro de que la demo en su página de inicio es lo suficientemente impresionante como para notarlo!