Объяснение визуализации временных рядов, включая подробные примеры кода в Matplotlib, Plotly и Altair.
Делиться

Это пятая статья из моей серии, посвящённой визуализации данных. См. также:
- Часть 1: «Визуализация данных: что это такое и почему это важно»
- Часть 2: «Визуализация данных: введение в визуальные переменные».
- Часть 3: «Визуализация данных: роль цвета».
- Часть 4: «Визуализация данных: обзор основ Python».
Пришло время приступить к созданию собственных визуализаций данных. В этой статье я подробно расскажу о процессе визуализации временных рядов в Python. Если вы не читали предыдущие статьи из моей серии, посвящённой визуализации данных, настоятельно рекомендую прочитать хотя бы предыдущую статью для ознакомления с Python.
В курсе написания визуализаций на Python я сосредоточусь на трёх пакетах Python: Matplotlib, Plotly и Altair. Один из подходов к их изучению может включать написание одной-двух статей на каждый пакет, каждая из которых будет подробно рассматривать выбранный пакет. Хотя это и обоснованный подход, основное внимание в моей серии уделяется не какой-либо конкретной библиотеке, а самому процессу визуализации данных. Эти пакеты — всего лишь инструменты, средства достижения цели.
В результате я структурирую эту и последующие статьи вокруг определенного типа визуализации данных и расскажу, как реализовать эту визуализацию в каждом из перечисленных пакетов, чтобы обеспечить вам широкий выбор подходов.
Для начала: определение временных рядов данных.
Что такое временные ряды данных?
Формально временные ряды данных включают в себя переменную, являющуюся функцией времени. Проще говоря, это просто данные, которые меняются со временем.
Например, цена акций публичной компании за последние десять лет — это временной ряд. Если вы предпочитаете более научный пример, рассмотрим погоду. График, отображающий ежедневную температуру в вашем любимом городе в течение года, — это график, отображающий временной ряд.
Данные временных рядов являются отличной отправной точкой для визуализации данных по нескольким причинам:
- Это чрезвычайно распространённый и полезный тип данных. Значительная часть информации зависит от времени, и её понимание даёт ценное представление о предмете интереса в будущем.
- Существуют проверенные и надёжные методы эффективной визуализации временных рядов данных, как вы увидите ниже. Освойте их, и вы будете в отличной форме.
- По сравнению с некоторыми другими типами данных, визуализация временных рядов достаточно интуитивно понятна человеку и соответствует нашему восприятию времени. Это позволяет сосредоточиться на базовых элементах проектирования визуализации на начальном этапе, не увязая в попытках разобраться в очень сложных данных.
Давайте начнем с рассмотрения различных методов визуализации на концептуальном уровне.
Как визуализируются данные временных рядов?
Стандартом визуализации временных рядов является знаменитая линейная диаграмма:

На этой диаграмме время обычно откладывается по оси X, а переменная, изменяющаяся со временем, — по оси Y. Это создаёт впечатление, что картина «движется вперёд», что соответствует линейному восприятию времени человеком.
Хотя линейный график является стандартом, существуют и другие, связанные с ним возможности.
Многолинейная диаграмма
Этот подход является прямым продолжением одинарной линейной диаграммы и отображает несколько связанных временных рядов на одном графике, что позволяет проводить сравнение между группами или категориями (например, продажи по регионам):

Диаграмма площади
Функционально диаграмма с областями почти такая же, как и линейная диаграмма, но область под линией заполнена. Это подчеркивает величину изменений:

Диаграмма с областями и штабелированием
Технически, стопочная диаграмма с областями является аналогом многолинейной диаграммы, но её немного сложнее читать. В частности, итоговый показатель является кумулятивным, а базовая линия для каждой стопочной линии начинается с линии, расположенной ниже. Например, в 2023 году на диаграмме ниже «Возраст 25–64» соответствует примерно 4 миллиардам человек, поскольку мы начинаем отсчёт там, где заканчивается «Возраст 15–24».

Столбчатая диаграмма (вертикальная или горизонтальная)
Наконец, в некоторых случаях столбчатая диаграмма также подходит для визуализации временных рядов. Этот подход полезен, если вы хотите отобразить дискретные временные интервалы, например, месячную сумму или среднегодовое значение какого-либо показателя, а не непрерывные данные. Однако в этой статье я не буду писать код для столбчатых диаграмм.

Теперь приступим к непосредственному созданию визуализаций. В каждом из примеров ниже я подробно разберу код в специальной библиотеке визуализации для построения линейных и площадных диаграмм. Я прикрепил ссылки на данные и рекомендую вам следовать инструкциям. Чтобы усвоить эти методы, вам необходимо попрактиковаться в их применении самостоятельно.
Кодирование визуализаций временных рядов в Matplotlib
import pandas as pd import matplotlib.pyplot as plt # Загрузка данных df = pd.read_csv('sales_data.csv') df['Дата'] = pd.to_datetime(df['Дата']) # Пример 1: Простая линейная диаграмма fig1, ax1 = plt.subplots(figsize=(10, 6)) ax1.plot(df['Дата'], df['Продажи продукта A'], linewidth=2) ax1.set_xlabel('Дата') ax1.set_ylabel('Продажи') ax1.set_title('Продажи продукта A с течением времени') ax1.grid(True, alpha=0.3) plt.tight_layout() # Отображение с помощью: fig1 # Пример 2: Многолинейная диаграмма fig2, ax2 = plt.subplots(figsize=(10, 6)) ax2.plot(df['Дата'], df['Продажи продукта A'], label='Продукт A', ширина линии=2) ax2.plot(df['Дата'], df['Продажи продукта B'], label='Продукт B', ширина линии=2) ax2.plot(df['Дата'], df['Продажи продукта C'], label='Продукт C', ширина линии=2) ax2.set_xlabel('Дата') ax2.set_ylabel('Продажи') ax2.set_title('Сравнение продаж — Все продукты') ax2.legend() ax2.grid(True, alpha=0.3) plt.tight_layout() # Отобразить с помощью: fig2 # Пример 3: Диаграмма с областями fig3, ax3 = plt.subplots(figsize=(10, 6)) ax3.fill_between(df['Дата'], df['Продажи продукта A'], alpha=0.4) ax3.plot(df['Дата'], df['Продажи продукта A'], linewidth=2) ax3.set_xlabel('Дата') ax3.set_ylabel('Продажи') ax3.set_title('Продажи продукта A — Диаграмма с областями') ax3.grid(True, alpha=0.3) plt.tight_layout() # Отобразить с помощью: fig3 # Пример 4: Диаграмма с областями с накоплением fig4, ax4 = plt.subplots(figsize=(10, 6)) ax4.stackplot(df['Дата'], df['Продажи продукта A'], df['Продажи продукта B'], df['Продажи продукта C'], labels=['Продукт A', 'Продукт B', 'Продукт C'], alpha=0.7) ax4.set_xlabel('Дата') ax4.set_ylabel('Продажи') ax4.set_title('Общие продажи — Диаграмма с областями и накоплением') ax4.legend(loc='upper left') ax4.grid(True, alpha=0.3) plt.tight_layout() # Отображение с помощью: fig4
Выполнение этого кода создает следующие четыре визуализации:




Давайте разберем код шаг за шагом, чтобы вы поняли, что происходит:
- Сначала мы загружаем данные в pandas как CSV-файл и гарантируем, что дата правильно представлена как объект datetime.
- Библиотека Matplotlib структурирует диаграммы внутри объекта Figure, представляющего весь холст. Доступ к нему можно получить напрямую с помощью plt.figure, но использование нескольких переменных с помощью plt.subplots более интуитивно понятно для множественной визуализации. Каждый вызов plt.subplots определяет новый, отдельный объект Figure (холст).
- Строка fig1, ax1 = plt.subplots(figsize=(10, 6)) определяет первый подграфик; fig1 представляет холст, но ax1 представляет фактическую область построения графика внутри него и является переменной, в которой вы будете вносить большинство изменений.
- В Matplotlib есть разные функции для построения разных диаграмм. Функция plot строит двумерные точки, а затем соединяет их, создавая линейный график. Именно это мы и указываем в строке ax1.plot(df['Date'], df['Product A Sales'], linewidth=2).
- Остальные строки в основном выполняют эстетические функции, которые выполняют именно то, на что указывают их названия: маркируют оси, добавляют линии сетки и задают макет.
- Для многолинейной диаграммы код точно такой же, за исключением того, что мы вызываем plot три раза: по одному для каждого набора точек xy, которые мы хотим отобразить на графике, чтобы показать все продукты.
- Диаграмма с областями почти идентична линейной диаграмме, за исключением добавления ax3.fill_between(df['Date'], df['Product A Sales'], alpha=0.4), который сообщает Matplotlib о необходимости затенить область под линией.
- Для диаграммы с областями с накоплением , напротив, требуется использовать функцию stacked_plot, которая одновременно обрабатывает все три массива данных, которые мы хотим отобразить. Однако остальной код, отвечающий за эстетику, остаётся тем же.
Попробуйте запрограммировать их самостоятельно в вашей любимой IDE или в Jupyter Notebook. Какие закономерности вы видите? Какая диаграмма вам нравится больше всего?
Кроме того, помните, что вам не нужно запоминать этот синтаксис, особенно если вы новичок в программировании визуализации данных или вообще не знакомы с Python. Сосредоточьтесь на понимании происходящего на концептуальном уровне; вы всегда можете найти конкретный синтаксис и подставить нужные данные.
Это будет справедливо и для оставшихся двух примеров.
Кодирование визуализаций временных рядов в Plotly
Вот код для создания тех же визуализаций, что и выше, на этот раз в стиле Plotly:
import pandas as pd import plotly.graph_objects as go # Загрузка данных df = pd.read_csv('sales_data.csv') df['Date'] = pd.to_datetime(df['Date']) # Пример 1: Простая линейная диаграмма fig1 = go.Figure() fig1.add_trace(go.Scatter(x=df['Date'], y=df['Product A Sales'], mode='lines', name='Product A')) fig1.update_layout( title='Продажи продукта A с течением времени', xaxis_title='Date', yaxis_title='Sales', template='plotly_white' ) # Отображение с помощью: fig1 # Пример 2: Многолинейная диаграмма fig2 = go.Figure() fig2.add_trace(go.Scatter(x=df['Date'], y=df['Продажи продукта A'], mode='lines', name='Продукт A')) fig2.add_trace(go.Scatter(x=df['Дата'], y=df['Продажи продукта B'], mode='lines', name='Продукт B')) fig2.add_trace(go.Scatter(x=df['Дата'], y=df['Продажи продукта C'], mode='lines', name='Продукт C')) fig2.update_layout( title='Сравнение продаж — Все продукты', xaxis_title='Дата', yaxis_title='Продажи', template='plotly_white' ) # Отобразить с помощью: fig2 # Пример 3: Диаграмма с областями fig3 = go.Figure() fig3.add_trace(go.Scatter( x=df['Дата'], y=df['Продукт A Sales'], mode='lines', name='Product A', fill='tozeroy' )) fig3.update_layout( title='Продажи продукта A — Диаграмма с областями', xaxis_title='Дата', yaxis_title='Продажи', template='plotly_white' ) # Отображение с помощью: fig3 # Пример 4: Диаграмма с областями с накоплением fig4 = go.Figure() fig4.add_trace(go.Scatter( x=df['Дата'], y=df['Продажи продукта A'], mode='lines', name='Продукт A', stackgroup='one' )) fig4.add_trace(go.Scatter( x=df['Дата'], y=df['Продажи продукта B'], mode='lines', name='Продукт B', stackgroup='one' )) fig4.add_trace(go.Scatter( x=df['Дата'], y=df['Продажи продукта C'], mode='lines', name='Продукт C', stackgroup='one' )) fig4.update_layout( title='Общие продажи — Диаграмма с областями и накоплением', xaxis_title='Дата', yaxis_title='Продажи', template='plotly_white' ) # Отображение с помощью: fig4
Получаем следующие четыре визуализации:




Вот разбивка кода:
- Plotly полностью независим от Matplotlib. Он использует объекты Figure с похожими именами, но не имеет объектов ax.
- Функция Scatter с режимом «линии» используется для построения линейной диаграммы с заданными данными по осям X и Y. Функцию add_trace можно рассматривать как добавление нового компонента к существующему рисунку. Таким образом, для многолинейной диаграммы мы просто вызываем add_trace с соответствующими входными данными Scatter три раза.
- Для маркировки и эстетики в Plotly используйте функцию update_layout.
- Диаграмма с областями строится идентично линейной диаграмме с добавлением необязательного аргумента fill='tozeroy'.
- На первый взгляд это может показаться каким-то непонятным цветом, но на самом деле это сообщение «TO ZERO Y», указывающее Plotly область, которую следует заполнить.
- Если вам трудно это представить, попробуйте изменить аргумент на «tozerox» и посмотрите, что произойдет.
- Для стековой диаграммы с областями нам понадобится другой необязательный параметр: stackgroup='one'. Добавление этого параметра к каждому вызову Scatter сообщает Plotly, что все они должны быть построены как часть одного стека.
Преимущество Plotly заключается в том, что по умолчанию все диаграммы Plotly интерактивны и позволяют масштабировать их, наводить курсор на подсказки и переключать легенду. (Обратите внимание, что изображения выше сохранены в формате PNG, поэтому вам придется самостоятельно сгенерировать диаграммы, чтобы увидеть это.)
Кодирование визуализаций временных рядов в Altair
Завершим созданием этих четырёх визуализаций в Altair. Вот код:
import pandas as pd import altair as alt # Загрузка данных df = pd.read_csv('sales_data.csv') df['Дата'] = pd.to_datetime(df['Дата']) # Пример 1: Простая линейная диаграмма chart1 = alt.Chart(df).mark_line().encode( x='Дата:T', y='Продажи продукта A:Q' ).properties( title='Продажи продукта A с течением времени', width=700, height=400 ) # Отображение с помощью: chart1 # Пример 2: Многолинейная диаграмма # Изменение формы данных для Altair df_melted = df.melt(id_vars='Дата', var_name='продукт', value_name='продажи') chart2 = alt.Chart(df_melted).mark_line().encode( x='Дата:T', y='sales:Q', color='product:N' ).properties( title='Сравнение продаж — Все продукты', width=700, height=400 ) # Отображается с помощью: chart2 # Пример 3: Диаграмма с областями chart3 = alt.Chart(df).mark_area(opacity=0.7).encode( x='Дата:T', y='Продажи продукта A:Q' ).properties( title='Продажи продукта A — Диаграмма с областями', width=700, height=400 ) # Отображается с помощью: chart3 # Пример 4: Диаграмма с областями с накоплением chart4 = alt.Chart(df_melted).mark_area(opacity=0.7).encode( x='Дата:T', y='sales:Q', color='product:N' ).properties( title='Общие продажи — Диаграмма с областями с накоплением', width=700, height=400 ) # Отображение с помощью: chart4
Получаем следующие графики:




Давайте разберем код:
- Структура Altair несколько отличается от Matplotlib и Plotly. Для её освоения требуется некоторая практика, но как только вы её поймёте, интуитивность сделает создание новых визуализаций простым и понятным.
- В Altair всё вращается вокруг объекта Chart, в который вы передаёте свои данные. Затем вы используете функцию mark_, чтобы указать, какой тип диаграммы вы хотите построить, и функцию encoding, чтобы указать, какие переменные будут соответствовать визуальным элементам на диаграмме (например, оси X и Y, цвету, размеру и т. д.).
- Для линейной диаграммы мы используем функцию mark_line, а затем указываем, что хотим, чтобы на оси X отображалась дата, а на оси Y — продажи.
- Функция «melt» не изменяет сами данные, а только их структуру. Она помещает все товары в один столбец, создавая «длинный формат», который лучше подходит для модели визуализации Altair. Подробнее см. в этой полезной статье.
- После преобразования данных, как указано выше, мы можем построить многолинейную диаграмму, просто добавив «цветовую» кодировку, как показано в коде. Это стало возможным благодаря тому, что все типы продуктов теперь представлены в одном столбце, и мы можем указать Altair различать их по цвету.
- Код для построения диаграмм с площадями демонстрирует всю красоту структуры Altair. Всё остаётся прежним — нужно лишь изменить используемую функцию на mark_area!
По мере того, как вы будете самостоятельно изучать другие типы визуализаций (и в будущих статьях!), модель Altair для построения визуализаций станет для вас более простой в реализации (и, надеемся, вы ее оцените по достоинству).
Что дальше?
В будущих статьях я расскажу, как использовать эти библиотеки для создания дополнительных типов визуализаций. Продолжая обучение, помните, что цель этих статей — не освоить какой-либо один инструмент. Речь идёт о комплексном изучении визуализации данных, и я надеюсь, что после прочтения этой статьи вы лучше поймете, как визуализируются временные ряды.
Что касается кода, то комфорт приходит со временем и практикой. Пока же вы можете смело использовать приведённые выше примеры и адаптировать их под свои данные по мере необходимости.
До следующего раза.
Ссылки
- https://matplotlib.org/
- https://plotly.com/
- https://altair-viz.github.io/
Источник: towardsdatascience.com



























