TL/DR : Si vous rencontrez des difficultés avec le ax.set_...
pour animer votre diagramme de dispersion, vous pouvez essayer d'effacer le diagramme à chaque image (c'est-à-dire, ax.clear()
) et réorganiser les choses comme vous le souhaitez. Ceci est plus lent mais peut s'avérer utile lorsque vous souhaitez modifier beaucoup de choses dans une petite animation.
Voici un exemple illustrant cette approche "claire" :
import itertools
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# set parameters
frames = 10
points = 20
np.random.seed(42)
# create data
data = np.random.rand(points, 2)
# set how the graph will change each frame
sizes = itertools.cycle([10, 50, 150])
colors = np.random.rand(frames, points)
colormaps = itertools.cycle(['Purples', 'Blues', 'Greens', 'Oranges', 'Reds'])
markers = itertools.cycle(['o', 'v', '^', 's', 'p'])
# init the figure
fig, ax = plt.subplots(figsize=(5,5))
def update(i):
# clear the axis each frame
ax.clear()
# replot things
ax.scatter(data[:, 0], data[:, 1],
s=next(sizes),
c=colors[i, :],
cmap=next(colormaps),
marker=next(markers))
# reformat things
ax.set_xlabel('world')
ax.set_ylabel('hello')
ani = animation.FuncAnimation(fig, update, frames=frames, interval=500)
ani.save('scatter.gif', writer='pillow')
Les didacticiels de matplotlib et d'autres sources que j'ai vus ne semblent pas utiliser cette approche, mais j'ai vu d'autres personnes (ainsi que moi-même) la suggérer sur ce site. Je vois des avantages et des inconvénients, mais j'aimerais connaître l'avis des autres :
Pour
- Vous pouvez éviter d'utiliser le
set_...
méthodes pour le diagramme de dispersion (c'est-à-dire .set_offsets()
, .set_sizes()
...), qui ont une documentation plus obscure et moins détaillée ( bien que la réponse principale vous mènera très loin ici ! ). De plus, il existe différentes méthodes pour différents types de parcelles (par exemple, vous utilisez set_data
pour les lignes, mais pas pour les points de dispersion). En effaçant l'axe, vous déterminez les éléments tracés à chaque trame comme tout autre tracé dans matplotlib.
- Plus encore, il n'est pas clair si certaines propriétés sont
set
-tels que le type de marqueur ( comme commenté ) ou la carte des couleurs. Je ne saurais pas comment créer le graphique ci-dessus en utilisant la fonction ax.set_...
par exemple, en raison des changements de marqueurs et de cartes de couleurs. Mais c'est assez basique avec ax.scatter()
.
Cons
-
Il peut être beaucoup plus lent ; c'est-à-dire tout effacer et redessiner, semble être plus coûteux que les
set...
méthodes. Ainsi, pour les grandes animations, cette approche peut être assez pénible.
- L'effacement de l'axe efface également des éléments tels que les étiquettes d'axe, les limites d'axe, les autres textes, etc. Ces éléments de mise en forme doivent donc être inclus dans le processus d'effacement.
update
(sinon ils disparaîtront). Cela peut être gênant si vous souhaitez que certaines choses changent, mais que d'autres restent inchangées.
Bien sûr, la vitesse est un gros inconvénient. Voici un exemple qui montre la différence. Compte tenu de ces données :
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
np.random.seed(42)
frames = 40
x = np.arange(frames)
y = np.sin(x)
colors = itertools.cycle(['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])
data = [(np.random.uniform(-1, 1, 10) + x[i],
np.random.uniform(-1, 1, 10) + y[i])
for i in range(frames)]
Vous pouvez tracer en utilisant le set...
méthode :
fig, ax = plt.subplots()
s = ax.scatter([], [])
ax.set_xlim(-2, frames+2)
ax.set_ylim(min(y) - 1, max(y) + 1)
def update(i):
s.set_offsets(np.column_stack([data[i][0], data[i][1]]))
s.set_facecolor(next(colors))
ani = animation.FuncAnimation(fig, update, frames=frames, interval=100)
ani.save('set.gif', writer='pillow')
Ou la méthode "claire" :
fig, ax = plt.subplots()
def update(i):
ax.clear()
ax.scatter(data[i][0], data[i][1], c=next(colors))
ax.set_xlim(-2, frames+2)
ax.set_ylim(min(y) - 1, max(y) + 1)
ani = animation.FuncAnimation(fig, update, frames=frames, interval=100)
ani.save('clear.gif', writer='pillow')
Pour obtenir ce chiffre :
Utilisation de %%time
on peut voir que le nettoyage et le recollement prennent (plus de) deux fois plus de temps :
- pour
set...
: Wall time: 1.33 s
- pour être clair :
Wall time: 2.73 s
Jouez avec le frames
pour tester cela à différentes échelles. Pour les petites animations (moins d'images/données), la différence de temps entre les deux méthodes est sans conséquence (et pour moi, elle me fait parfois préférer la méthode de compensation). Mais pour les cas plus importants, l'utilisation de set_...
peut faire gagner beaucoup de temps.
3 votes
Il existe un exemple dans la documentation de matplotlib : Simulation de pluie .
0 votes
matplotlib : Simulation de pluie avec un lien mis à jour.