График временных рядов Pandas, устанавливающий основные и второстепенные отметки и метки по оси X

87

Я хочу иметь возможность устанавливать основные и второстепенные xticks и их метки для графика временных рядов, построенного из объекта временного ряда Pandas.

На странице "Что нового" в Pandas 0.9 говорится:

"вы можете использовать to_pydatetime или зарегистрировать конвертер для типа Timestamp"

но я не могу понять, как это сделать, чтобы использовать команды matplotlib ax.xaxis.set_major_locatorи ax.xaxis.set_major_formatter(и второстепенные).

Если я использую их без преобразования времени панд, отметки и метки оси x окажутся неправильными.

Используя параметр xticks, я могу передать основные отметки в pandas.plot, а затем установить основные ярлыки отметок. Я не могу понять, как делать мелкие тики с помощью этого подхода. (Я могу установить метки на второстепенные отметки по умолчанию, установленные pandas.plot)

Вот мой тестовый код:

import pandas
print 'pandas.__version__ is ', pandas.__version__
print 'matplotlib.__version__ is ', matplotlib.__version__    

dStart = datetime.datetime(2011,5,1) # 1 May
dEnd = datetime.datetime(2011,7,1) # 1 July    

dateIndex = pandas.date_range(start=dStart, end=dEnd, freq='D')
print "1 May to 1 July 2011", dateIndex      

testSeries = pandas.Series(data=np.random.randn(len(dateIndex)),
                           index=dateIndex)    

ax = plt.figure(figsize=(7,4), dpi=300).add_subplot(111)
testSeries.plot(ax=ax, style='v-', label='first line')    

# using MatPlotLib date time locators and formatters doesn't work with new
# pandas datetime index
ax.xaxis.set_minor_locator(matplotlib.dates.WeekdayLocator(byweekday=(1),
                                                           interval=1))
ax.xaxis.set_minor_formatter(matplotlib.dates.DateFormatter('%d\n%a'))
ax.xaxis.grid(True, which="minor")
ax.xaxis.grid(False, which="major")
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('\n\n\n%b%Y'))
plt.show()    

# set the major xticks and labels through pandas
ax2 = plt.figure(figsize=(7,4), dpi=300).add_subplot(111)
xticks = pandas.date_range(start=dStart, end=dEnd, freq='W-Tue')
print "xticks: ", xticks
testSeries.plot(ax=ax2, style='-v', label='second line',
                xticks=xticks.to_pydatetime())
ax2.set_xticklabels([x.strftime('%a\n%d\n%h\n%Y') for x in xticks]);
# set the text of the first few minor ticks created by pandas.plot
#    ax2.set_xticklabels(['a','b','c','d','e'], minor=True)
# remove the minor xtick labels set by pandas.plot 
ax2.set_xticklabels([], minor=True)
# turn the minor ticks created by pandas.plot off 
# plt.minorticks_off()
plt.show()
print testSeries['6/4/2011':'6/7/2011']

и его вывод:

pandas.__version__ is  0.9.1.dev-3de54ae
matplotlib.__version__ is  1.1.1
1 May to 1 July 2011 <class 'pandas.tseries.index.DatetimeIndex'>
[2011-05-01 00:00:00, ..., 2011-07-01 00:00:00]
Length: 62, Freq: D, Timezone: None

График со странными датами на оси x

xticks:  <class 'pandas.tseries.index.DatetimeIndex'>
[2011-05-03 00:00:00, ..., 2011-06-28 00:00:00]
Length: 9, Freq: W-TUE, Timezone: None

График с правильными датами

2011-06-04   -0.199393
2011-06-05   -0.043118
2011-06-06    0.477771
2011-06-07   -0.033207
Freq: D

Обновление: я смог приблизиться к макету, который хотел, используя цикл для создания основных меток xtick:

# only show month for first label in month
month = dStart.month - 1
xticklabels = []
for x in xticks:
    if  month != x.month :
        xticklabels.append(x.strftime('%d\n%a\n%h'))
        month = x.month
    else:
        xticklabels.append(x.strftime('%d\n%a'))

Однако это немного похоже на использование оси x ax.annotate: возможно, но не идеально.

бренд
источник
1
Я знаю, что это на самом деле не отвечает на вопрос, но в качестве общего подхода, когда мне действительно важно, как выглядит сюжет, я обычно просто пытаюсь получить его векторную версию и сделать так, чтобы она выглядела хорошо в Illustrator или Inkscape. Я обнаружил, что большинство людей, которых я знаю, похоже, поступают так же.
Джон МакДоннелл,
2
Можете ли вы просто полностью игнорировать аргументы plotфункции pandas и установить все отметки после построения графика, используя методы matplotlib возвращаемого axобъекта (например, ax.set_xticks)?
BrenBarn
@BrenBarn Я не мог понять, как получить дату как дату Python вместо даты и времени pandas для методов matplotlib. Ответ bmu исправляет это путем преобразования дат перед построением.
brenda

Ответы:

89

Оба pandasи matplotlib.datesиспользуют matplotlib.unitsдля обнаружения клещей.

Но хотя matplotlib.datesесть удобные способы установить галочки вручную, pandas, похоже, до сих пор фокусируется на автоматическом форматировании (вы можете взглянуть на код для преобразования даты и форматирования в pandas).

Так что на данный момент кажется более разумным использовать matplotlib.dates(как упомянул @BrenBarn в своем комментарии).

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
import matplotlib.dates as dates

idx = pd.date_range('2011-05-01', '2011-07-01')
s = pd.Series(np.random.randn(len(idx)), index=idx)

fig, ax = plt.subplots()
ax.plot_date(idx.to_pydatetime(), s, 'v-')
ax.xaxis.set_minor_locator(dates.WeekdayLocator(byweekday=(1),
                                                interval=1))
ax.xaxis.set_minor_formatter(dates.DateFormatter('%d\n%a'))
ax.xaxis.grid(True, which="minor")
ax.yaxis.grid()
ax.xaxis.set_major_locator(dates.MonthLocator())
ax.xaxis.set_major_formatter(dates.DateFormatter('\n\n\n%b\n%Y'))
plt.tight_layout()
plt.show()

pandas_like_date_fomatting

(у меня немецкий язык, поэтому вторник [вт] становится Dienstag [Di])

БМУ
источник