Анимация — это интересный способ демонстрации того или иного феномена. Мы, люди, всегда приходим в восторг от анимированных и интерактивных диаграмм, а не от статических. Применение анимации также может быть отличной идеей при необходимости продемонстрировать временные отрезки, таких как цены на акции за прошедшие годы, изменение климата за последнее десятилетие, сезонность и тенденции, так проще увидеть, как конкретный параметр ведет себя со временем.
Изображение выше — симуляция дождя, которая была выполнена при помощи библиотеки Matplotlib, известной как праотец пакетов визуализации в Python. Matplotlib симулирует капли дождя на поверхности, анимируя масштаб и непрозрачность 50 точек рассеяния. Сегодня Python может похвастаться большим количеством мощных инструментов, таких как Plotly, Bokeh и Altair. Эти библиотеки могут довести анимацию и интерактив до уровня искусства. Впрочем, цель данной статьи — осветить один аспект этой библиотеки, который слабо исследован. Мы поговорим непосредственно об анимации и о способах ее создать.
Обзор Matplotlib
Matplotlib — это библиотека Python для работы с 2D графиками, которая является одной из самых популярных. Большинство начинают свой путь визуализации данных именно с этой библиотекой. Matplotlib может генерировать графики, гистограммы, спектры мощности, диаграммы ошибок и рассеяния. Он также легко интегрируется с такими библиотеками как Pandas и Seaborn для создания более сложных визуализаций.
Рассмотрим ключевые особенности matplotlib:
- Он собран на подобии MATLAB, так что переключатся между ними очень легко.
- Наличие большого количество бэкендов для рендеринга.
- Возможность создавать практически любые графики.
- Существует уже более десяти лет, так что в наличии огромная пользовательская база.
Впрочем, существуют области, где Matplotlib не настолько хорош, как его коллеги.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
- Matplotlib имеет императивный API, который часто чересчур многословен.
- Встречаются слабые настройки стилей.
- Слабая поддержка для веб и интерактивных графиков.
- Зачастую работает медленно с большими и сложными данными.
Если вы хотите освежить память — на Datacamp есть шпаргалка по Matplotlib, которой вы можете воспользоваться: https://s3.amazonaws.com/assets.datacamp.com/blog_assets/Python_Matplotlib_Cheat_Sheet.pdf
Анимация в matplotlib Python
Базовый класс Matplotlib под названием animation
занимается вопросом анимации. Он предоставляет структуру, вокруг которой строится функционал создаваемой анимации. Для этих целей существуют два основных интерфейса, которые используют:
- FuncAnimation — создает анимацию путем повторяющегося вызова функции
func
. - ArtistAnimation — анимация, использующая фиксированный набор объектов
Artist
.
Впрочем, из этих двоих, предпочтение чаще отдают FuncAnimation
благодаря удобному использованию. Вы можете узнать о них больше в документации, так как дальше мы будем работать именно с FuncAnimation
.
Требования
- Модули, включая numpy и
matplotlib
, должны быть установлены. - Для сохранения анимации в вашей системе в форматах mp4 или gif, нужно установить
ffmpeg
илиimagemagick
.
1 2 3 4 5 6 |
pip3 install numpy pip3 install matplotlib # Установка библиотек sudo apt install ffmpeg sudo apt install imagemagick |
После этого, мы можем начать нашу первую базовую анимацию в Jupyter Notebooks. Код для этой статьи может быть получен из репозитория на Github: https://github.com/parulnith/Animations-with-Matplotlib
Простая анимация: движущаяся синусоида
Давайте используем FuncAnimation
для создания простой анимации синусоиды, движущейся по экрану. Исходный код для анимации был взят из руководства Matplotlib Animation. Для начала, изучим выдачу, а затем код, чтобы понять, что происходит.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import numpy as np from matplotlib import pyplot as plt from matplotlib.animation import FuncAnimation plt.style.use('seaborn-pastel') fig = plt.figure() ax = plt.axes(xlim=(0, 4), ylim=(-2, 2)) line, = ax.plot([], [], lw=3) def init(): line.set_data([], []) return line, def animate(i): x = np.linspace(0, 4, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return line, anim = FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True) anim.save('sine_wave.gif', writer='imagemagick') |
- В строках 7-9 мы просто создаем фигуру с одной осью. Затем мы создаем наш пустой объект строки, который по сути будет модифицирован в анимации. Объект
line
будет заполнен данными в дальнейшем. - В строках 11-13 мы создаем функцию
init
, которая будет отвечать за осуществление анимации. Функцияinit
инициализирует данные, а также указывае лимит осей. - В строках 14-18 мы наконец определяем функцию анимации, которая принимает фрейм
number(i)
в качестве параметра и создает синусоиду (или любую другую анимацию), которая сдвигается в зависимости от значенияi
. Функция здесь возвращает кортеж объектов графика, который был модифицирован, и говорит фреймворку анимации, какие части графика должны быть анимированы. - В строке 20 мы создаем наш объект анимации. Параметр
blit
гарантирует, что будут перерисованы только те части графика, которые были изменены.
Это основное понимание того, что стоит за созданием анимации в Matplotlib. Выполняя небольшие изменения в коде, можно добиться интересных визуализаций. Давайте рассмотрим несколько из них.
Спираль в matplotlib
Таким же образом мы можем воспользоваться отличным примером создания фигур от GeeksforGeeks. Давайте создадим движущуюся спираль, которая медленно вращается при помощи класса animation
библиотеки matplotlib. Код весьма похож на код синусоиды с небольшими поправками.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np plt.style.use('dark_background') fig = plt.figure() ax = plt.axes(xlim=(-50, 50), ylim=(-50, 50)) line, = ax.plot([], [], lw=2) # Функция инициализации. def init(): # создение пустого графа. line.set_data([], []) return line, xdata, ydata = [], [] # функция анимации def animate(i): t = 0.1 * i # x, y данные на графике x = t * np.sin(t) y = t * np.cos(t) # добавление новых точек в список точек осей x, y xdata.append(x) ydata.append(y) line.set_data(xdata, ydata) return line, # Заголовок анимации plt.title('Создаем спираль в matplotlib') # Скрываем лишние данные plt.axis('off') # Вызов анимации. anim = animation.FuncAnimation(fig, animate, init_func=init, frames=500, interval=20, blit=True) # Сохраняем анимацию как gif файл anim.save('coil.gif', writer='imagemagick') |
Обновляемые графики в matplotlib
Обновляемые графики могут понадобиться, когда дело доходит до построения динамических величин, таких как данные о стоках, данные датчиков, и другие нестационарные данные. Мы построим простой график, который автоматически будет обновляться с появлением новых данных в системе.
Давайте составим график стоковых цен за месяц в гипотетической компании.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import matplotlib.pyplot as plt import matplotlib.animation as animation plt.style.use('dark_background') fig = plt.figure() ax1 = fig.add_subplot(1, 1, 1) def animate(i): data = open('stock.txt', 'r').read() lines = data.split('\n') xs = [] ys = [] for line in lines: x, y = line.split(',') # Отделяем дату от цены xs.append(x) ys.append(float(y)) ax1.clear() ax1.plot(xs, ys) plt.xlabel('Дата') plt.ylabel('Цена') plt.title('Обновляемые графики в matplotlib') ani = animation.FuncAnimation(fig, animate, interval=1000) plt.show() |
Теперь, откроем терминал и запустим наш код. Вы получите график, наподобие того, что находится внизу, который будет автоматически обновляться:
Здесь интервал длится 1000 миллисекунд, или одну секунду.
Анимирование 3D графика в matplotlib
Создание трехмерных графиков — обычное дело, но что если мы попробуем анимировать угол обзора таких графиков? Суть в изменении угла обзора камеры и использовать каждое итоговое изображение для создания анимации. Есть хороший раздел, посвященный данному вопросу в Python Graph Gallery.
Создайте папку под названием frames в том же каталоге, где расположен notebook. Все изображения будут храниться в этой папке, а затем будут использованы в анимации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt import pandas as pd # Скачиваем данные для графика. url = 'https://python-scripts.com/wp-content/uploads/2019/3d-data.csv' data = pd.read_csv(url) # Преобразуем его в длинный формат df = data.unstack().reset_index() df.columns=["X", "Y", "Z"] # Переименовываем старые названия столбцов в числовой формат. df['X'] = pd.Categorical(df['X']) df['X'] = df['X'].cat.codes # Мы собираемся сделать 20 графиков, для 20 разных углов for angle in range(70, 210, 2): fig = plt.figure() ax = fig.gca(projection='3d') ax.plot_trisurf(df['Y'], df['X'], df['Z'], cmap=plt.cm.viridis, linewidth=0.2) ax.view_init(30, angle) filename = 'frames/step'+str(angle)+'.png' plt.savefig(filename, dpi=96) plt.gca() |
Так мы создадим несколько файлов PNG в папке frames. Теперь, используем ImageMagick для трансформации изображений в анимацию. Открываем терминал и переходим к папке frames
и вводим следующую команду:
1 |
convert -delay 10 step*.png animated_3d.gif |
Анимация и модуль Celluloid
Celluloid — это модуль Python, который упрощает процесс создания анимаций в matplotlib. Эта библиотека создает фигуру matplotlib и создает из нее камеру. Далее она снова использует фигуру, и по мере создания каждого кадра, делает скриншот нашей камерой. Наконец, анимация создается со всеми сохраненными кадрами.
Установка:
1 |
pip3 install celluloid |
Несколько примеров использования модуля Celluloid.
Минимум
1 2 3 4 5 6 7 8 9 10 11 12 |
from matplotlib import pyplot as plt from celluloid import Camera fig = plt.figure() camera = Camera(fig) for i in range(10): plt.plot([i] * 10) camera.snap() animation = camera.animate() animation.save('celluloid_minimal.gif', writer = 'imagemagick') |
Подграфики
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import numpy as np from matplotlib import pyplot as plt from celluloid import Camera fig, axes = plt.subplots(2) camera = Camera(fig) t = np.linspace(0, 2 * np.pi, 128, endpoint=False) for i in t: axes[0].plot(t, np.sin(t + i), color='blue') axes[1].plot(t, np.sin(t - i), color='blue') camera.snap() animation = camera.animate() animation.save('celluloid_subplots.gif', writer = 'imagemagick') |
Легенды
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import matplotlib from matplotlib import pyplot as plt from celluloid import Camera fig = plt.figure() camera = Camera(fig) for i in range(20): t = plt.plot(range(i, i + 5)) plt.legend(t, [f'line {i}']) camera.snap() animation = camera.animate() animation.save('celluloid_legends.gif', writer = 'imagemagick') |
Подведем итоги
Анимации помогают осветить определенные аспекты визуализации, которые никак не могут быть связаны со статическими графиками. Также стоит упомянуть то, что излишнее и бессмысленное использование визуализаций может усложнить работу. Каждая функция в визуализации данных должна использоваться разумно, чтобы получился лучший эффект.
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»