Error with dates.DayLocator when specifying timezone?

Hey folks,

I'm plotting a simple rainfall record and when I tell the DayLocator to make sure to use 'US/Pacific' as it's time zone, it barfs on me. (US/Pacific is also set in my matplotlibrc file). When I don't specify the time zone, it doesn't barf, but the xticks are placed 8 hours off (presumably at the start of day GMT, right?). Am I not specifying the datetime.tzinfo object correctly?

The code and the traceback are below. The trace back mentions some EOF in a multi-line statement, but blames it on my fig.savefig(...) command.

Thanks for everything. This library is truly amazing. My mind is consistently blown as to what the developers have created.

Here's some code:
import numpy as np
import datetime as dt
import matplotlib.pyplot as pl
import matplotlib.dates as md

TZ = dt.tzinfo('US/Pacific')
dmin = dt.datetime(2009,12,22,0,0)
dmax = dt.datetime(2010,1,31,0,0)
delta = dt.timedelta(5/(24*60.))

dr = md.drange(dmin, dmax, delta)
y1 = np.zeros(len(dr)) + 1

fig = pl.figure(figsize=(7,4))
ax = fig.add_axes([0.10,0.13,0.85,0.82])

#~ --- this is where the error happens -------
#~ leave it as is for the point to be off
#~ OR
#~ uncomment the next line to produce the error
days = md.DayLocator(interval=4)
# days = md.DayLocator(interval=4, tz=TZ)

# verify xtick locations
a = dt.datetime(2009,12,26,0,0,0)
b = 4.5

L1 = ax.plot(dr, y1, 'b-', lw=1, label='Hourly')
p1 = ax.plot(a,b,'g.', label='Point not @ start of day')

ax.legend(loc='upper right')
ax.xaxis.set_major_locator(days)
ax.xaxis.set_major_formatter(md.DateFormatter('%m/%d'))

fig.savefig('storm.png')
# -------------------------------------------------------

The traceback:
In [138]: run storm_tracker
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (550, 0))

ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (550, 0))

ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (550, 0))

ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (91, 0))

···

---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)

c:\stuff\utils\py\storm_tracker.py in <module>()
     59 ax.set_ylim([0,5])
     60 ax.set_xlim([dmin, dmax])
---> 61 fig.savefig('storm.png')
     62
     63

C:\Python26\lib\site-packages\matplotlib\figure.pyc in savefig(self, *args, **kwargs)
   1030 patch.set_alpha(0.0)
   1031
-> 1032 self.canvas.print_figure(*args, **kwargs)
   1033
   1034 if transparent:

C:\Python26\lib\site-packages\matplotlib\backends\backend_qt4agg.pyc in print_figure(self, *args, **kwargs)
    142
    143 def print_figure(self, *args, **kwargs):
--> 144 FigureCanvasAgg.print_figure(self, *args, **kwargs)
    145 self.draw()
    146

C:\Python26\lib\site-packages\matplotlib\backend_bases.pyc in print_figure(self, filename, dpi, facecolor, edg
ecolor, orientation, format, **kwargs)
   1474 orientation=orientation,
   1475 bbox_inches_restore=_bbox_inches_restore,
-> 1476 **kwargs)
   1477 finally:
   1478 if bbox_inches and restore_bbox:

C:\Python26\lib\site-packages\matplotlib\backends\backend_agg.pyc in print_png(self, filename_or_obj, *args, *
*kwargs)
    356
    357 def print_png(self, filename_or_obj, *args, **kwargs):
--> 358 FigureCanvasAgg.draw(self)
    359 renderer = self.get_renderer()
    360 original_dpi = renderer.dpi

C:\Python26\lib\site-packages\matplotlib\backends\backend_agg.pyc in draw(self)
    312
    313 self.renderer = self.get_renderer()
--> 314 self.figure.draw(self.renderer)
    315
    316 def get_renderer(self):

C:\Python26\lib\site-packages\matplotlib\artist.pyc in draw_wrapper(artist, renderer, *kl)
     44 def draw_wrapper(artist, renderer, *kl):
     45 before(artist, renderer)
---> 46 draw(artist, renderer, *kl)
     47 after(artist, renderer)
     48

C:\Python26\lib\site-packages\matplotlib\figure.pyc in draw(self, renderer)
    771
    772 # render the axes

--> 773 for a in self.axes: a.draw(renderer)
    774
    775 # render the figure text

C:\Python26\lib\site-packages\matplotlib\artist.pyc in draw_wrapper(artist, renderer, *kl)
     44 def draw_wrapper(artist, renderer, *kl):
     45 before(artist, renderer)
---> 46 draw(artist, renderer, *kl)
     47 after(artist, renderer)
     48

C:\Python26\lib\site-packages\matplotlib\axes.pyc in draw(self, renderer, inframe)
   1733
   1734 for zorder, i, a in dsu:
-> 1735 a.draw(renderer)
   1736
   1737 renderer.close_group('axes')

C:\Python26\lib\site-packages\matplotlib\artist.pyc in draw_wrapper(artist, renderer, *kl)
     44 def draw_wrapper(artist, renderer, *kl):
     45 before(artist, renderer)
---> 46 draw(artist, renderer, *kl)
     47 after(artist, renderer)
     48

C:\Python26\lib\site-packages\matplotlib\axis.pyc in draw(self, renderer, *args, **kwargs)
    734 renderer.open_group(__name__)
    735 interval = self.get_view_interval()
--> 736 for tick, loc, label in self.iter_ticks():
    737 if tick is None: continue
    738 if not mtransforms.interval_contains(interval, loc): continue

C:\Python26\lib\site-packages\matplotlib\axis.pyc in iter_ticks(self)
    675 Iterate through all of the major and minor ticks.
    676 """
--> 677 majorLocs = self.major.locator()
    678 majorTicks = self.get_major_ticks(len(majorLocs))
    679 self.major.formatter.set_locs(majorLocs)

C:\Python26\lib\site-packages\matplotlib\dates.pyc in __call__(self)
    476 def __call__(self):
    477 # if no data have been set, this will tank with a ValueError

--> 478 try: dmin, dmax = self.viewlim_to_dt()
    479 except ValueError: return []
    480

C:\Python26\lib\site-packages\matplotlib\dates.pyc in viewlim_to_dt(self)
    452 def viewlim_to_dt(self):
    453 vmin, vmax = self.axis.get_view_interval()
--> 454 return num2date(vmin, self.tz), num2date(vmax, self.tz)
    455
    456 def _get_unit(self):

C:\Python26\lib\site-packages\matplotlib\dates.pyc in num2date(x, tz)
    247 """
    248 if tz is None: tz = _get_rc_timezone()
--> 249 if not cbook.iterable(x): return _from_ordinalf(x, tz)
    250 else: return [_from_ordinalf(val, tz) for val in x]
    251

C:\Python26\lib\site-packages\matplotlib\dates.pyc in _from_ordinalf(x, tz)
    177 dt = datetime.datetime(
    178 dt.year, dt.month, dt.day, int(hour), int(minute), int(second),
--> 179 microsecond, tzinfo=UTC).astimezone(tz)
    180
    181 if microsecond>999990: # compensate for rounding errors

NotImplementedError: a tzinfo subclass must implement utcoffset()
WARNING: Failure executing file: <storm_tracker.py>

Paul M. Hobson
Senior Staff Engineer
--
Geosyntec Consultants
55 SW Yamhill St, Ste 200
Portland, OR 97204
Phone: 503.222.9518
www.geosyntec.com