2012-06-29 31 views
79

Tengo un problema al intentar que mis marcas de fecha giren en matplotlib. Un pequeño programa de muestra está debajo. Si trato de rotar los tics al final, los tics no se rotan. Si trato de rotar los ticks como se muestra debajo del comentario 'crashes', entonces matplot lib falla.Marcadores de fecha y rotación en matplotlib

Esto solo ocurre si los valores-x son fechas. Si reemplazo la variable dates con la variable t en la llamada a avail_plot, la llamada xticks(rotation=70) funciona perfectamente dentro de avail_plot.

¿Alguna idea?

import numpy as np 
import matplotlib.pyplot as plt 
import datetime as dt 

def avail_plot(ax, x, y, label, lcolor): 
    ax.plot(x,y,'b') 
    ax.set_ylabel(label, rotation='horizontal', color=lcolor) 
    ax.get_yaxis().set_ticks([]) 

    #crashes 
    #plt.xticks(rotation=70) 

    ax2 = ax.twinx() 
    ax2.plot(x, [1 for a in y], 'b') 
    ax2.get_yaxis().set_ticks([]) 
    ax2.set_ylabel('testing') 

f, axs = plt.subplots(2, sharex=True, sharey=True) 
t = np.arange(0.01, 5, 1) 
s1 = np.exp(t) 
start = dt.datetime.now() 
dates=[] 
for val in t: 
    next_val = start + dt.timedelta(0,val) 
    dates.append(next_val) 
    start = next_val 

avail_plot(axs[0], dates, s1, 'testing', 'green') 
avail_plot(axs[1], dates, s1, 'testing2', 'red') 
plt.subplots_adjust(hspace=0, bottom=0.3) 
plt.yticks([0.5,],("","")) 
#doesn't crash, but does not rotate the xticks 
#plt.xticks(rotation=70) 
plt.show() 
+0

Para crear un gráfico con fechas en el eje x es una tarea tan común - es una pena que no haya más completa ejemplos por ahí. – alexw

+0

Me pregunto si esto no es un duplicado de https://stackoverflow.com/questions/10998621/rotate-axis-text-in-python-matplotlib – ImportanceOfBeingErnest

Respuesta

143

Si prefiere un enfoque orientado a objetos no-, mover plt.xticks (rotación = 70) a la derecha antes de las dos llamadas avail_plot, por ejemplo

plt.xticks(rotation=70) 
avail_plot(axs[0], dates, s1, 'testing', 'green') 
avail_plot(axs[1], dates, s1, 'testing2', 'red') 

Esto establece la propiedad de rotación antes de configurar las etiquetas. Dado que tiene dos ejes aquí, plt.xticks se confunde después de haber hecho las dos tramas. En el momento en que plt.xticks no hace nada, plt.gca() no le da los ejes que desea modificar, y así plt.xticks, que actúa en los ejes actuales, no va a funcionar.

Para un enfoque orientado a objetos no usar plt.xticks, puede utilizar

plt.setp(axs[1].xaxis.get_majorticklabels(), rotation=70) 

después de una llamada a avail_plot. Esto establece la rotación en los ejes correctos específicamente.

+8

Otra cosa útil: cuando llamas a 'plt.setp' puede establecer múltiples parámetros al especificarlos como argumentos de palabras clave adicionales. el kwarg 'horizontalalignment' es particularmente útil cuando gira las etiquetas tick:' plt.setp (axs [1] .xaxis.get_majorticklabels(), rotation = 70, horizontalalignment = 'right') ' – 8one6

+2

No me gusta esta solución ya que mezcla los enfoques pyplot y orientados a objetos. Puede llamar a 'ax.tick_params (axis = 'x', rotation = 70)' en cualquier lugar. –

+1

@TedPetrou ¿A qué te refieres con "mezclar" aquí? la solución 'plt.setp' está completamente orientada a objetos. Si no te gusta el hecho de que hay algún 'plt', usa' from matplotlib.artist import setp; setp (ax.get_xticklabels(), rotation = 90) 'en su lugar. – ImportanceOfBeingErnest

7

Otra forma de aplicar horizontalalignment y rotation a cada etiqueta garrapata está haciendo un bucle for sobre las etiquetas señalizadoras que desea cambiar:

import numpy as np 
import matplotlib.pyplot as plt 
import datetime as dt 

now = dt.datetime.now() 
hours = [now + dt.timedelta(minutes=x) for x in np.arange(0,24*60,10)] 
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)] 
hours_value = np.random.random(len(hours)) 
days_value = np.random.random(len(days)) 

fig, axs = plt.subplots(2) 
fig.subplots_adjust(hspace=0.75) 
axs[0].plot(hours,hours_value) 
axs[1].plot(days,days_value) 

for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels(): 
    label.set_rotation(30) 
    label.set_horizontalalignment("right") 

enter image description here

Y aquí es un ejemplo si quieres controlar la localización de marcas mayores y menores:

import numpy as np 
import matplotlib.pyplot as plt 
import datetime as dt 

fig, axs = plt.subplots(2) 
fig.subplots_adjust(hspace=0.75) 
now = dt.datetime.now() 
hours = [now + dt.timedelta(minutes=x) for x in np.arange(0,24*60,10)] 
days = [now + dt.timedelta(days=x) for x in np.arange(0,30,1/4.)] 

axs[0].plot(hours,np.random.random(len(hours))) 
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True) 
x_minor_lct = matplotlib.dates.HourLocator(byhour = range(0,25,1)) 
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct) 
axs[0].xaxis.set_major_locator(x_major_lct) 
axs[0].xaxis.set_minor_locator(x_minor_lct) 
axs[0].xaxis.set_major_formatter(x_fmt) 
axs[0].set_xlabel("minor ticks set to every hour, major ticks start with 00:00") 

axs[1].plot(days,np.random.random(len(days))) 
x_major_lct = mpl.dates.AutoDateLocator(minticks=2,maxticks=10, interval_multiples=True) 
x_minor_lct = matplotlib.dates.DayLocator(bymonthday = range(0,32,1)) 
x_fmt = matplotlib.dates.AutoDateFormatter(x_major_lct) 
axs[1].xaxis.set_major_locator(x_major_lct) 
axs[1].xaxis.set_minor_locator(x_minor_lct) 
axs[1].xaxis.set_major_formatter(x_fmt) 
axs[1].set_xlabel("minor ticks set to every day, major ticks show first day of month") 
for label in axs[0].get_xmajorticklabels() + axs[1].get_xmajorticklabels(): 
    label.set_rotation(30) 
    label.set_horizontalalignment("right") 

enter image description here

16

Una solución fácil que evita un bucle a través de los ticklabes es utilizar simplemente

fig.autofmt_xdate()

Este comando gira automáticamente las etiquetas de eje X y ajusta su posición. Los valores predeterminados son un ángulo de rotación de 30 ° y una alineación horizontal "derecha". Pero se pueden cambiar en la llamada de función

fig.autofmt_xdate(bottom=0.2, rotation=30, ha='right') 

El bottom argumento adicional es equivalente a establecer plt.subplots_adjust(bottom=bottom), que permite fijar la parte inferior de los ejes de relleno a un valor más grande para albergar los ticklabels rotados.

Así que, básicamente, aquí tiene todos los ajustes que necesita para tener un buen eje de fecha en un solo comando.

A good example se puede encontrar en la página matplotlib.

+0

¡Gran respuesta! ¡Gracias! – Abramodj

9

solución funciona para matplotlib 2.1+

Existe un método ejes tick_params que pueden cambiar las propiedades de garrapatas. También existe como un método de eje como set_tick_params

ax.tick_params(axis='x', rotation=45) 

O

ax.xaxis.set_tick_params(rotation=45) 

Como una nota, la solución actual mezcla la interfaz de estado (usando pyplot) con la interfaz orientada a objetos utilizando el comando plt.xticks(rotation=70). Dado que el código en la pregunta utiliza el enfoque orientado a objetos, es mejor mantener ese enfoque en todo momento. La solución da una buena solución explícita con plt.setp(axs[1].xaxis.get_majorticklabels(), rotation=70)

0

plt.imshow() método

import matplotlib.pyplot as plt 
import pandas as pd 

corr = df.corr() 
plt.imshow (corr, cmap='Blues') 
plt.xticks(range(len(corr.columns)), corr.columns, rotation=35) 
plt.yticks(range(len(corr.columns)), corr.columns) 
plt.colorbar() 
plt.show() 
Cuestiones relacionadas