Tick location is seconds since the epoch. Use a :func:`strftime`
format string.
Python only supports :mod:`datetime` :func:`strftime` formatting
for years greater than 1900. Thanks to Andrew Dalke, Dalke
Scientific Software who contributed the :func:`strftime` code
below to include dates earlier than this year.
"""
illegal_s=re.compile(r"((^|[^%])(%%)*%s)")
def__init__(self, fmt, tz=None):
"""
*fmt* is an :func:`strftime` format string; *tz* is the
:class:`tzinfo` instance.
"""
iftzisNone: tz=_get_rc_timezone()
self.fmt=fmt
self.tz=tz
def__call__(self, x, pos=0):
ifx==0:
raiseValueError('DateFormatter found a value of x=0, which is an illegal date. This usually occurs because you have not informed the axis that it is plotting dates, eg with ax.xaxis_date()')
dt=num2date(x, self.tz)
returnself.strftime(dt, self.fmt)
defset_tzinfo(self, tz):
self.tz=tz
def_findall(self, text, substr):
# Also finds overlaps
sites= []
i=0
while1:
j=text.find(substr, i)
ifj==-1:
break
sites.append(j)
i=j+1
returnsites
# Dalke: I hope I did this math right. Every 28 years the
# calendar repeats, except through century leap years excepting
# the 400 year leap years. But only if you're using the Gregorian
# calendar.
defstrftime(self, dt, fmt):
fmt=self.illegal_s.sub(r"\1", fmt)
fmt=fmt.replace("%s", "s")
ifdt.year>1900:
returncbook.unicode_safe(dt.strftime(fmt))
year=dt.year
# For every non-leap year century, advance by
# 6 years to get into the 28-year repeat cycle
delta=2000-year
off=6*(delta//100+delta//400)
year=year+off
# Move to around the year 2000
year=year+ ((2000-year)//28)*28
timetuple=dt.timetuple()
s1=time.strftime(fmt, (year,) +timetuple[1:])
sites1=self._findall(s1, str(year))
s2=time.strftime(fmt, (year+28,) +timetuple[1:])
sites2=self._findall(s2, str(year+28))
sites= []
forsiteinsites1:
ifsiteinsites2:
sites.append(site)
s=s1
syear="%4d"% (dt.year,)
forsiteinsites:
s=s[:site] +syear+s[site+4:]
returncbook.unicode_safe(s)
classIndexDateFormatter(ticker.Formatter):
"""
Use with :class:`~matplotlib.ticker.IndexLocator` to cycle format
strings by index.
"""
def__init__(self, t, fmt, tz=None):
"""
*t* is a sequence of dates (floating point days). *fmt* is a
:func:`strftime` format string.
"""
iftzisNone: tz=_get_rc_timezone()
self.t=t
self.fmt=fmt
self.tz=tz
def__call__(self, x, pos=0):
'Return the label for time *x* at position *pos*'
ind=int(round(x))
ifind>=len(self.t) orind<=0: return''
dt=num2date(self.t[ind], self.tz)
returncbook.unicode_safe(dt.strftime(self.fmt))
classAutoDateFormatter(ticker.Formatter):
"""
This class attempts to figure out the best format to use. This is
most useful when used with the :class:`AutoDateLocator`.
The AutoDateFormatter has a scale dictionary that maps the scale
of the tick (the distance in days between one major tick) and a
format string. The default looks like this::
self.scaled = {
365.0 : '%Y',
30. : '%b %Y',
1.0 : '%b %d %Y',
1./24. : '%H:%M:%D',
}
The algorithm picks the key in the dictionary that is >= the
current scale and uses that format string. You can customize this
dictionary by doing::
formatter = AutoDateFormatter()
formatter.scaled[1/(24.*60.)] = '%M:%S' # only show min and sec
"""
# This can be improved by providing some user-level direction on
# how to choose the best format (precedence, etc...)
# Perhaps a 'struct' that has a field for each time-type where a
# zero would indicate "don't show" and a number would indicate
# "show" with some sort of priority. Same priorities could mean
# show all with the same priority.
# Or more simply, perhaps just a format string for each