web-dev-qa-db-fra.com

Pandas timeseries), réglage des graduations et des graduations majeures et mineures de l'axe des abscisses

Je veux pouvoir définir les xticks majeurs et mineurs et leurs étiquettes pour un graphe de série chronologique tracé à partir d'un objet de série temporelle Pandas.

La page Pandas 0.9 "quoi de neuf" dit:

"vous pouvez utiliser to_pydatetime ou enregistrer un convertisseur pour le type d'horodatage"

mais je ne peux pas comprendre comment faire cela pour pouvoir utiliser le matplotlib ax.xaxis.set_major_locator et ax.xaxis.set_major_formatter (et mineur) commandes.

Si je les utilise sans convertir les pandas fois), les graduations et les libellés de l'axe des x sont erronés.

En utilisant le paramètre 'xticks', je peux transmettre les repères principaux à pandas.plot, puis définir les libellés des repères principaux. Je ne peux pas comprendre comment faire les tics mineurs en utilisant cette approche. (Je peux définir les étiquettes sur les ticks mineurs par défaut définis par pandas.plot)

Voici mon code de test:

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

et sa sortie:

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

Graph with strange dates on xaxis

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

Graph with correct dates

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

Mise à jour: J'ai été en mesure de me rapprocher de la mise en page souhaitée en utilisant une boucle pour créer les principales étiquettes 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'))

Cependant, c'est un peu comme si on faisait l'axe des x en utilisant ax.annotate: possible mais pas idéal.

83
brenda

pandas et matplotlib.dates utilisation matplotlib.units pour localiser les tiques.

Mais en même temps matplotlib.dates dispose de moyens pratiques pour définir les graduations manuellement, pandas semble avoir jusqu’à présent mis l’accent sur le formatage automatique (vous pouvez consulter le code pour la conversion de date et mise en forme dans les pandas).

Donc, pour le moment, il semble plus raisonnable d'utiliser matplotlib.dates (mentionné par @BrenBarn dans son commentaire).

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

(ma langue est l'allemand, de sorte que mardi [mardi] devienne Dienstag [di])

83
bmu