Entorno: Python 2.7, matplotlib 1.3, IPython notebook 1.1, linux, chrome. El código está en una sola celda de entrada, usando--pylab=inline
Quiero usar el cuaderno IPython y los pandas para consumir un flujo y actualizar dinámicamente un gráfico cada 5 segundos.
Cuando solo uso la declaración de impresión para imprimir los datos en formato de texto, funciona perfectamente bien: la celda de salida sigue imprimiendo datos y agregando nuevas filas. Pero cuando trato de trazar los datos (y luego actualizarlos en un bucle), la trama nunca aparece en la celda de salida. Pero si elimino el bucle, solo grábelo una vez. Funciona bien.
Luego hice una prueba simple:
i = pd.date_range('2013-1-1',periods=100,freq='s')
while True:
plot(pd.Series(data=np.random.randn(100), index=i))
#pd.Series(data=np.random.randn(100), index=i).plot() also tried this one
time.sleep(5)
La salida no mostrará nada hasta que interrumpa manualmente el proceso (ctrl + m + i). Y después de que lo interrumpo, la trama se muestra correctamente como múltiples líneas superpuestas. Pero lo que realmente quiero es una trama que aparezca y se actualice cada 5 segundos (o cuando elplot()
que se llame a función, al igual que los resultados de la declaración de impresión que mencioné anteriormente, que funciona bien). Solo mostrar el gráfico final después de que la celda esté completamente hecha NO es lo que quiero.
Incluso intenté agregar explícitamente la función draw () después de cada plot()
, etc. Ninguno de ellos funciona. Me pregunto cómo actualizar dinámicamente un gráfico mediante un bucle for / while dentro de una celda en el cuaderno IPython.
fuente
clear_output(wait=True)
resuelve este problema. Vea la respuesta de wabu a continuación.%matplotlib nbagg
que te da una figura viva con la que jugar.nbagg
para lograr esto. (Haciendo ping en caso de que esté interesado en responder.) Stackoverflow.com/questions/34486642/…Puede mejorar aún más esto agregando
wait=True
aclear_output
:display.clear_output(wait=True) display.display(pl.gcf())
fuente
Un par de mejoras en la respuesta de HYRY :
display
antesclear_output
para que termine con una parcela, en lugar de dos, cuando la celda se interrumpa.KeyboardInterrupt
, para que la salida de la celda no esté llena de rastreo.import matplotlib.pylab as plt import pandas as pd import numpy as np import time from IPython import display %matplotlib inline i = pd.date_range('2013-1-1',periods=100,freq='s') while True: try: plt.plot(pd.Series(data=np.random.randn(100), index=i)) display.display(plt.gcf()) display.clear_output(wait=True) time.sleep(1) except KeyboardInterrupt: break
fuente
display.display(gcf())
debería ir ANTESdisplay.clear_output(wait=True)
display
ser llamado antesclear_output
? ¿No debería primero borrar la salida y luego mostrar los nuevos datos, en lugar de hacerlo al revés?Agregar etiquetas a las otras soluciones publicadas aquí seguirá agregando nuevas etiquetas en cada ciclo. Para lidiar con eso, borre la trama usando
clf
for t in range(100) if t % refresh_rate == 0: plt.clf() plt.plot(history['val_loss'], 'r-', lw=2, label='val') plt.plot(history['training_loss'], 'b-', lw=1, label='training') plt.legend() display.clear_output(wait=True) display.display(plt.gcf())
fuente
plt.clf()
funciona. Sin embargo, ¿hay alguna forma de deshacerse del parpadeo de las actualizaciones?Intente agregar
show()
ogcf().show()
después de laplot()
función. Esto forzará la actualización de la figura actual (gcf () devuelve una referencia para la figura actual).fuente
Puedes hacerlo así. Acepta x, y como lista y genera un gráfico de dispersión más una tendencia lineal en el mismo gráfico.
from IPython.display import clear_output from matplotlib import pyplot as plt %matplotlib inline def live_plot(x, y, figsize=(7,5), title=''): clear_output(wait=True) plt.figure(figsize=figsize) plt.xlim(0, training_steps) plt.ylim(0, 100) x= [float(i) for i in x] y= [float(i) for i in y] if len(x) > 1: plt.scatter(x,y, label='axis y', color='k') m, b = np.polyfit(x, y, 1) plt.plot(x, [x * m for x in x] + b) plt.title(title) plt.grid(True) plt.xlabel('axis x') plt.ylabel('axis y') plt.show();
solo necesitas llamar
live_plot(x, y)
dentro de un bucle. Así es como se ve:fuente