2012-03-11 39 views
5

He estado buscando cómo hacer gráficas contra el tiempo en el eje x y tenerlo bastante ordenado, con una extraña peculiaridad que me hace preguntarme si he corrido en un error o (mucho más probable) estoy haciendo algo que realmente no entiendo.Configuración manual de xticks con xaxis_date() en Python/matplotlib

En pocas palabras, a continuación se muestra una versión simplificada de mi programa. Si pongo esto en un archivo .py y lo ejecuto desde un intérprete (ipython) obtengo una figura con un eje x con el año solamente, "2012", repetida varias veces, like this.

Sin embargo, si hago un comentario fuera de la línea (40) que establece los xticks manualmente, es decir 'plt.xticks (tk)' y luego ejecuto ese comando exacto en el intérprete inmediatamente después de ejecutar el script, funciona muy bien y la figura se ve like this.

De manera similar, también funciona si simplemente muevo esa línea para que esté después del comando savefig en el script, es decir para ponerlo al final del archivo. Por supuesto, en ambos casos, solo la figura dibujada en la pantalla tendrá el eje deseado, y no el archivo guardado. ¿Por qué no puedo establecer mi eje x antes?

Agradecido por cualquier información, gracias de antemano!

import matplotlib.pyplot as plt 
import datetime 

# define arrays for x, y and errors 
x=[16.7,16.8,17.1,17.4] 
y=[15,17,14,16] 
e=[0.8,1.2,1.1,0.9] 

xtn=[] 

# convert x to datetime format 
for t in x: 
    hours=int(t) 
    mins=int((t-int(t))*60) 
    secs=int(((t-hours)*60-mins)*60) 
    dt=datetime.datetime(2012,01,01,hours,mins,secs) 
    xtn.append(date2num(dt)) 

# set up plot 
fig=plt.figure() 
ax=fig.add_subplot(1,1,1) 

# plot 
ax.errorbar(xtn,y,yerr=e,fmt='+',elinewidth=2,capsize=0,color='k',ecolor='k') 

# set x axis range 
ax.xaxis_date() 
t0=date2num(datetime.datetime(2012,01,01,16,35)) # x axis startpoint 
t1=date2num(datetime.datetime(2012,01,01,17,35)) # x axis endpoint 
plt.xlim(t0,t1) 

# manually set xtick values 
tk=[] 
tk.append(date2num(datetime.datetime(2012,01,01,16,40))) 
tk.append(date2num(datetime.datetime(2012,01,01,16,50))) 
tk.append(date2num(datetime.datetime(2012,01,01,17,00))) 
tk.append(date2num(datetime.datetime(2012,01,01,17,10))) 
tk.append(date2num(datetime.datetime(2012,01,01,17,20))) 
tk.append(date2num(datetime.datetime(2012,01,01,17,30))) 
plt.xticks(tk) 

plt.show() 

# save to file 
plt.savefig('savefile.png') 

Respuesta

5

No creo que necesite esa llamada al xaxis_date(); ya que usted está proporcionando los datos del eje x en un formato que matplotlib sabe cómo manejar. También creo que hay algo ligeramente mal con tu fórmula secs.

Podemos hacer uso de formateadores y localizadores incorporadas de matplotlib a:

  1. conjunto los principales xticks a intervalos regulares (minutos, horas, días, etc.)
  2. personalizar la pantalla utilizando una strftime formateo cadena

Parece que si no se especifica un formateador, el valor predeterminado es mostrar el año; que es lo que estabas viendo

Trate de hacer esto:

import datetime as dt 
import matplotlib.pyplot as plt 
from matplotlib.dates import DateFormatter, MinuteLocator 

x = [16.7,16.8,17.1,17.4] 
y = [15,17,14,16] 
e = [0.8,1.2,1.1,0.9] 
xtn = [] 
for t in x: 
    h = int(t) 
    m = int((t-int(t))*60) 
    xtn.append(dt.datetime.combine(dt.date(2012,1,1), dt.time(h,m))) 

def larger_alim(alim): 
    ''' simple utility function to expand axis limits a bit ''' 
    amin,amax = alim 
    arng = amax-amin 
    nmin = amin - 0.1 * arng 
    nmax = amax + 0.1 * arng 
    return nmin,nmax 

plt.errorbar(xtn,y,yerr=e,fmt='+',elinewidth=2,capsize=0,color='k',ecolor='k') 
plt.gca().xaxis.set_major_locator(MinuteLocator(byminute=range(0,60,10))) 
plt.gca().xaxis.set_major_formatter(DateFormatter('%H:%M:%S')) 
plt.gca().set_xlim(larger_alim(plt.gca().get_xlim())) 
plt.show() 

Resultado:

enter image description here

Fwiw la función de utilidad larger_alim fue escrito originalmente para esta otra pregunta: Is there a way to tell matplotlib to loosen the zoom on the plotted data?