Tracé de la série temporelle Pandas définissant les graduations et les étiquettes majeures et mineures de l'axe X

87

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

La page "Quoi de neuf" de Pandas 0.9 indique:

"vous pouvez utiliser to_pydatetime ou enregistrer un convertisseur pour le type Timestamp"

mais je ne peux pas trouver comment faire cela pour pouvoir utiliser les commandes matplotlib ax.xaxis.set_major_locatoret ax.xaxis.set_major_formatter(et mineures).

Si je les utilise sans convertir les temps des pandas, les graduations et les étiquettes de l'axe des x se trompent.

En utilisant le paramètre 'xticks', je peux passer les graduations principales à pandas.plot, puis définir les étiquettes de graduation principales. Je ne peux pas comprendre comment faire les graduations mineures en utilisant cette approche. (Je peux définir les étiquettes sur les graduations mineures par défaut définies 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

Graphique avec des dates étranges sur 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

Graphique avec les dates correctes

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 pu me rapprocher de la mise en page que je voulais en utilisant une boucle pour créer les principales étiquettes 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 faire l'axe des x en utilisant ax.annotate: possible mais pas idéal.

Brenda
la source
1
Je sais que cela ne répond pas vraiment à la question, mais en tant qu'approche générale, lorsque je me soucie vraiment de l'apparence d'une intrigue, j'essaie généralement d'en obtenir une version vectorielle et de la rendre jolie dans Illustrator ou Inkscape. J'ai trouvé que la plupart des autres personnes que je connais semblent faire de même.
John McDonnell
2
Pouvez-vous ignorer totalement les arguments de la plotfonction pandas et définir toutes les graduations après le traçage, en utilisant les méthodes matplotlib de l' axobjet retourné (par exemple, ax.set_xticks)?
BrenBarn
@BrenBarn Je ne pouvais pas comprendre comment obtenir la date en tant que date python au lieu d'une date-heure pandas pour les méthodes matplotlib. La réponse de bmu corrige cela en convertissant les dates avant le traçage.
brenda

Réponses:

89

Les deux pandaset matplotlib.datesutiliser matplotlib.unitspour localiser les tiques.

Mais bien qu'il matplotlib.datesdispose de moyens pratiques pour définir les graduations manuellement, les pandas semblent jusqu'à présent se concentrer sur le formatage automatique (vous pouvez consulter le code de conversion de date et de formatage dans les pandas).

Donc pour le moment il semble plus raisonnable à utiliser matplotlib.dates(comme 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 [mar] devienne Dienstag [Di])

bmu
la source