Il y a deux façons de créer une animation avec matplotlib: matplotlib.animation.ArtistAnimation
et matplotlib.animation.FuncAnimation
. ʻArtistAnimationest plus facile et vous pouvez le créer comme vous le souhaitez. Cependant, il y avait un problème parce que c'était lourd car tous les éléments ont été créés à l'avance et conservés en mémoire.
FuncAnimation` semble être plus léger car il est généré séquentiellement, mais je ne comprends pas bien le comportement et c'est toujours gênant J'ai écrit les images du numéro de série et les ai converties en mp4 plus tard. J'ai donc étudié avec beaucoup d'efforts pour les comprendre et les utiliser. Ceci est une note de synthèse.
Vous pouvez créer une animation en passant les informations nécessaires à la création de l'animation à matplotlib.animation.FuncAnimation
, donc ce que vous devez comprendre ce sont ses arguments et le comportement de cette fonction.
Les deux premiers arguments sont obligatoires et vous définirez généralement les arguments frames
, ʻinterval` en plus d'eux.
func
, est le sujet principal. Nous le verrons en détail dans la prochaine mesure.frames
est un itérateur qui produit l'équivalent du" nom "de chaque image, par exemple en passant range (128) ʻou
np.linspace (0, 2 * np.pi, 128)`. Dans ce cas, les deux créent une animation avec 128 images.FuncAnimation
L'idée de FuncAnimation
est résumée dans l'exemple de code suivant (extrait de API doc)
for d in frames:
artists = func(d, *fargs)
fig.canvas.draw_idle()
fig.canvas.start_event_loop(interval)
Autrement dit, tournez l'itérateur frames
, passez chaque" nom de trame " d
à la fonction func
, et dessinez le ʻartist retourné. Après ce temps ʻinterval
, frames
se termine. Répétez jusqu'à ce que vous le fassiez.
Alors faisons-le maintenant. Créons une animation du point P qui se déplace de 0, 1, 2, ... sur l'axe des X. Mettons simplement ce que nous venons d'apprendre dans le code. Qu'il sera?
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure()
ax = fig.add_subplot(111)
def update(frame):
ax.plot(frame, 0, "o")
anim = FuncAnimation(fig, update, frames=range(8), interval=1000)
anim.save("c01.gif", writer="imagemagick") #Si vous voulez l'afficher sur l'écran plt.show()Est bon
plt.close()
Cliquez ici pour les résultats.
Ce n'est pas ce que je voulais. Ce qui est différent, c'est que la position passée du point P dessiné dans l'image précédente est toujours dessinée. Pour résoudre ce problème, ʻupdate` Il semble que tous les éléments écrits en axes doivent être effacés au début de la fonction.
Voici donc le code modifié et les résultats de l'exécution.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure()
ax = fig.add_subplot(111)
def update(frame):
ax.cla() #Hache claire
ax.plot(frame, 0, "o")
anim = FuncAnimation(fig, update, frames=range(8), interval=1000)
anim.save("c02.gif", writer="imagemagick")
plt.close()
L'animation a été réalisée comme prévu.
Notez que l'appel ʻax.cla () efface l'étiquette d'axe ʻax.set_xlabel ()
, les lignes de grille ʻax.grid () , la plage de dessin ʻax.set_xlim ()
, etc. Vous devez reconfigurer après avoir lu ʻax.cla () `.
Dans l'exemple ci-dessus, tout le contenu du dessin a été effacé à chaque image, mais je pense que vous voulez souvent effacer uniquement certains artistes. Par exemple, l'exemple suivant est un point qui se déplace sur le cercle unité P Bien que ce soit une animation de, cela semble inutile car je dessine une grille et un cercle unitaire à chaque fois.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure()
ax = fig.add_subplot(111, aspect=1)
theta = np.linspace(0, 2*np.pi, 128)
def update(f):
ax.cla() #Hache claire
ax.grid()
ax.plot(np.cos(theta), np.sin(theta), c="gray")
ax.plot(np.cos(f), np.sin(f), "o", c="red")
anim = FuncAnimation(fig, update, frames=np.pi*np.arange(0,2,0.25), interval=200)
anim.save("c03.gif", writer="imagemagick")
plt.close()
Dans ce cas, au lieu de tout effacer, vous pouvez atteindre votre objectif en supprimant explicitement l'artiste que vous souhaitez effacer.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure()
ax = fig.add_subplot(111, aspect=1)
theta = np.linspace(0, 2*np.pi, 128)
p = []
ax.grid()
ax.plot(np.cos(theta), np.sin(theta), c="gray")
def update(f):
if len(p) > 0:
item = p.pop(0)
ax.lines.remove(item)
p.append( ax.plot([np.cos(f)], [np.sin(f)], "o", c="red")[0] )
anim = FuncAnimation(fig, update, frames=np.pi*np.arange(0,2,0.25), interval=200)
anim.save("c03.gif", writer="imagemagick")
plt.close()
Cependant, je ne sais pas lequel de ces deux exemples est le meilleur en termes de vitesse de dessin, bien qu'il semble préférable de l'utiliser avec blit = True
dans l'argument FuncAnimation.
Si vous utilisez plt.cla ()
pour effacer le contenu du dessin, cela a la même signification que ʻax.cla () (ʻax
sont les axes que vous avez touchés immédiatement avant), donc plusieurs sous-tracés. Les animations avec ont des sous-tracés qui ne parviennent pas à effacer ce qui est affiché. Pour tous les axes, ʻax.cla () `.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure()
axs = [
fig.add_subplot(121),
fig.add_subplot(122, aspect=1),
]
theta = np.linspace(0, 4*np.pi, 128)
def update(f):
for ax in axs:
ax.cla() #Hache claire
ax.grid()
axs[0].set_xlim([0, 4*np.pi])
axs[0].plot(theta, np.cos(theta - f), c="blue")
axs[0].plot(0, np.cos(f), "o", c="blue")
axs[1].plot(np.cos(theta), np.sin(theta), c="gray")
axs[1].plot(np.cos(f), np.sin(f), "o", c="blue")
axs[1].plot(np.cos(f), 0 , "o", c="blue")
axs[1].plot([np.cos(f), np.cos(f)], [0, np.sin(f)], c="blue")
anim = FuncAnimation(fig, update, frames=np.pi*np.arange(0,2,0.1), interval=200)
anim.save("c04.gif", writer="imagemagick")
plt.close()
Recommended Posts