matplotlib.animation#

Animation#

Der einfachste Weg, eine Live-Animation in Matplotlib zu erstellen, ist die Verwendung einer der Animation-Klassen.

Inheritance diagram of matplotlib.animation.FuncAnimation, matplotlib.animation.ArtistAnimation

Animation

Eine Basisklasse für Animationen.

FuncAnimation

TimedAnimation Unterklasse, die eine Animation erstellt, indem sie wiederholt eine Funktion func aufruft.

ArtistAnimation

TimedAnimation Unterklasse, die eine Animation erstellt, indem sie eine feste Menge von Artist-Objekten verwendet.

In beiden Fällen ist es entscheidend, eine Referenz auf das Instanzobjekt zu behalten. Die Animation wird durch einen Timer (typischerweise vom Host-GUI-Framework) vorangetrieben, auf den das Animation-Objekt die einzige Referenz hält. Wenn Sie keine Referenz auf das Animation-Objekt halten, wird es (und damit die Timer) vom Garbage Collector aufgeräumt, was die Animation stoppt.

Um eine Animation zu speichern, verwenden Sie Animation.save, Animation.to_html5_video oder Animation.to_jshtml.

Siehe Writer-Klassen unten für Details, welche Filmformate unterstützt werden.

FuncAnimation#

Das Innenleben von FuncAnimation ist mehr oder weniger

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

mit Details zur Handhabung von 'Blitting' (zur dramatischen Verbesserung der Live-Leistung), zur Nicht-Blockierung, zur Vermeidung wiederholten Startens/Stoppens der GUI-Ereignisschleife, zur Handhabung von Wiederholungen, mehreren animierten Achsen und zum einfachen Speichern der Animation in einer Filmdatei.

'Blitting' ist eine Standardtechnik in der Computergrafik. Die allgemeine Idee ist, eine vorhandene Bitmap (in unserem Fall eine weitgehend gerasterte Figur) zu nehmen und dann einen weiteren Künstler darüber zu 'blittern'. Dadurch, dass wir eine gespeicherte 'saubere' Bitmap verwalten, können wir nur die wenigen Künstler neu zeichnen, die sich bei jedem Frame ändern, und möglicherweise erhebliche Zeit sparen. Wenn wir Blitting verwenden (durch Übergabe von blit=True), wird die Kernschleife von FuncAnimation etwas komplizierter

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)

Dies lässt natürlich viele Details aus (wie z. B. das Aktualisieren des Hintergrunds beim Ändern der Größe der Figur oder beim vollständigen Neuzeichnen). Dieses hoffentlich minimalistische Beispiel vermittelt jedoch ein Gefühl dafür, wie init_func und func innerhalb von FuncAnimation verwendet werden und die Theorie, wie 'Blitting' funktioniert.

Hinweis

Die Z-Reihenfolge von Künstlern wird beim 'Blitting' nicht berücksichtigt, da die 'geblitteten' Künstler immer oben gezeichnet werden.

Die erwartete Signatur von func und init_func ist sehr einfach, um FuncAnimation aus Ihrer Buchhaltungs- und Plotting-Logik herauszuhalten. Dies bedeutet jedoch, dass die von Ihnen übergebenen aufrufbaren Objekte wissen müssen, auf welche Künstler sie sich beziehen sollen. Es gibt mehrere Ansätze zur Handhabung dieses Problems, mit unterschiedlicher Komplexität und Kapselung. Der einfachste Ansatz, der in einem Skript recht gut funktioniert, ist die Definition des Künstlers im globalen Geltungsbereich und die Überlassung der Sortierung an Python. Zum Beispiel

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()

Die zweite Methode ist die Verwendung von functools.partial, um Argumente an die Funktion zu übergeben

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

fig, ax = plt.subplots()
line1, = ax.plot([], [], 'ro')

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

def update(frame, ln, x, y):
    x.append(frame)
    y.append(np.sin(frame))
    ln.set_data(x, y)
    return ln,

ani = FuncAnimation(
    fig, partial(update, ln=line1, x=[], y=[]),
    frames=np.linspace(0, 2*np.pi, 128),
    init_func=init, blit=True)

plt.show()

Eine dritte Methode ist die Verwendung von Closures zum Erstellen der erforderlichen Künstler und Funktionen. Eine vierte Methode ist die Erstellung einer Klasse.

Beispiele#

ArtistAnimation#

Beispiele#

Writer-Klassen#

Inheritance diagram of matplotlib.animation.FFMpegFileWriter, matplotlib.animation.FFMpegWriter, matplotlib.animation.ImageMagickFileWriter, matplotlib.animation.ImageMagickWriter, matplotlib.animation.PillowWriter, matplotlib.animation.HTMLWriter

Die bereitgestellten Writer lassen sich in wenige Hauptkategorien einteilen.

Der Pillow-Writer verwendet die Pillow-Bibliothek zum Schreiben der Animation und hält alle Daten im Speicher.

Der HTML-Writer generiert JavaScript-basierte Animationen.

HTMLWriter

Writer für JavaScript-basierte HTML-Filme.

Die Pipe-basierten Writer streamen die aufgenommenen Frames über eine Pipe an einen externen Prozess. Die Pipe-basierten Varianten sind tendenziell performanter, funktionieren aber möglicherweise nicht auf allen Systemen.

FFMpegWriter

Pipe-basierter ffmpeg-Writer.

ImageMagickWriter

Pipe-basierter animierter GIF-Writer.

Die dateibasierten Writer speichern temporäre Dateien für jeden Frame, die am Ende zu einer einzigen Datei zusammengefügt werden. Obwohl langsamer, sind diese Writer leichter zu debuggen.

FFMpegFileWriter

Dateibasierter ffmpeg-Writer.

ImageMagickFileWriter

Dateibasierter animierter GIF-Writer.

Die Writer-Klassen bieten eine Möglichkeit, sequentielle Frames von derselben zugrunde liegenden Figure zu erfassen. Sie alle bieten drei Methoden, die nacheinander aufgerufen werden müssen

  • setup bereitet den Writer vor (z. B. das Öffnen einer Pipe). Pipe-basierte und dateibasierte Writer nehmen unterschiedliche Argumente für setup() entgegen.

  • grab_frame kann dann beliebig oft aufgerufen werden, um einen einzelnen Frame auf einmal zu erfassen

  • finish schließt den Film ab und schreibt die Ausgabedatei auf die Festplatte.

Beispiel

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

Wenn Sie die Writer-Klassen direkt verwenden (nicht über Animation.save), wird dringend empfohlen, den saving Kontextmanager zu verwenden

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

um sicherzustellen, dass Einrichtung und Bereinigung nach Bedarf durchgeführt werden.

Beispiele#

Hilfsklassen#

Animation-Basisklassen#

Animation

Eine Basisklasse für Animationen.

TimedAnimation

Animation Unterklasse für zeitbasierte Animation.

Writer-Registrierung#

Eine Modul-weite Registrierung wird bereitgestellt, um zwischen dem Namen des Writers und der Klasse abzubilden, damit ein String an Animation.save übergeben werden kann, anstatt einer Writer-Instanz.

MovieWriterRegistry

Registrierung verfügbarer Writer-Klassen nach menschenlesbarem Namen.

Writer-Basisklassen#

Um Code-Duplizierung zu reduzieren, Basisklassen

AbstractMovieWriter

Abstrakte Basisklasse für das Schreiben von Filmen, die eine Möglichkeit bietet, Frames durch Aufrufen von grab_frame zu erfassen.

MovieWriter

Basisklasse für das Schreiben von Filmen.

FileMovieWriter

MovieWriter zum Schreiben in einzelne Dateien und Zusammenfügen am Ende.

und Mixins

FFMpegBase

Mixin-Klasse für FFMpeg-Ausgabe.

ImageMagickBase

Mixin-Klasse für ImageMagick-Ausgabe.

werden bereitgestellt.

Sehen Sie sich den Quellcode an, um leicht neue MovieWriter-Klassen zu implementieren.