matplotlib
Animations et traçage interactif
Recherche…
Introduction
Avec python matplotlib, vous pouvez créer des graphiques animés correctement.
Animation de base avec FuncAnimation
Le package matplotlib.animation propose des classes pour créer des animations. FuncAnimation
crée des animations en appelant plusieurs fois une fonction. Nous utilisons ici une fonction animate()
qui modifie les coordonnées d'un point sur le graphique d'une fonction sinus.
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()
Enregistrer l'animation sur gif
Dans cet exemple , nous utilisons la save
méthode pour enregistrer une Animation
objet en utilisant 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)
Contrôles interactifs avec matplotlib.widgets
Pour interagir avec les tracés, Matplotlib propose des widgets neutres pour l'interface graphique. Les widgets nécessitent un objet matplotlib.axes.Axes
.
Voici une démo de widget de curseur qui indique l'amplitude d'une courbe sinusoïdale. La fonction de mise à jour est déclenchée par l'événement on_changed()
du curseur.
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
- Bouton
- Boutons de contrôle
- Le curseur
- EllipseSelector
- Lasso
- LassoSelector
- LockDraw
- MultiCursor
- RadioButtons
- RectangleSelector
- SpanSelector
- SubplotTool
- Des outils
Tracez des données en direct depuis un tuyau avec matplotlib
Cela peut être utile lorsque vous souhaitez visualiser les données entrantes en temps réel. Ces données pourraient, par exemple, provenir d'un microcontrôleur qui échantillonne en permanence un signal analogique.
Dans cet exemple, nous allons obtenir nos données à partir d'un canal nommé (également appelé fifo). Pour cet exemple, les données dans le tube doivent être des nombres séparés par des caractères de nouvelle ligne, mais vous pouvez l'adapter à votre goût.
Exemple de données:
100
123.5
1589
Plus d'informations sur les canaux nommés
Nous utiliserons également le type de données, provenant des collections de bibliothèques standard. Un objet deque fonctionne beaucoup comme une liste. Mais avec un objet deque, il est assez facile d'y ajouter quelque chose tout en gardant l'objet deque à une longueur fixe. Cela nous permet de garder l'axe x à une longueur fixe au lieu de toujours croître et écraser le graphique ensemble. Plus d'informations sur les objets deque
Choisir le bon backend est vital pour la performance. Vérifiez ce que les backends fonctionnent sur votre système d'exploitation et choisissez-en un rapide. Pour moi, seul qt4agg et le backend par défaut fonctionnaient, mais celui par défaut était trop lent. Plus d'informations sur les backends en matplotlib
Cet exemple est basé sur l'exemple matplotlib de traçage de données aléatoires .
Aucun des caractères de ce code ne doit être supprimé.
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()
Si votre tracé commence à être retardé après un certain temps, essayez d’ajouter plus de données datalist.append, afin que davantage de lignes soient lues à chaque image. Ou choisissez un backend plus rapide si vous le pouvez.
Cela a fonctionné avec 150hz données d'un tuyau sur mon 1.7ghz i3 4005u.