@@ -1168,6 +1168,15 @@ def __call__(self):
11681168 return self .tick_values (dmin , dmax )
11691169
11701170 def tick_values (self , vmin , vmax ):
1171+ start , stop = self ._create_rrule (vmin , vmax )
1172+ dates = self .rule .between (start , stop , True )
1173+ if len (dates ) == 0 :
1174+ return date2num ([vmin , vmax ])
1175+ return self .raise_if_exceeds (date2num (dates ))
1176+
1177+ def _create_rrule (self , vmin , vmax ):
1178+ # set appropriate rrule dtstart and until and return
1179+ # start and end
11711180 delta = relativedelta (vmax , vmin )
11721181
11731182 # We need to cap at the endpoints of valid datetime
@@ -1187,10 +1196,7 @@ def tick_values(self, vmin, vmax):
11871196
11881197 self .rule .set (dtstart = start , until = stop )
11891198
1190- dates = self .rule .between (vmin , vmax , True )
1191- if len (dates ) == 0 :
1192- return date2num ([vmin , vmax ])
1193- return self .raise_if_exceeds (date2num (dates ))
1199+ return vmin , vmax
11941200
11951201 def _get_unit (self ):
11961202 # docstring inherited
@@ -1454,7 +1460,7 @@ def get_locator(self, dmin, dmax):
14541460 return locator
14551461
14561462
1457- class YearLocator (DateLocator ):
1463+ class YearLocator (RRuleLocator ):
14581464 """
14591465 Make ticks on a given day of each year that is a multiple of base.
14601466
@@ -1471,52 +1477,28 @@ def __init__(self, base=1, month=1, day=1, tz=None):
14711477 Mark years that are multiple of base on a given month and day
14721478 (default jan 1).
14731479 """
1474- super ().__init__ (tz )
1480+ rule = rrulewrapper (YEARLY , interval = base , bymonth = month ,
1481+ bymonthday = day , ** self .hms0d )
1482+ super ().__init__ (rule , tz )
14751483 self .base = ticker ._Edge_integer (base , 0 )
1476- self .replaced = {'month' : month ,
1477- 'day' : day ,
1478- 'hour' : 0 ,
1479- 'minute' : 0 ,
1480- 'second' : 0 ,
1481- }
1482- if not hasattr (tz , 'localize' ):
1483- # if tz is pytz, we need to do this w/ the localize fcn,
1484- # otherwise datetime.replace works fine...
1485- self .replaced ['tzinfo' ] = tz
14861484
1487- def __call__ (self ):
1488- # if no data have been set, this will tank with a ValueError
1489- try :
1490- dmin , dmax = self .viewlim_to_dt ()
1491- except ValueError :
1492- return []
1485+ def _create_rrule (self , vmin , vmax ):
1486+ # 'start' needs to be a multiple of the interval to create ticks on
1487+ # interval multiples when the tick frequency is YEARLY
1488+ ymin = max (self .base .le (vmin .year ) * self .base .step , 1 )
1489+ ymax = min (self .base .ge (vmax .year ) * self .base .step , 9999 )
14931490
1494- return self .tick_values (dmin , dmax )
1491+ c = self .rule ._construct
1492+ replace = {'year' : ymin ,
1493+ 'month' : c .get ('bymonth' , 1 ),
1494+ 'day' : c .get ('bymonthday' , 1 ),
1495+ 'hour' : 0 , 'minute' : 0 , 'second' : 0 }
14951496
1496- def tick_values (self , vmin , vmax ):
1497- ymin = self .base .le (vmin .year ) * self .base .step
1498- ymax = self .base .ge (vmax .year ) * self .base .step
1499-
1500- vmin = vmin .replace (year = ymin , ** self .replaced )
1501- if hasattr (self .tz , 'localize' ):
1502- # look after pytz
1503- if not vmin .tzinfo :
1504- vmin = self .tz .localize (vmin , is_dst = True )
1505-
1506- ticks = [vmin ]
1507-
1508- while True :
1509- dt = ticks [- 1 ]
1510- if dt .year >= ymax :
1511- return date2num (ticks )
1512- year = dt .year + self .base .step
1513- dt = dt .replace (year = year , ** self .replaced )
1514- if hasattr (self .tz , 'localize' ):
1515- # look after pytz
1516- if not dt .tzinfo :
1517- dt = self .tz .localize (dt , is_dst = True )
1518-
1519- ticks .append (dt )
1497+ start = vmin .replace (** replace )
1498+ stop = start .replace (year = ymax )
1499+ self .rule .set (dtstart = start , until = stop )
1500+
1501+ return start , stop
15201502
15211503
15221504class MonthLocator (RRuleLocator ):
0 commit comments