Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually setting xticks with xaxis_date() in Python/matplotlib

I've been looking into how to make plots against time on the x axis and have it pretty much sorted, with one strange quirk that makes me wonder whether I've run into a bug or (admittedly much more likely) am doing something I don't really understand.

Simply put, below is a simplified version of my program. If I put this in a .py file and execute it from an interpreter (ipython) I get a figure with an x axis with the year only, "2012", repeated a number of times, like this.

However, if I comment out the line (40) that sets the xticks manually, namely 'plt.xticks(tk)' and then run that exact command in the interpreter immediately after executing the script, it works great and my figure looks like this.

Similarly it also works if I just move that line to be after the savefig command in the script, that's to say to put it at the very end of the file. Of course in both cases only the figure drawn on screen will have the desired axis, and not the saved file. Why can't I set my x axis earlier?

Grateful for any insights, thanks in advance!

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')
like image 351
anlag Avatar asked Mar 11 '12 00:03

anlag


People also ask

What is the use of Xticks () and Yticks () in plotting?

You can use the xticks() and yticks() functions and pass in an array denoting the actual ticks. On the X-axis, this array starts on 0 and ends at the length of the x array. On the Y-axis, it starts at 0 and ends at the max value of y . You can hard code the variables in as well.

How do you change the frequency of Xticks in Python?

MatPlotLib with Python Create x and y data points using numpy. Plot x and y data points using plot() method. Initialize a variable freq_x to adjust the frequency of the xticks. Use xticks() method to set the xticks.


Video Answer


1 Answers

I don't think you need that call to xaxis_date(); since you are already providing the x-axis data in a format that matplotlib knows how to deal with. I also think there's something slightly wrong with your secs formula.

We can make use of matplotlib's built-in formatters and locators to:

  1. set the major xticks to a regular interval (minutes, hours, days, etc.)
  2. customize the display using a strftime formatting string

It appears that if a formatter is not specified, the default is to display the year; which is what you were seeing.

Try this out:

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()

Result:

enter image description here

FWIW the utility function larger_alim was originally written for this other question: Is there a way to tell matplotlib to loosen the zoom on the plotted data?

like image 195
mechanical_meat Avatar answered Nov 15 '22 04:11

mechanical_meat