Создание анимированных диаграмм в Python

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

Однако это может оказаться довольно сложной задачей. Для успешной коммуникации, основанной на данных, используется популярная и мощная техника сторителлинга (рассказывания историй). 

“Факт, что в нашем распоряжении находится вся информация в мире, совсем не облегчает процесс коммуникации, а, наоборот, усложняет его”. (Коул Нуссбаумер Кнафлич, автор книги “Storytelling with Data”)

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

В этой статье вы узнаете о том, как создавать анимированные диаграммы и добавлять новое измерение в гистограммы, линейные и круговые диаграммы. Эта статья — лишь первый шаг в мир безграничных возможностей.  

Двойной маятник

Как работает анимация 

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

Этот пакет является методом расширения FuncAnimation и частью класса Animation библиотеки Matplotlib в Python. Мы рассмотрим разнообразные примеры использования упомянутого интерфейса, но пока будем считать эту функцию циклом while, который продолжает перерисовывать нашу фигуру на холсте. 

Как использовать библиотеку 

Я смог лучше понять процесс создания анимированных диаграмм, начав их изучение с конца. Магия анимации начинается с двух следующих строк: 

import matplotlib.animation as ani

animator = ani.FuncAnimation(fig, chartfunc, interval = 100)

Посмотрим на эти вводные данные FuncAnimation: 

  1. fig обозначает объект рисунка, на котором мы будем “рисовать диаграмму”. 
  2. chartfunc — это функция, которая принимает числовой ввод, показывающий время измерения во временном ряду (по мере увеличения числа мы продвигаемся по временной шкале). 
  3. interval — это задержка между кадрами в миллисекундах (по умолчанию до 200). 

Ознакомьтесь с документацией по дополнительным параметрам входных данных. 

В дальнейшем остается только параметризовать диаграммы в функцию, принимающую в виде числового ввода точку во временном ряду, и процесс запущен! 


Как начать работу 

Проверим на практике, как хорошо мы усвоили основы. Для этого создадим диаграммы, используя статистические данные по пандемии COVID-19 (число смертей в день) и готовый набор данных из приведенного ниже кода. 

import matplotlib.animation as ani
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

url = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series
/time_series_covid19_deaths_global.csv'
df = pd.read_csv(url, delimiter=',', header='infer')

df_interest = df.loc[
    df['Country/Region'].isin(['United Kingdom', 'US', 'Italy', 'Germany'])
    & df['Province/State'].isna()]

df_interest.rename(
    index=lambda x: df_interest.at[x, 'Country/Region'], inplace=True)
df1 = df_interest.transpose()

df1 = df1.drop(['Province/State', 'Country/Region', 'Lat', 'Long'])
df1 = df1.loc[(df1 != 0).any(1)]
df1.index = pd.to_datetime(df1.index)

Анимированная линейная диаграмма 

Сначала определим параметры диаграммы, которые останутся постоянными. То есть создадим объект рисунка, координаты x и y, а также установим цвета линий и поля этого объекта.

import numpy as np
import matplotlib.pyplot as plt

color = ['red', 'green', 'blue', 'orange']
fig = plt.figure()
plt.xticks(rotation=45, ha="right", rotation_mode="anchor") #циклическое перемещение значений по оси x 
plt.subplots_adjust(bottom = 0.2, top = 0.9) #убеждаемся, что даты (по оси x) умещаются на экране 
plt.ylabel('No of Deaths')
plt.xlabel('Dates')

Затем нужно настроить функцию кривой и анимировать ее:

def buildmebarchart(i=int):
    plt.legend(df1.columns)
    p = plt.plot(df1[:i].index, df1[:i].values) #обращаем внимание, что происходит возврат набора данных вплоть до точки i 
    for i in range(0,4):
        p[i].set_color(color[i]) #устанавливаем цвет для каждой кривой

importmatplotlib.animation as ani
animator = ani.FuncAnimation(fig, buildmebarchart, interval = 100)
plt.show()

Анимированная круговая диаграмма 

Структуры кода круговой и линейной диаграммы похожи, но есть и некоторые отличия. 

import numpy as np
import matplotlib.pyplot as plt

fig,ax = plt.subplots()
explode=[0.01,0.01,0.01,0.01] #выделяем каждый сектор круга 

def getmepie(i):
    def absolute_value(val): #превращаем % обратно в число 
        a  = np.round(val/100.*df1.head(i).max().sum(), 0)
        return int(a)
    ax.clear()
    plot = df1.head(i).max().plot.pie(y=df1.columns,autopct=absolute_value, label='',explode = explode, shadow = True)
    plot.set_title('Total Number of Deaths\n' + str(df1.index[min(i, 
len(df1.index)-1 )].strftime('%y-%m-%d')), fontsize=12)
import matplotlib.animation as ani
animator = ani.FuncAnimation(fig, getmepie, interval = 200)
plt.show()

Главное отличие состоит в том, что в выше приведенном коде каждый раз возвращается один набор значений. А в линейном графике мы возвращали весь временной ряд к точке, с которого начинали. Для этого использовалась: 

df1.head(i).max()

df1.head(i) возвращает временной ряд, но .max() гарантирует, что мы получаем только самые последние данные (потому что общее значение смертей либо останется таким же, либо будет расти). 


Анимированная гистограмма 

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

fig = plt.figure()
bar = ''

def buildmebarchart(i=int):
    iv = min(i, len(df1.index)-1) #Цикл производит одну дополнительную итерацию, что приводит к выходу структур данных из границ. Это был самый простой (точнее, самый ленивый)способ решить проблему :)
    objects = df1.max().index
    y_pos = np.arange(len(objects))
    performance = df1.iloc[[iv]].values.tolist()[0]
    if bar == 'vertical':
        plt.bar(y_pos, performance, align='center', color=['red', 'green', 'blue', 'orange'])
        plt.xticks(y_pos, objects)
        plt.ylabel('Deaths')
        plt.xlabel('Countries')
        plt.title('Deaths per Country \n' + str(df1.index[iv].strftime('%y-%m-%d')))
    else:
        plt.barh(y_pos, performance, align='center', color=['red', 'green', 'blue', 'orange'])
        plt.yticks(y_pos, objects)
        plt.xlabel('Deaths')
        plt.ylabel('Countries')

animator = ani.FuncAnimation(fig, buildmebarchart, interval=100)

plt.show()

Как сохранить анимированные диаграммы 

Создав свои первые анимированные диаграммы, вы, конечно же, захотите ими поделиться. Как же их сохранить?

К счастью, для этого необходима всего одна строка кода:

animator.save(r'C:\temp\myfirstAnimation.gif')

С более подробной информацией можно ознакомиться здесь

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Costas Andreou: Learn How to Create Animated Graphs in Python

Предыдущая статьяРуководство по Webpack для начинающих
Следующая статьяПовторный рендеринг и мемоизация в React