84 votes

Tracé de séries temporelles Pandas définissant les tics majeurs et mineurs et les étiquettes de l'axe des x

Je souhaite être en mesure de définir les signes 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 dit :

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

mais je n'arrive pas à trouver comment le faire pour pouvoir utiliser la bibliothèque matplotlib. ax.xaxis.set_major_locator et ax.xaxis.set_major_formatter (et mineures).

Si je les utilise sans convertir les temps pandas, les tics et les étiquettes de l'axe des x sont erronés.

En utilisant le paramètre "xticks", je peux transmettre les ticks majeurs à pandas.plot, puis définir les étiquettes des ticks majeurs. Je n'arrive pas à trouver comment faire pour les ticks 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 son résultat :

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 pu me rapprocher de la mise en page que je voulais en utilisant une boucle pour construire 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'))

Mais c'est un peu comme faire l'axe des x en utilisant ax.annotate, possible mais pas idéal.

85voto

bmu Points 7109

Les deux sites pandas et matplotlib.dates utiliser matplotlib.units pour localiser les tiques.

Mais alors que matplotlib.dates dispose de moyens pratiques pour définir les points manuellement, mais pandas semble avoir mis l'accent sur le formatage automatique jusqu'à présent (vous pouvez jeter un coup d'œil à la section code pour la conversion et le formatage des dates dans pandas).

Ainsi, pour le moment, il semble plus raisonnable d'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, donc le mardi [Tue] devient Dienstag [Di]).

2voto

blaylockbk Points 416

Pour désactiver l'ajustement de la date de Pandas, vous devez ajouter l'argument x_compat=True

Ejemplo:

ds.plot(x_compat=True)

D'autres exemples sont présentés dans la documentation de Pandas : Suppression de l'ajustement de la résolution des tics

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X