Tout d'abord, (bien que cela ne changera pas du tout les performances) envisagez de nettoyer votre code, comme ceci:
import matplotlib.pyplot as plt
import numpy as np
import time
x = np.arange(0, 2*np.pi, 0.01)
y = np.sin(x)
fig, axes = plt.subplots(nrows=6)
styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-']
lines = [ax.plot(x, y, style)[0] for ax, style in zip(axes, styles)]
fig.show()
tstart = time.time()
for i in xrange(1, 20):
for j, line in enumerate(lines, start=1):
line.set_ydata(np.sin(j*x + i/10.0))
fig.canvas.draw()
print 'FPS:' , 20/(time.time()-tstart)
Avec l'exemple ci-dessus, j'obtiens environ 10fps.
Juste un petit mot, en fonction de votre cas d'utilisation exact, matplotlib peut ne pas être un excellent choix. Il est orienté vers des chiffres de qualité de publication, pas vers l'affichage en temps réel.
Cependant, vous pouvez faire beaucoup de choses pour accélérer cet exemple.
Il y a deux raisons principales pour lesquelles cela est aussi lent que cela.
1) L'appel fig.canvas.draw()
redessine tout . C'est votre goulot d'étranglement. Dans votre cas, vous n'avez pas besoin de redessiner des éléments tels que les limites des axes, les étiquettes de graduation, etc.
2) Dans votre cas, il y a beaucoup de sous-parcelles avec beaucoup d'étiquettes de graduation. Ceux-ci prennent beaucoup de temps à dessiner.
Ces deux problèmes peuvent être résolus en utilisant le blitting.
Pour faire du blitting efficacement, vous devrez utiliser du code spécifique au backend. En pratique, si vous êtes vraiment inquiet pour des animations fluides, vous intégrez généralement des tracés matplotlib dans une sorte de boîte à outils d'interface graphique, de toute façon, ce n'est donc pas vraiment un problème.
Cependant, sans en savoir un peu plus sur ce que vous faites, je ne peux pas vous y aider.
Néanmoins, il existe une manière de le faire, indépendante de l'interface graphique, qui est encore raisonnablement rapide.
import matplotlib.pyplot as plt
import numpy as np
import time
x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)
fig, axes = plt.subplots(nrows=6)
fig.show()
# We need to draw the canvas before we start animating...
fig.canvas.draw()
styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-']
def plot(ax, style):
return ax.plot(x, y, style, animated=True)[0]
lines = [plot(ax, style) for ax, style in zip(axes, styles)]
# Let's capture the background of the figure
backgrounds = [fig.canvas.copy_from_bbox(ax.bbox) for ax in axes]
tstart = time.time()
for i in xrange(1, 2000):
items = enumerate(zip(lines, axes, backgrounds), start=1)
for j, (line, ax, background) in items:
fig.canvas.restore_region(background)
line.set_ydata(np.sin(j*x + i/10.0))
ax.draw_artist(line)
fig.canvas.blit(ax.bbox)
print 'FPS:' , 2000/(time.time()-tstart)
Cela me donne environ 200 images par seconde.
Pour rendre cela un peu plus pratique, il existe un animations
module dans les versions récentes de matplotlib.
Par exemple:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)
fig, axes = plt.subplots(nrows=6)
styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-']
def plot(ax, style):
return ax.plot(x, y, style, animated=True)[0]
lines = [plot(ax, style) for ax, style in zip(axes, styles)]
def animate(i):
for j, line in enumerate(lines, start=1):
line.set_ydata(np.sin(j*x + i/10.0))
return lines
# We'd normally specify a reasonable "interval" here...
ani = animation.FuncAnimation(fig, animate, xrange(1, 200),
interval=0, blit=True)
plt.show()