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 и теории работы «блека».
Примечание
Порядок z объектов не учитывается при «блеке», так как «блекнутые» объекты всегда рисуются поверх.
Ожидаемая подпись для 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
Примеры
Классы записи
Предоставленные классы записи можно разделить на несколько основных категорий.
Класс PillowWriter использует библиотеку Pillow для записи анимации, сохраняя все данные в памяти.
Класс HTMLWriter генерирует анимации на основе 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/3.7.5/api/animation_api.html