Вывести временной интервал на график временного ряда с помощь Python
Часто для анализа временных рядов нужно перебрать много факторов в поисках возможных связей. И обычно, факторы — это просто какие-то события происходившие в некоторый период времени и на прямую не влиявшие на целевой показатель. То есть хочется «подсветить» диапазон времени на графике временного ряда, а ещё так чтобы каждый тип события имел свой цвет.
Как оказалось, найти решение гораздо сложнее, чем его реализовать. Код базируется на статье с geeksforgeeks.org, однако моё решение представлено в виде функции, пусть и не очень изящной, позволяет автоматически генерировать разные цвета для разных диапазонов времени, а также собирает легенду.
Для иллюстрации посмотрим, есть ли какие-то взаимосвязи между извержениями вулканов России и средним отклонением мировой температуры от базовой. Кривую отклонения температур берём от сюда, а базу с извержением вулканов можно скачать здесь. Чтобы не загружать график выберем только извержения с VEI от 4 и больше (Volcanic Explosivity Index — метрика силы извержения).
Последовательность действий
В целом, всё что нужно сделать укладывается в 4 пункта:
-
объявляем
subplots -
«строим»
scatterилиplotс целевым значением -
с помощью
axvspanдобавляем нужные временные отрезки -
plt.show()— ура, временные интервалы подсветились на графике
Строим график сами
Библиотеки и загрузка данных
Для сборки графика потребуется функции subplots и axvspan из библиотеки matplotlib.pyplot. Данные удобнее всего хранить в датафреймах, поэтому также подгружаем pandas и для генерации цветов, учитывая возможную потребность в их большом количестве воспользуемся методом random из numpy.
import pandas as pd import matplotlib.pyplot as plt import numpy as np
Загружаем данные. Почему-то база данных извержений вулканов выгружает в очень старых версиях экселя, файлик придется либо пересохранить вручную, либо искать подходящий параметр engine(я не нашла).
Важно, чтобы все временный данные имели одинаковый тип и я везде для удобства использую datetime, но строго говоря это не обязательно — отображать можно и просто числовые данные.
Загрузка и предобработка данных
# загружаем данные в датафремы df_temp = pd.read_csv('annual_temp.csv') df_eruptions = pd.read_excel('eruptions.xlsx') # приводим данные в datetime для температурных данных df_temp['Year'] = pd.to_datetime(df_temp['Year'], format='%Y') df_temp.dropna(inplace=True) # убираем пропуски df_temp = df_temp.groupby('Year').mean() # данные за каждый год представлены несколькими источниками, группируем и берем среднее df_temp['Year'] = df_temp.index # для удобства создадим столбец с годами # данные о изврежения нужно фильтровать df_eruptions = df_eruptions[['Volcano Name', 'VEI', 'Start Year', 'Start Month', 'Start Day', 'End Year','End Month', 'End Day']] # нужные столбцы df_eruptions.dropna(inplace=True) # убираем пропуски df_eruptions = df_eruptions[(df_eruptions['VEI'] >=4) &(df_eruptions['Start Year'] >=1880)] # фильтруем данные по VEI # это строки посвящены формированию столбцов с датами начала и конца изврежения df_eruptions[['Start Year', 'Start Month', 'Start Day', 'End Year', 'End Month', 'End Day']] = df_eruptions[['Start Year', 'Start Month', 'Start Day', 'End Year', 'End Month', 'End Day']].astype(str) df_eruptions['start_date'] = pd.to_datetime(df_eruptions['Start Year'] + '/' + df_eruptions['Start Month'] + '/' + df_eruptions['Start Day'], format='%Y/%m.0/%d.0' ) df_eruptions['end_date'] = pd.to_datetime(df_eruptions['End Year'] + '/' + df_eruptions['End Month'] + '/' + df_eruptions['End Day'], format='%Y.0/%m.0/%d.0')
График
Данные готовы — пора создать визуализацию.
plt.subplots() — позволят создавать сет субграфиков и общий макет подзаголовков. Например, здесь можно задать размер итогового изображения
ax.plot — строим кривую целевых значений (вместо plot, может быть например scatter или другой). В функцию подаем x и y, для легенды можно обозначить label.
ax.axvspan — выделит цветом временной диапазон. На вход нужно подать даты начала и конца интервала. В дополнительные параметры можно передать цвет и лейбл.
В этом коде цвет присваивается извержению, т.е. извержения Шивелуча 1964 года и записанное в одно большое извержения с 1999 года имеют разные цвета. Соответственно и легенда раздувается. В функции ниже реализованы одинаковые цвета.
Поскольку временных интервалов много — реализован цикл пробегающий по спискам с данными. Преобразование в списки продиктовано удобством и понятностью кода.
fig, ax = plt.subplots(figsize=(20, 6)) # задаем сабплот и размеры графика ax.plot(df_temp['Year'], df_temp['Mean'], marker='x',label='Среднее отклонение от базовой температуры') eruption_started = df_eruptions['start_date'].to_list() eruption_ended = df_eruptions['end_date'].to_list() for i in range(len(eruption_started)): ax.axvspan(eruption_started[i], eruption_ended[i], alpha=0.3, color=np.random.rand(3,), label=df_eruptions['Volcano Name'].to_list()[i] ) plt.legend() plt.show()

Функция
Реализуем в виде функции highlighted_date. На вход она принимает:
-
pandas.Seriesс координатами х и у для целевого графика; -
str— название целевого графика для легенды; -
pandas.Seriesс координатами х и у для временных интервалов; -
pandas.Seriesс лейблами временных интервалов Функция выводит график сscatterцелевой функции (для соединений можно заменить наplot), временные диапазоны окрашиваются поlabel— т.е. все извержения Шивелуча имеют одинаковый цвет и обозначен в легенде единожды. Отображается легенда.
def highlighted_date (x, y, label, x_2, y_2, label_2): """ main_prepare_data(series,series, str, series,series,series) подсвечивает временные отрезки и выводит целевую кривую """ fig, ax = plt.subplots(figsize=(20, 6)) # задаём параметры графика ax.scatter(x, y, marker='x', label=label) # строим график целевого значения x_2 = x_2.to_list() y_2 = y_2.to_list() color_dict = {} already_labeled = [] # для фильтрации уже вынесенных в легенду for j in label_2.unique(): # создаём словарь цветов для уникальных названий color_dict[j] = np.random.rand(3,) # цвета задаются рандомом label_2 = label_2.to_list() for i in range(len(x_2)): if(label_2[i] in already_labeled): ax.axvspan(x_2[i], y_2[i], alpha=0.3, color=color_dict[label_2[i]]) else: ax.axvspan(x_2[i], y_2[i], alpha=0.3, color=color_dict[label_2[i]], label=label_2[i]) already_labeled.append(label_2[i]) plt.legend() plt.show()
Вызов выглядит так:
highlighted_date(df_temp['Year'], df_temp['Mean'], 'Среднее отклонение от базовой температуры', df_eruptions['start_date'], df_eruptions['end_date'], df_eruptions['Volcano Name'])

Вывод
Интересно, насколько велико влияние извержения вулкана Безымянного 1955 года на резкий скачок температуры?
С помощью python можно понятно и красиво отображать временные интервалы на графике временных данных. Разные события можно окрасить в разные цвета или сгруппировать в один. Иногда, такая визуализация может существенно повысить качество анализа и найти взаимосвязи.
ссылка на оригинал статьи https://habr.com/ru/post/710530/
Добавить комментарий