Pandas series de tiempo trazan la configuración del eje x, ticks y etiquetas mayores y menores


87

Quiero poder establecer los xticks mayores y menores y sus etiquetas para un gráfico de serie de tiempo trazada a partir de un objeto de serie de tiempo de Pandas.

La página de "novedades" de Pandas 0.9 dice:

"puede usar to_pydatetime o registrar un convertidor para el tipo de marca de tiempo"

pero no puedo averiguar cómo hacerlo para poder usar los comandos matplotlib ax.xaxis.set_major_locatory ax.xaxis.set_major_formatter(y menores).

Si los uso sin convertir los tiempos de los pandas, las marcas y etiquetas del eje x terminan mal.

Al usar el parámetro 'xticks', puedo pasar los ticks principales a pandas.plot y luego establecer las etiquetas de ticks principales. No puedo averiguar cómo hacer los ticks menores usando este enfoque. (Puedo configurar las etiquetas en los ticks menores predeterminados establecidos por pandas.plot)

Aquí está mi código de prueba:

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

y su salida:

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

Gráfico con fechas extrañas en 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

Gráfico con fechas correctas

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

Actualización: he podido acercarme al diseño que quería usando un bucle para construir las principales etiquetas 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'))

Sin embargo, esto es un poco como hacer el eje x usando ax.annotate: posible pero no ideal.


1
Sé que esto realmente no responde a la pregunta, pero como enfoque general cuando realmente me importa cómo se ve una trama, generalmente solo trato de obtener una versión vectorial y hacer que se vea bien en Illustrator o Inkscape. He descubierto que la mayoría de las personas que conozco parecen hacer lo mismo.
John McDonnell

2
¿Puede simplemente ignorar por completo los argumentos de la plotfunción pandas y establecer todos los ticks después del trazado, utilizando métodos matplotlib del axobjeto devuelto (por ejemplo, ax.set_xticks)?
BrenBarn

@BrenBarn No pude averiguar cómo obtener la fecha como una fecha de Python en lugar de una fecha y hora de pandas para los métodos matplotlib. La respuesta de bmu corrige eso al convertir las fechas antes de graficar.
brenda

Respuestas:


89

Ambos pandasy matplotlib.datesuso matplotlib.unitspara localizar las garrapatas.

Pero si matplotlib.datesbien tiene formas convenientes de configurar los ticks manualmente, los pandas parecen estar enfocados en el formateo automático hasta ahora (puede ver el código para la conversión de fechas y el formato en pandas).

Entonces, por el momento, parece más razonable de usar matplotlib.dates(como lo menciona @BrenBarn en su comentario).

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

(mi configuración regional es alemana, por lo que el martes [mar] se convierte en Dienstag [Di])

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.