Время прочтения: 5 мин.

Анимация построения графиков в Matplotlib может быть реализована несколькими способами. В данном посте рассмотрю два из них:

  • первый способ заключается в объединении кадров в анимационный файл;
  • второй способ использует функции matplotlib.animation.FuncAnimation

Для начала создам датасет с абстрактными данными, который буду использовать для визуализации работы анимации. Так как при работе с набором данных чаще всего используют Pandas DataFrame, то и генерацию данных осуществлю непосредственно в нём.

# импортируем необходимые для генерации DataFrame библиотеки 
import pandas as pd # версия 1.1.5
import numpy as np # версия 1.18.5
import random
# объявляем «переменные»
df = pd.DataFrame()
max_sum  = 2000
stroki = 50 # количество строк в DataFrame
# генерируем дата сет в DataFrame
df['sum'] = np.random.choice(range(100, max_sum),stroki)
df['count'] = np.random.choice(range(1,20),stroki)
df['avg_sum'] = round(df['sum']/df['count'],1)
# Посмотрим содержимое DataFrame
df.head()
	sum	count	avg_sum
0	157	38	4.1
1	407	37	11.0
2	461	146	3.2
3	1277	190	6.7
4	1345	58	23.2

На выходе получаю DataFrame, содержащий три столбца и пятьдесят строк. При работе с реальными данными можно осуществить импорт данных в DataFrame из файлов или использовать готовый DataFrame.

Сохраню полученный DataFrame в CSV файл для использования во втором способе анимации.

# импортируем библиотеки для работы с файловой системой
import glob
import os
import shutil
# запоминаем текущую папку
path_script = os.getcwd()
# сохраним полученный датасет для использования во втором способе
df.to_csv(path_script + '/dataset.csv', index = False)

После создания / импорта датасета приступлю непосредственно к анимированию.

Первый способ заключается в генерации файлов (кадров) в графическом формате и их дальнейшем объединении в анимированный файл. Далее перехожу к генерации кадров:

# импортируем необходимые библиотеки для генерации кадров 
import moviepy.editor as mpy # версия 1.0.3
import matplotlib.pyplot as plt #3.3.4
# при необходимости импортируем библиотеки
pip install moviepy
# задаем имя папки, в которую будем складывать кадры
dir_name = 'pngs' 
# создаем папку, в которую будем складывать кадры
os.mkdir(os.path.join(path_script, dir_name))
# задаем имя файла анимации
gif_name = 'anim_var1.gif'
# в цикле бежим по DataFrame, отрисовываем графики и сохраняем кадры
for i in range(0,len(df.index)):
    # задаем:
    # столбцы DateFrame, из которых берем данные,
    # размер холста,
    # толщину линии,
    # цвет линий
    ax = df[['sum', 'count', 'avg_sum']].iloc[:i+1].plot(figsize = (12,8), linewidth = 2, color= ['b','g','r'])
    # задаем лимиты по осям
    ax.set_xlim(0, i+1)
    ax.set_ylim(0, max_sum)
    # задаем названия осей и титул графика и размеры шрифта
    ax.set_xlabel('x label', fontsize = 12)
    ax.set_ylabel('y label', fontsize = 12)
    ax.set_title('Title', fontsize = 18)
    # задаем легенду графика, оформление
    ax.legend(['Сумма', 'Кол-во', 'Ср.сумм'], loc = 'upper left', frameon = False)
    # убираем ненужные оси
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    # линии сетки по оси Х
    ax.grid(axis = 'x')
    # отрисовываем данные на холсте
    fig = ax.get_figure()
    # сохраняем холст в файл
    fig.savefig(os.path.join(path_script, dir_name) + f'/{i}.png')

После отработки получаю набор файлов в папке, из которых далее буду формировать анимацию.

# задаем частоту кадров в секунду
fps = 5
# создаем список файлов-кадров из ранее созданной папки
file_list = glob.glob(os.path.join(path_script, dir_name) + '/*')
# создаем анимацию из списка файлов
clip = mpy.ImageSequenceClip(file_list, fps = fps)
# сохраняем анимацию в формате GIF в папку со скриптом
clip.write_gif(path_script + '/{}'.format(gif_name), fps = fps)
# удаляем папку с файлами кадров
shutil.rmtree(os.path.join(path_script, dir_name))

В результате работы скрипта получается файл в формате GIF, который содержит анимацию построения графика по данным из датасета.

Во втором способе для сравнения анимаций использую датасет из предыдущего примера. В этом способе буду использовать стандартную функцию animate библиотеки matplotlib.

# импортируем необходимые библиотеки 
import pandas as pd
import os
# при необходимости импортируем библиотеки
pip install Pillow # версия 8.4.0
# запоминаем текущую папку
path_script = os.getcwd()
# прочитаем датасет из первого способа
df = pd.read_csv(path_script + '/dataset.csv')
# импортируем необходимые библиотеки
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# инициализируем холст, задаем размер
fig,ax = plt.subplots(figsize = (12,8))
# задаем лимиты по осям
ax.set_xlim(0, len(df.index) + 1)
ax.set_ylim(0, max_sum)
# задаем названия осей и титул графика и размеры шрифта
ax.set_xlabel('x label', fontsize = 12)
ax.set_ylabel('y label', fontsize = 12)
ax.set_title('Title', fontsize = 18)
# убираем ненужные оси
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# линии сетки по оси Х
ax.grid(axis = 'x')
# объявляем «переменные» для координат графиков
x = []
y_sum = []
y_count = []
y_avg_sum = []
# функция анимации
def animate(i):
    # задаем легенду графика, оформление
    ax.legend(['Сумма', 'Кол-во', 'Ср.сумм'], loc = 'upper left', frameon = False)
    # прописываем функции координат
    x.append(i)
    y_sum.append(df['sum'].iloc[i])
    y_count.append(df['count'].iloc[i])
    y_avg_sum.append(df['avg_sum'].iloc[i])
    # отображаем графики на холсте
    ax.plot(x,y_sum, 'b')
    ax.plot(x,y_count, 'g')
    ax.plot(x,y_avg_sum, 'r')
# создаем анимацию
anim = animation.FuncAnimation(fig, animate,  frames = len(df.index), interval = len(df.index))
# сохраняем анимацию в формате GIF в папку со скриптом
anim.save(os.getcwd() + '/anim_var2.gif', fps = 5, writer = 'pillow')

Как видно из графиков, анимация одного и того же датасета имеет разную визуализацию. Исходя из потребностей, можно выбрать необходимый способ и использовать получаемый анимационный файл, например, для вставки в презентации или размещения на интернет страницах.