matplotlib.animation#

Animation #

Le moyen le plus simple de créer une animation en direct dans Matplotlib consiste à utiliser l'une des Animationclasses.

Diagramme d'héritage de matplotlib.animation.FuncAnimation, matplotlib.animation.ArtistAnimation

Animation

Une classe de base pour les animations.

FuncAnimation

Crée une animation en appelant à plusieurs reprises une fonction func .

ArtistAnimation

Animation utilisant un ensemble fixe d' Artistobjets.

Dans les deux cas, il est essentiel de conserver une référence à l'objet instance. L'animation est avancée par une minuterie (généralement du framework GUI hôte) auquel l' Animationobjet détient la seule référence. Si vous ne détenez pas de référence à l' Animationobjet, celui-ci (et donc les minuteurs) sera ramassé, ce qui arrêtera l'animation.

Pour enregistrer une animation, utilisez Animation.save, Animation.to_html5_videoou Animation.to_jshtml.

Voir Classes d'assistance ci-dessous pour plus de détails sur les formats de film pris en charge.

FuncAnimation#

Le fonctionnement interne de FuncAnimationest plus ou moins :

for d in frames:
    artists = func(d, *fargs)
    fig.canvas.draw_idle()
    fig.canvas.start_event_loop(interval)

avec des détails pour gérer le "blitter" (pour améliorer considérablement les performances en direct), pour ne pas bloquer, ne pas démarrer/arrêter à plusieurs reprises la boucle d'événements de l'interface graphique, gérer les répétitions, plusieurs axes animés et enregistrer facilement l'animation dans un fichier vidéo.

Le 'Blitting' est une technique standard en infographie. L'essentiel est de prendre une image bitmap existante (dans notre cas, une figure principalement pixellisée), puis de "blit" un autre artiste par-dessus. Ainsi, en gérant un bitmap « propre » sauvegardé, on ne peut redessiner que les quelques artistes qui changent à chaque image et éventuellement gagner un temps considérable. Lorsque nous utilisons le blitting (en passant blit=True), la boucle centrale de FuncAnimationdevient un peu plus compliquée :

ax = fig.gca()

def update_blit(artists):
    fig.canvas.restore_region(bg_cache)
    for a in artists:
        a.axes.draw_artist(a)

    ax.figure.canvas.blit(ax.bbox)

artists = init_func()

for a in artists:
   a.set_animated(True)

fig.canvas.draw()
bg_cache = fig.canvas.copy_from_bbox(ax.bbox)

for f in frames:
    artists = func(f, *fargs)
    update_blit(artists)
    fig.canvas.start_event_loop(interval)

Cela laisse bien sûr de côté de nombreux détails (comme la mise à jour de l'arrière-plan lorsque la figure est redimensionnée ou entièrement redessinée). Cependant, cet exemple, espérons-le, minimaliste, donne une idée de la façon dont init_func et funcsont utilisés à l'intérieur de FuncAnimationet de la théorie du fonctionnement du « blitting ».

La signature attendue sur funcet init_funcest très simple à garder FuncAnimationen dehors de votre logique de comptabilité et de traçage, mais cela signifie que les objets appelables que vous transmettez doivent savoir sur quels artistes ils doivent travailler. Il existe plusieurs approches pour gérer cela, de complexité et d'encapsulation variables. L'approche la plus simple, qui fonctionne assez bien dans le cas d'un script, consiste à définir l'artiste dans une portée globale et à laisser Python régler les choses. Par exemple

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = ax.plot([], [], 'ro')

def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return ln,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    return ln,

ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init, blit=True)
plt.show()

La deuxième méthode consiste à utiliser functools.partialpour « lier » les artistes à la fonction. Une troisième méthode consiste à utiliser des fermetures pour constituer les artistes et les fonctions nécessaires. Une quatrième méthode consiste à créer une classe.

Exemples #

ArtistAnimation#

Exemples #

Cours d'écrivain #

Diagramme d'héritage de matplotlib.animation.FFMpegFileWriter, matplotlib.animation.FFMPegWriter, matplotlib.animation.ImageMagickFileWriter, matplotlib.animation.ImageMagickWriter, matplotlib.animation.PillowWriter, matplotlib.animation.HTMLWriter

Les écrivains fournis se répartissent en quelques grandes catégories.

L'écrivain Pillow s'appuie sur la bibliothèque Pillow pour écrire l'animation, en gardant toutes les données en mémoire.

PillowWriter

Le rédacteur HTML génère des animations basées sur JavaScript.

HTMLWriter

Écrivain pour les films HTML basés sur JavaScript.

Les rédacteurs basés sur un canal diffusent les images capturées via un canal vers un processus externe. Les variantes basées sur des tuyaux ont tendance à être plus performantes, mais peuvent ne pas fonctionner sur tous les systèmes.

FFMpegWriter

Écrivain ffmpeg basé sur un tube.

ImageMagickWriter

Gif animé basé sur des tuyaux.

Les écrivains basés sur des fichiers enregistrent des fichiers temporaires pour chaque image qui sont assemblés en un seul fichier à la fin. Bien que plus lents, ces écrivains peuvent être plus faciles à déboguer.

FFMpegFileWriter

Écrivain ffmpeg basé sur des fichiers.

ImageMagickFileWriter

Éditeur de gifs animés basé sur des fichiers.

Les classes d'écriture fournissent un moyen de récupérer des images séquentielles à partir du même fichier Figure. Ils fournissent tous trois méthodes qui doivent être appelées dans l'ordre :

  • setupprépare l'écrivain (par exemple ouvrir une pipe). Les rédacteurs basés sur des tubes et basés sur des fichiers prennent des arguments différents pour setup().

  • grab_framepeut ensuite être appelé aussi souvent que nécessaire pour capturer une seule image à la fois

  • finishfinalise le film et écrit le fichier de sortie sur le disque.

Exemple:

moviewriter = MovieWriter(...)
moviewriter.setup(fig, 'my_movie.ext', dpi=100)
for j in range(n):
    update_figure(j)
    moviewriter.grab_frame()
moviewriter.finish()

Si vous utilisez les classes d'écriture directement (et non via Animation.save), il est fortement recommandé d'utiliser le savinggestionnaire de contexte :

with moviewriter.saving(fig, 'myfile.mp4', dpi=100):
    for j in range(n):
        update_figure(j)
        moviewriter.grab_frame()

pour s'assurer que la configuration et le nettoyage sont effectués selon les besoins.

Exemples #

Classes d'aide #

Classes de base d'animation #

Animation

Une classe de base pour les animations.

TimedAnimation

Animationsous-classe pour l'animation basée sur le temps.

Numéro de registre de l'écrivain

Un registre au niveau du module est fourni pour établir une correspondance entre le nom de l'écrivain et la classe afin de permettre à une chaîne d'être transmise à la Animation.saveplace d'une instance d'écrivain.

MovieWriterRegistry

Registre des classes d'écrivains disponibles par nom lisible par l'homme.

Classes de base de l'écrivain #

Pour réduire les classes de base de duplication de code

AbstractMovieWriter

Classe de base abstraite pour écrire des films, fournissant un moyen de saisir des images en appelant grab_frame.

MovieWriter

Classe de base pour écrire des films.

FileMovieWriter

MovieWriterpour écrire dans des fichiers individuels et assembler à la fin.

et mixins

FFMpegBase

Classe Mixin pour la sortie FFMpeg.

ImageMagickBase

Classe Mixin pour la sortie ImageMagick.

sont prévus.

Voir le code source pour savoir comment implémenter facilement de nouvelles MovieWriterclasses.