Ci-dessous, j'ai le script suivant qui crée un graphique de série temporelle simple:
%matplotlib inline
import datetime
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
df = []
start_date = datetime.datetime(2015, 7, 1)
for i in range(10):
for j in [1,2]:
unit = 'Ones' if j == 1 else 'Twos'
date = start_date + datetime.timedelta(days=i)
df.append({
'Date': date.strftime('%Y%m%d'),
'Value': i * j,
'Unit': unit
})
df = pd.DataFrame(df)
sns.tsplot(df, time='Date', value='Value', unit='Unit', ax=ax)
fig.autofmt_xdate()
Et le résultat est le suivant:
Comme vous pouvez le constater, l’axe des x comporte des nombres étranges pour les dates-heures, et non les représentations "Nice" habituelles fournies avec matplotlib
et d’autres utilitaires de traçage. J'ai essayé beaucoup de choses, reformater les données mais elles ne sortent jamais proprement. Quelqu'un sait-il un moyen de contourner?
Matplotlib représente les dates sous forme de nombres à virgule flottante (en jours). Ainsi, à moins que vous (ou les pandas ou les natifs de la mer), leur disiez que vos valeurs représentent des dates, les ticks ne seront pas formatés en tant que dates. Je ne suis pas un expert né de la mer, mais il semble que cela convertisse les objets datetime
en dates matplotlib, mais n'affecte pas les localisateurs et les formateurs appropriés aux axes. C'est pourquoi vous obtenez ces nombres étranges, qui ne sont en fait que quelques jours depuis le 0001.01.01. Vous devrez donc vous occuper des tiques manuellement (ce qui, dans la plupart des cas, est meilleur de toute façon car cela vous donne plus de contrôle).
Vous devrez donc affecter un localisateur de date qui décidera où placer les ticks et un formateur de date qui formatera ensuite les chaînes pour les libellés de ticks.
import datetime
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
# build up the data
df = []
start_date = datetime.datetime(2015, 7, 1)
for i in range(10):
for j in [1,2]:
unit = 'Ones' if j == 1 else 'Twos'
date = start_date + datetime.timedelta(days=i)
# I believe it makes more sense to directly convert the datetime to a
# "matplotlib"-date (float), instead of creating strings and then let
# pandas parse the string again
df.append({
'Date': mdates.date2num(date),
'Value': i * j,
'Unit': unit
})
df = pd.DataFrame(df)
# build the figure
fig, ax = plt.subplots()
sns.tsplot(df, time='Date', value='Value', unit='Unit', ax=ax)
# assign locator and formatter for the xaxis ticks.
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y.%m.%d'))
# put the labels at 45deg since they tend to be too long
fig.autofmt_xdate()
plt.show()
Résultat:
Pour moi, la réponse de @ hitzg se traduit par "OverflowError: le nombre entier signé est supérieur au maximum" dans les profondeurs de DateFormatter.
En regardant mon cadre de données, mes index sont datetime64, pas datetime. Pandas les convertit bien cependant. Ce qui suit fonctionne très bien pour moi:
import matplotlib as mpl
def myFormatter(x, pos):
return pd.to_datetime(x)
[ . . . ]
ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))
Voici une solution potentiellement peu élégante, mais c’est la seule que j’ai ... Espérons que cela aide!
g = sns.pointplot(x, y, data=df, ci=False);
unique_dates = sorted(list(df['Date'].drop_duplicates()))
date_ticks = range(0, len(unique_dates), 5)
g.set_xticks(date_ticks);
g.set_xticklabels([unique_dates[i].strftime('%d %b') for i in date_ticks], rotation='vertical');
g.set_xlabel('Date');
Faites-moi savoir si vous voyez des problèmes!
def myFormatter(x, pos):
return pd.to_datetime(x).strftime('%Y%m%d')
ax.xaxis.set_major_formatter(mpl.ticker.FuncFormatter(myFormatter))