matplotlib.animation
Оглавление
Анимация
Самый простой способ создать живую анимацию в Matplotlib — использовать один из классов Animation.
См. также
Базовый класс для анимаций. | |
Подкласс | |
Подкласс |
В обоих случаях крайне важно сохранить ссылку на экземпляр объекта. Анимация обновляется таймером (обычно из фреймворка графического интерфейса), к которому у объекта Animation есть единственная ссылка. Если вы не сохраняете ссылку на объект Animation, он (и, следовательно, таймеры) будут удалены сборщиком мусора, что остановит анимацию.
Для сохранения анимации используйте Animation.save, Animation.to_html5_video или Animation.to_jshtml.
Подробные сведения о поддерживаемых форматах видео см. ниже в разделе Вспомогательные классы.
FuncAnimation
Внутренняя работа FuncAnimation выглядит примерно так:
for d in frames:
artists = func(d, *fargs)
fig.canvas.draw_idle()
fig.canvas.start_event_loop(interval)
с подробностями по обработке «блиттинга» (для существенного повышения производительности в режиме реального времени), чтобы она была асинхронной, не вызывала повторного запуска/остановки цикла событий GUI, обрабатывала повторы, несколько осей анимации и позволяла легко сохранять анимацию в файл видео.
«Блиттинг» — это стандартный метод в компьютерной графике. В общем случае он заключается в использовании существующей битовой карты (в нашем случае, в основном растрового изображения) и «блиттинга» ещё одного объекта поверх неё. Таким образом, управляя сохранённой «чистой» битовой картой, мы можем перерисовывать только те немногие объекты, которые изменяются в каждом кадре, что потенциально экономит значительное время. Когда мы используем блиттинг (передав blit=True), основной цикл FuncAnimation становится немного сложнее:
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)
Конечно, это опускает множество деталей (например, обновление фона при изменении размера фигуры или полном перерисовке). Однако, надеемся, этот минимальный пример даёт представление о том, как init_func и func используются внутри FuncAnimation и о принципах работы «блиттинга».
Примечание
При «блиттинге» порядок zorder объектов не учитывается, так как «блиттированные» объекты всегда выводятся поверх.
Ожидаемая сигнатура для func и init_func очень проста, чтобы FuncAnimation не входила в ваш учёт и логику построения графиков. Однако это означает, что вызываемые объекты, которые вы передаёте, должны знать, на каких объектах они должны работать. Существует несколько подходов к этому с разной сложностью и инкапсуляцией. Самый простой подход, который работает довольно хорошо в случае сценария, заключается в определении объекта на глобальном уровне и предоставлении Python возможности решить эту задачу. Например:
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()
Второй метод заключается в использовании functools.partial для передачи аргументов в функцию:
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()
Третий метод — использование замыканий для построения необходимых объектов и функций. Четвёртый метод — создание класса.
Примеры
ArtistAnimation
Примеры
Классы записи
Предоставленные классы записи делятся на несколько широких категорий.
Класс Pillow опирается на библиотеку Pillow для записи анимации, сохраняя все данные в памяти.
Класс HTML генерирует анимации на основе JavaScript.
Запись для JavaScript-анимаций HTML-фильмов. |
Классы записи, основанные на каналах, передают захваченные кадры через канал во внешний процесс. Варианты, основанные на каналах, обычно более производительны, но могут не работать на всех системах.
Запись ffmpeg, основанная на каналах. | |
Запись анимированного GIF, основанная на каналах. |
Классы записи, основанные на файлах, сохраняют временные файлы для каждого кадра, которые склеиваются в один файл в конце. Несмотря на более медленную работу, эти классы записи могут быть проще для отладки.
Запись ffmpeg, основанная на файлах. | |
Запись анимированного GIF, основанная на файлах. |
Классы записи обеспечивают способ получения последовательных кадров из того же базового Figure. Все они предоставляют три метода, которые необходимо вызывать последовательно:
-
setupподготавливает запись (например, открывает канал). Классы записи, основанные на каналах и файлах, принимают разные аргументы дляsetup(). -
grab_frameможно вызывать столько раз, сколько нужно, для захвата одного кадра за раз -
finishзавершает фильм и записывает выходной файл на диск.
Пример:
moviewriter = MovieWriter(...)
moviewriter.setup(fig, 'my_movie.ext', dpi=100)
for j in range(n):
update_figure(j)
moviewriter.grab_frame()
moviewriter.finish()
Если вы используете классы записи непосредственно (а не через Animation.save), настоятельно рекомендуется использовать контекстный менеджер saving:
with moviewriter.saving(fig, 'myfile.mp4', dpi=100):
for j in range(n):
update_figure(j)
moviewriter.grab_frame()
чтобы гарантировать выполнение необходимой настройки и очистки.
Примеры
Вспомогательные классы
Базовые классы анимации
Базовый класс для анимаций. | |
Подкласс |
Регистр записи
Для сопоставления имени записи с классом предоставлен реестр на уровне модуля, чтобы разрешить передачу строки в Animation.save вместо экземпляра записи.
Реестр доступных классов записи по удобочитаемым именам. |
Базовые классы записи
Для сокращения дублирования кода предоставляются базовые классы
Абстрактный базовый класс для записи фильмов, обеспечивающий способ захвата кадров вызовом | |
Базовый класс для записи фильмов. | |
|
и миксины
Миксин-класс для вывода FFMpeg. | |
Миксин-класс для вывода ImageMagick. |
предоставлены.
См. исходный код, чтобы узнать, как легко реализовать новые MovieWriter классы.
© 2012–2023 Matplotlib Development Team. All rights reserved.
Licensed under the Matplotlib License Agreement.
https://matplotlib.org/stable/api/animation_api.html