matplotlib.animation
Содержание
Анимация
Самый простой способ создать живую анимацию в Matplotlib — использовать один из классов Animation.
Базовый класс для анимаций. | |
Подкласс | |
Подкласс |
В обоих случаях крайне важно сохранить ссылку на объект экземпляра. Анимация продвигается таймером (обычно из хост-фреймворка GUI), и объект 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
Примеры
Классы Writer
Предоставленные писатели относятся к нескольким широким категориям.
Пишущий 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 вместо экземпляра писателя.
Регистр доступных классов писателей по удобочитаемым именам. |
Базовые классы писателей
Для сокращения дублирования кода предоставляются базовые классы
Абстрактный базовый класс для записи фильмов, предоставляющий способ захвата кадров путем вызова | |
Базовый класс для записи фильмов. | |
|
и миксины
Mixin-класс для вывода FFMpeg. | |
Mixin-класс для вывода ImageMagick. |
См. исходный код для простого внедрения новых MovieWriter классов.
© 2012–2023 Matplotlib Development Team. All rights reserved.
Licensed under the Matplotlib License Agreement.
https://matplotlib.org/3.8.4/api/animation_api.html