HOWTO · Matplotlib
Traccia i dati in tempo reale utilizzando Matplotlib
Visualizza dati in cambiamento in una finestra Matplotlib con FuncAnimation(), ridisegni manuali della tela o un elemento scatter che si aggiorna.
In questa pagina
Per visualizzare dati che cambiano in una finestra Matplotlib, aggiorna i dati degli elementi grafici e lascia che un backend con supporto GUI aggiorni la schermata. Scegli FuncAnimation() quando gli aggiornamenti arrivano sotto forma di frame, canvas.draw() e canvas.flush_events() quando vuoi controllare direttamente un ciclo, oppure un elemento scatter quando ogni aggiornamento aggiunge un punto. Questi esempi generano valori localmente; per adattarli, sostituisci la logica di aggiornamento con valori provenienti dalla tua sorgente. Non si collegano a un sensore né a un flusso di rete.
Animare un grafico con FuncAnimation()
matplotlib.animation.FuncAnimation richiama una funzione di aggiornamento per ogni frame e pianifica i ridisegni. La funzione di callback riceve il valore del frame corrente, aggiorna la linea esistente e restituisce gli elementi grafici modificati. frames=10 fornisce valori da 0 a 9, mentre interval=50 richiede un intervallo di 50 millisecondi tra i frame; la temporizzazione effettiva dipende dal ciclo di eventi della GUI.
Mantieni un riferimento all’oggetto animazione per tutto il tempo in cui la finestra resta aperta. L’esempio mostra l’animazione in modo interattivo. Per salvarla, chiama ani.save("animation.gif", writer="pillow", fps=10) prima di plt.show() e installa un writer per animazioni compatibile, come Pillow. Il salvataggio è una fase di rendering separata e non crea un flusso di dati in tempo reale.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
figure, ax = plt.subplots()
line, = ax.plot([], [])
ax.set(xlim=(0, 2 * np.pi), ylim=(-1, 1), xlabel="x", ylabel="sin(x)")
def update(frame):
x = np.linspace(0, 2 * np.pi, 200)
y = np.sin(x - frame / 5)
line.set_data(x, y)
return (line,)
ani = FuncAnimation(figure, update, frames=40, interval=50, blit=True)
plt.show()
Usa init_func se l’animazione richiede uno stato iniziale separato e fargs per passare alla funzione di callback altri argomenti fissi. Se la finestra si apre ma non si aggiorna, verifica che il backend Matplotlib selezionato supporti un ciclo di eventi GUI e mantieni attivo ani mentre la finestra è visualizzata.
Aggiornare una linea con canvas.draw() e canvas.flush_events()
Per un ciclo che controlla ogni aggiornamento, crea una linea una sola volta e modificane i dati con set_ydata(). Poi canvas.draw() ridisegna la figura aggiornata e canvas.flush_events() consente alla GUI di elaborare gli eventi in sospeso. Sono metodi del canvas di Matplotlib: non cancellano la figura. plt.ion() attiva la modalità interattiva; una breve pausa dà alla GUI il tempo di rispondere.
import time
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 200)
figure, ax = plt.subplots()
line, = ax.plot(x, np.sin(x))
ax.set(xlim=(0, 2 * np.pi), ylim=(-1, 1), xlabel="x", ylabel="sin(x)")
plt.ion()
for frame in range(40):
line.set_ydata(np.sin(x - frame / 5))
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.05)
plt.ioff()
plt.show()
Questo approccio è utile quando il ciclo deve anche coordinare altre attività. Mantieni brevi gli aggiornamenti, così il ciclo di eventi può elaborare gli input e le richieste di ridisegno. Con un backend non interattivo, queste chiamate possono renderizzare una figura ma non offrire una finestra reattiva; per aggiornamenti interattivi, scegli un backend GUI.
Creare un grafico a dispersione in tempo reale
Per un flusso di punti, crea un solo elemento scatter e sostituiscine gli offset man mano che arrivano nuove coordinate. Aggiornare lo stesso elemento evita di accumulare un nuovo oggetto grafico a ogni iterazione. plt.pause() aggiorna il ciclo di eventi della GUI tra un frame e l’altro, mentre i limiti degli assi riportati sotto mantengono visibili tutti i punti generati.
import numpy as np
import matplotlib.pyplot as plt
figure, ax = plt.subplots()
points = ax.scatter([], [])
ax.set(xlim=(0, 4), ylim=(-1.1, 1.1), xlabel="x", ylabel="sin(x)")
x_values = []
y_values = []
for frame in range(100):
x = frame * 0.04
x_values.append(x)
y_values.append(np.sin(x))
points.set_offsets(np.column_stack((x_values, y_values)))
plt.pause(0.05)
plt.show()
Se ti interessa solo il punto più recente, conserva una sola coppia di coordinate invece dell’intera cronologia. Se vuoi mantenere visibili tutti i punti precedenti, estendi i limiti degli assi man mano che il flusso cresce. Con dati ad alta frequenza, aggiorna il grafico meno spesso dell’arrivo dei dati oppure conserva solo una finestra recente, così il disegno non diventa il collo di bottiglia.