Pandas timeseries kreśli kreślenie głównych i pobocznych znaczników i etykiet na osi X.

87

Chcę mieć możliwość ustawienia głównych i pomocniczych znaczników oraz ich etykiet dla wykresu szeregów czasowych wykreślonych z obiektu szeregów czasowych Pandas.

Na stronie Pandas 0.9 „co nowego” jest napisane:

„możesz użyć to_pydatetime lub zarejestrować konwerter dla typu Timestamp”

ale nie wiem, jak to zrobić, aby móc używać poleceń matplotlib ax.xaxis.set_major_locatori ax.xaxis.set_major_formatter(i pobocznych).

Jeśli użyję ich bez przeliczania czasów pand, znaczniki osi X i etykiety kończą się nieprawidłowo.

Używając parametru „xticks”, mogę przekazać główne tiki do pandas.plot, a następnie ustawić główne etykiety tików. Nie mogę wymyślić, jak zrobić drobne tiki, używając tego podejścia. (Mogę ustawić etykiety na domyślnych drobnych taktach ustawionych przez pandas.plot)

Oto mój kod testowy:

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']

i jego wyjście:

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

Wykres z dziwnymi datami na osi 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

Wykres z poprawnymi datami

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

Aktualizacja: byłem w stanie zbliżyć się do układu, który chciałem, używając pętli do tworzenia głównych etykiet 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'))

Jednak jest to trochę jak robienie osi X za pomocą ax.annotate: możliwe, ale nie idealne.

brenda
źródło
1
Wiem, że to tak naprawdę nie odpowiada na pytanie, ale jako ogólne podejście, gdy naprawdę zależy mi na tym, jak wygląda fabuła, generalnie staram się uzyskać wersję wektorową i sprawić, by wyglądała ładnie w programie Illustrator lub Inkscape. Zauważyłem, że większość ludzi, których znam, robi to samo.
John McDonnell
2
Czy możesz po prostu całkowicie zignorować argumenty plotfunkcji pandy i ustawić wszystkie takty po wykreśleniu, używając metod matplotlib zwróconego axobiektu (np. ax.set_xticks)?
BrenBarn
@BrenBarn Nie mogłem wymyślić, jak uzyskać datę jako datę w Pythonie zamiast daty pandy dla metod matplotlib. Odpowiedź bmu naprawia to, konwertując daty przed wykreśleniem.
brenda

Odpowiedzi:

89

Oba pandasi matplotlib.datessłużą matplotlib.unitsdo lokalizowania kleszczy.

Ale chociaż matplotlib.datesma wygodne sposoby ręcznego ustawiania taktów, pandy wydają się do tej pory skupiać się na automatycznym formatowaniu (możesz rzucić okiem na kod konwersji daty i formatowania w pandach).

Tak więc na razie wydaje się bardziej rozsądne w użyciu matplotlib.dates(jak wspomniał @BrenBarn w swoim komentarzu).

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

(moje ustawienia regionalne to niemiecki, więc wtorek [wt] zmienia się w Dienstag [Di])

bmu
źródło