Отображение временных данных с разными частотами (matplotlib, pandas) - PullRequest
0 голосов
/ 07 мая 2018

Я пытаюсь объединить временной ряд Панд и ряд вертикальных сегментов (маркеров) на одном графике. Ряд имеет частоту «Q-DEC» (квартал), которая в этом примере выводится из дат, но в реальной задаче является частью набора данных. Маркеры, как правило, не совпадают с сериями и могут появляться где угодно, необязательно в конце квартала.

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

Q : Как я могу нанести маркеры в правильные позиции на графике временного ряда?

import datetime
import pandas as pd
from pandas import Timestamp
import matplotlib.pyplot as plt

data = pd.DataFrame({0: {Timestamp('2017-03-31'): 1, 
                         Timestamp('2017-06-30'): 2, 
                         Timestamp('2017-09-30'): 3, 
                         Timestamp('2017-12-31'): 3, 
                         Timestamp('2018-03-31'): 2, 
                         Timestamp('2018-06-30'): 1}})

ax = plt.subplot(2,1,1)
data[0].plot(ax=ax,style="-mo")
ax.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
ax.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
ax.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
ax.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')
ax = plt.subplot(2,1,2)
ax.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
ax.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
ax.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
ax.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')
data[0].plot(ax=ax,style="-mo")
plt.show()

Example

Ответы [ 2 ]

0 голосов
/ 07 мая 2018

Если вы переместите даты в индекс как PeriodIndex, начните с freq="M", чтобы обеспечить правильное построение линий.
Затем замените галочки со значениями индекса, установленными на freq="Q-DEC".

data.set_index(pd.PeriodIndex(data.index, freq="M"), inplace=True)
ax = data[0].plot(style="-mo")

ax.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
ax.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
ax.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
ax.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')

Теперь сбросьте галочки:

q_ticks = data.index.asfreq("Q-DEC")
ax.minorticks_off()
ax.set_xticks(q_ticks)
ax.set_xticklabels(q_ticks)

Выход:

enter image description here

Примечание. Если вы не удалите второстепенные тики с помощью minorticks_off(), вы получите некоторое совпадение с исходными месячными тиками и новыми квартальными тиками.

Update
Если вам действительно нужно получить формат точно , как в вашем примере, вам нужно будет немного маневрировать с основными и второстепенными позициями и форматами тиков:

ax.get_xaxis().set_tick_params(which='major', pad=15)

q_ticks = data.index.asfreq("Q-DEC")

# extract only the year, and only the year's first listing
major_ticklabels = pd.Series(q_ticks.strftime("%Y"))
major_ticklabels[major_ticklabels.duplicated()] = ""
ax.set_xticks(q_ticks)
ax.set_xticklabels(major_ticklabels)

# format as Q[quarter number]
minor_ticklabels = q_ticks.strftime("Q%q")
ax.xaxis.set_ticks(q_ticks, minor=True)
ax.xaxis.set_ticklabels(minor_ticklabels, minor=True)

enter image description here

0 голосов
/ 07 мая 2018

Следующий код может изменить ось вашего второго субплота, как и первый субплот.Попробуйте, если хотите, чтобы четверть была осью X.

data = pd.DataFrame({0: {Timestamp('2017-03-31'): 1, 
                         Timestamp('2017-06-30'): 2, 
                         Timestamp('2017-09-30'): 3, 
                         Timestamp('2017-12-31'): 3, 
                         Timestamp('2018-03-31'): 2, 
                         Timestamp('2018-06-30'): 1}})

xaxis = ['Q{}'.format((pd.to_datetime(date).month-1)//3+1) for date in data.index.values]
plt.xticks(data.index.values,xaxis)

plt.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
plt.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
plt.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
plt.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')
data[0].plot(style="-mo")

выход enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...