matplotlib
Animazioni e trama interattiva
Ricerca…
introduzione
Con python matplotlib puoi creare correttamente grafici animati.
Animazione di base con FuncAnimation
Il pacchetto matplotlib.animation offre alcune classi per la creazione di animazioni. FuncAnimation
crea animazioni chiamando ripetutamente una funzione. Qui usiamo una funzione animate()
che cambia le coordinate di un punto sul grafico di una funzione seno.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
TWOPI = 2*np.pi
fig, ax = plt.subplots()
t = np.arange(0.0, TWOPI, 0.001)
s = np.sin(t)
l = plt.plot(t, s)
ax = plt.axis([0,TWOPI,-1,1])
redDot, = plt.plot([0], [np.sin(0)], 'ro')
def animate(i):
redDot.set_data(i, np.sin(i))
return redDot,
# create animation using the animate() function
myAnimation = animation.FuncAnimation(fig, animate, frames=np.arange(0.0, TWOPI, 0.1), \
interval=10, blit=True, repeat=True)
plt.show()
Salva l'animazione in gif
In questo esempio usiamo il save
metodo per salvare un Animation
oggetto usando ImageMagick.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import rcParams
# make sure the full paths for ImageMagick and ffmpeg are configured
rcParams['animation.convert_path'] = r'C:\Program Files\ImageMagick\convert'
rcParams['animation.ffmpeg_path'] = r'C:\Program Files\ffmpeg\bin\ffmpeg.exe'
TWOPI = 2*np.pi
fig, ax = plt.subplots()
t = np.arange(0.0, TWOPI, 0.001)
s = np.sin(t)
l = plt.plot(t, s)
ax = plt.axis([0,TWOPI,-1,1])
redDot, = plt.plot([0], [np.sin(0)], 'ro')
def animate(i):
redDot.set_data(i, np.sin(i))
return redDot,
# create animation using the animate() function with no repeat
myAnimation = animation.FuncAnimation(fig, animate, frames=np.arange(0.0, TWOPI, 0.1), \
interval=10, blit=True, repeat=False)
# save animation at 30 frames per second
myAnimation.save('myAnimation.gif', writer='imagemagick', fps=30)
Controlli interattivi con matplotlib.widgets
Per interagire con i grafici Matplotlib offre i widget neutri della GUI. I widget richiedono un oggetto matplotlib.axes.Axes
.
Ecco una demo del widget slider che aggiorna l'ampiezza di una curva sinusoidale. La funzione di aggiornamento viene attivata on_changed()
del dispositivo di scorrimento.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.widgets import Slider
TWOPI = 2*np.pi
fig, ax = plt.subplots()
t = np.arange(0.0, TWOPI, 0.001)
initial_amp = .5
s = initial_amp*np.sin(t)
l, = plt.plot(t, s, lw=2)
ax = plt.axis([0,TWOPI,-1,1])
axamp = plt.axes([0.25, .03, 0.50, 0.02])
# Slider
samp = Slider(axamp, 'Amp', 0, 1, valinit=initial_amp)
def update(val):
# amp is the current value of the slider
amp = samp.val
# update curve
l.set_ydata(amp*np.sin(t))
# redraw canvas while idle
fig.canvas.draw_idle()
# call update function on slider value change
samp.on_changed(update)
plt.show()
- AxesWidget
- Pulsante
- CheckButtons
- Cursore
- EllipseSelector
- laccio
- LassoSelector
- LockDraw
- MultiCursor
- Tasti della radio
- RectangleSelector
- SpanSelector
- SubplotTool
- ToolHandles
Traccia i dati in tempo reale da pipe con matplotlib
Questo può essere utile quando si desidera visualizzare i dati in arrivo in tempo reale. Questi dati potrebbero, ad esempio, provenire da un microcontrollore che campiona continuamente un segnale analogico.
In questo esempio otterremo i nostri dati da una named pipe (nota anche come fifo). Per questo esempio, i dati nella pipe devono essere numeri separati da caratteri newline, ma è possibile adattarli a proprio piacimento.
Dati di esempio:
100
123.5
1589
Maggiori informazioni sulle pipe denominate
Utilizzeremo anche il deque del tipo di dati, dalle raccolte di librerie standard. Un oggetto deque funziona parecchio come un elenco. Ma con un oggetto di deque è abbastanza facile aggiungervi qualcosa mantenendo l'oggetto di deque a una lunghezza fissa. Questo ci permette di mantenere l'asse x a una lunghezza fissa invece di crescere sempre e schiacciare insieme il grafico. Ulteriori informazioni sugli oggetti deque
La scelta del back-end giusto è vitale per le prestazioni. Controlla quali backend funzionano sul tuo sistema operativo e scegli quello veloce. Per me solo qt4agg e il backend predefinito funzionavano, ma quello predefinito era troppo lento. Maggiori informazioni sui backend in matplotlib
Questo esempio è basato sull'esempio matplotlib di tracciare dati casuali .
Nessuno dei 'caratteri in questo codice deve essere rimosso.
import matplotlib
import collections
#selecting the right backend, change qt4agg to your desired backend
matplotlib.use('qt4agg')
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#command to open the pipe
datapipe = open('path to your pipe','r')
#amount of data to be displayed at once, this is the size of the x axis
#increasing this amount also makes plotting slightly slower
data_amount = 1000
#set the size of the deque object
datalist = collections.deque([0]*data_amount,data_amount)
#configure the graph itself
fig, ax = plt.subplots()
line, = ax.plot([0,]*data_amount)
#size of the y axis is set here
ax.set_ylim(0,256)
def update(data):
line.set_ydata(data)
return line,
def data_gen():
while True:
"""
We read two data points in at once, to improve speed
You can read more at once to increase speed
Or you can read just one at a time for improved animation smoothness
data from the pipe comes in as a string,
and is seperated with a newline character,
which is why we use respectively eval and rstrip.
"""
datalist.append(eval((datapipe.readline()).rstrip('\n')))
datalist.append(eval((datapipe.readline()).rstrip('\n')))
yield datalist
ani = animation.FuncAnimation(fig,update,data_gen,interval=0, blit=True)
plt.show()
Se la trama inizia a essere ritardata dopo un po ', prova ad aggiungere altri dati datalist.append, in modo che più linee vengano lette ogni fotogramma. Oppure scegli un backend più veloce se puoi.
Questo ha funzionato con dati 150hz da una pipe sul mio 1.7ghz i3 4005u.