diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 8046cf7a3731..e1e10d519380 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -96,8 +96,11 @@ <../gallery/ticks_and_spines/date_demo_rrule.html>`_. * :class:`AutoDateLocator`: On autoscale, this class picks the best - :class:`MultipleDateLocator` to set the view limits and the tick - locations. + :class:`RRuleLocator` to set the view limits and the tick + locations. If called with ``interval_multiples=True`` it will + make ticks line up with sensible multiples of the tick intervals. E.g. + if the interval is 4 hours, it will pick hours 0, 4, 8, etc as ticks. + This behaviour is not garaunteed by default. Date formatters --------------- @@ -1189,15 +1192,15 @@ def get_locator(self, dmin, dmax): else: byranges[i] = self._byranges[i] - # We found what frequency to use break else: raise ValueError('No sensible date limit could be found in the ' 'AutoDateLocator.') - if use_rrule_locator[i]: + if (freq == YEARLY) and self.interval_multiples: + locator = YearLocator(interval) + elif use_rrule_locator[i]: _, bymonth, bymonthday, byhour, byminute, bysecond, _ = byranges - rrule = rrulewrapper(self._freq, interval=interval, dtstart=dmin, until=dmax, bymonth=bymonth, bymonthday=bymonthday, diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index f53fdb7dd1b3..7de1180a2d25 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -380,6 +380,79 @@ def _create_auto_date_locator(date1, date2): assert list(map(str, mdates.num2date(locator()))) == expected +def test_auto_date_locator_intmult(): + def _create_auto_date_locator(date1, date2): + locator = mdates.AutoDateLocator(interval_multiples=True) + locator.create_dummy_axis() + locator.set_view_interval(mdates.date2num(date1), + mdates.date2num(date2)) + return locator + + d1 = datetime.datetime(1997, 1, 1) + results = ([datetime.timedelta(weeks=52 * 200), + ['1980-01-01 00:00:00+00:00', '2000-01-01 00:00:00+00:00', + '2020-01-01 00:00:00+00:00', '2040-01-01 00:00:00+00:00', + '2060-01-01 00:00:00+00:00', '2080-01-01 00:00:00+00:00', + '2100-01-01 00:00:00+00:00', '2120-01-01 00:00:00+00:00', + '2140-01-01 00:00:00+00:00', '2160-01-01 00:00:00+00:00', + '2180-01-01 00:00:00+00:00', '2200-01-01 00:00:00+00:00'] + ], + [datetime.timedelta(weeks=52), + ['1997-01-01 00:00:00+00:00', '1997-02-01 00:00:00+00:00', + '1997-03-01 00:00:00+00:00', '1997-04-01 00:00:00+00:00', + '1997-05-01 00:00:00+00:00', '1997-06-01 00:00:00+00:00', + '1997-07-01 00:00:00+00:00', '1997-08-01 00:00:00+00:00', + '1997-09-01 00:00:00+00:00', '1997-10-01 00:00:00+00:00', + '1997-11-01 00:00:00+00:00', '1997-12-01 00:00:00+00:00'] + ], + [datetime.timedelta(days=141), + ['1997-01-01 00:00:00+00:00', '1997-01-22 00:00:00+00:00', + '1997-02-01 00:00:00+00:00', '1997-02-22 00:00:00+00:00', + '1997-03-01 00:00:00+00:00', '1997-03-22 00:00:00+00:00', + '1997-04-01 00:00:00+00:00', '1997-04-22 00:00:00+00:00', + '1997-05-01 00:00:00+00:00', '1997-05-22 00:00:00+00:00'] + ], + [datetime.timedelta(days=40), + ['1997-01-01 00:00:00+00:00', '1997-01-08 00:00:00+00:00', + '1997-01-15 00:00:00+00:00', '1997-01-22 00:00:00+00:00', + '1997-01-29 00:00:00+00:00', '1997-02-01 00:00:00+00:00', + '1997-02-08 00:00:00+00:00'] + ], + [datetime.timedelta(hours=40), + ['1997-01-01 00:00:00+00:00', '1997-01-01 04:00:00+00:00', + '1997-01-01 08:00:00+00:00', '1997-01-01 12:00:00+00:00', + '1997-01-01 16:00:00+00:00', '1997-01-01 20:00:00+00:00', + '1997-01-02 00:00:00+00:00', '1997-01-02 04:00:00+00:00', + '1997-01-02 08:00:00+00:00', '1997-01-02 12:00:00+00:00', + '1997-01-02 16:00:00+00:00'] + ], + [datetime.timedelta(minutes=20), + ['1997-01-01 00:00:00+00:00', '1997-01-01 00:05:00+00:00', + '1997-01-01 00:10:00+00:00', '1997-01-01 00:15:00+00:00', + '1997-01-01 00:20:00+00:00'] + ], + [datetime.timedelta(seconds=40), + ['1997-01-01 00:00:00+00:00', '1997-01-01 00:00:05+00:00', + '1997-01-01 00:00:10+00:00', '1997-01-01 00:00:15+00:00', + '1997-01-01 00:00:20+00:00', '1997-01-01 00:00:25+00:00', + '1997-01-01 00:00:30+00:00', '1997-01-01 00:00:35+00:00', + '1997-01-01 00:00:40+00:00'] + ], + [datetime.timedelta(microseconds=1500), + ['1996-12-31 23:59:59.999507+00:00', + '1997-01-01 00:00:00+00:00', + '1997-01-01 00:00:00.000502+00:00', + '1997-01-01 00:00:00.001005+00:00', + '1997-01-01 00:00:00.001508+00:00'] + ], + ) + + for t_delta, expected in results: + d2 = d1 + t_delta + locator = _create_auto_date_locator(d1, d2) + assert list(map(str, mdates.num2date(locator()))) == expected + + @image_comparison(baseline_images=['date_inverted_limit'], extensions=['png']) def test_date_inverted_limit():