From 9eda3db0cb36fd2ace2c8b15d33b985e324b98c8 Mon Sep 17 00:00:00 2001 From: ImportanceOfBeingErnest Date: Wed, 10 Oct 2018 03:36:57 +0200 Subject: [PATCH 1/3] Update AutoDateFormatter with locator --- lib/matplotlib/axis.py | 10 ++++++++-- lib/matplotlib/tests/test_dates.py | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 23aa7e3a09af..09e233cb9a28 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1579,10 +1579,13 @@ def set_major_locator(self, locator): locator : ~matplotlib.ticker.Locator """ if not isinstance(locator, mticker.Locator): - raise TypeError("formatter argument should be instance of " + raise TypeError("locator argument should be instance of " "matplotlib.ticker.Locator") self.isDefault_majloc = False self.major.locator = locator + if (hasattr(self.get_major_formatter(), "_locator") and + hasattr(self.get_major_formatter(), "_tz")): + self.get_major_formatter()._locator = locator locator.set_axis(self) self.stale = True @@ -1595,10 +1598,13 @@ def set_minor_locator(self, locator): locator : ~matplotlib.ticker.Locator """ if not isinstance(locator, mticker.Locator): - raise TypeError("formatter argument should be instance of " + raise TypeError("locator argument should be instance of " "matplotlib.ticker.Locator") self.isDefault_minloc = False self.minor.locator = locator + if (hasattr(self.get_minor_formatter(), "_locator") and + hasattr(self.get_minor_formatter(), "_tz")): + self.get_minor_formatter()._locator = locator locator.set_axis(self) self.stale = True diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index da742c0236c9..5d93d8108e86 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -220,6 +220,27 @@ def test_DateFormatter(): fig.autofmt_xdate() +def test_locator_set_formatter(): + """ + Test if setting the locator only will update the formatter to use + the new locator. + """ + plt.rcParams["date.autoformatter.minute"] = "%d %H:%M" + t = [datetime.datetime(2018, 9, 30, 8, 0), + datetime.datetime(2018, 9, 30, 8, 59), + datetime.datetime(2018, 9, 30, 10, 30)] + x = [2, 3, 1] + + fig, ax = plt.subplots() + ax.plot(t, x) + ax.xaxis.set_major_locator(mdates.MinuteLocator((0, 30))) + fig.canvas.draw() + ticklabels = [tl.get_text() for tl in ax.get_xticklabels()] + expected = ['30 08:00', '30 08:30', '30 09:00', + '30 09:30', '30 10:00', '30 10:30'] + assert ticklabels == expected + + def test_date_formatter_strftime(): """ Tests that DateFormatter matches datetime.strftime, From c62ea1327c20be21cc96b8010484790ba6cbccd2 Mon Sep 17 00:00:00 2001 From: ImportanceOfBeingErnest Date: Mon, 15 Oct 2018 05:52:40 +0200 Subject: [PATCH 2/3] Update formatter with Locator in dates.py --- lib/matplotlib/axis.py | 8 ++------ lib/matplotlib/dates.py | 12 +++++++++++- lib/matplotlib/tests/test_dates.py | 14 +++++++++++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 09e233cb9a28..1292398e8299 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1567,6 +1567,8 @@ def set_minor_formatter(self, formatter): "matplotlib.ticker.Formatter") self.isDefault_minfmt = False self.minor.formatter = formatter + if hasattr(self.minor.formatter, "_ismajor"): + self.minor.formatter._ismajor = False formatter.set_axis(self) self.stale = True @@ -1583,9 +1585,6 @@ def set_major_locator(self, locator): "matplotlib.ticker.Locator") self.isDefault_majloc = False self.major.locator = locator - if (hasattr(self.get_major_formatter(), "_locator") and - hasattr(self.get_major_formatter(), "_tz")): - self.get_major_formatter()._locator = locator locator.set_axis(self) self.stale = True @@ -1602,9 +1601,6 @@ def set_minor_locator(self, locator): "matplotlib.ticker.Locator") self.isDefault_minloc = False self.minor.locator = locator - if (hasattr(self.get_minor_formatter(), "_locator") and - hasattr(self.get_minor_formatter(), "_tz")): - self.get_minor_formatter()._locator = locator locator.set_axis(self) self.stale = True diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 217b9cdc3dad..d392c5f35bad 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -806,6 +806,7 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): returned by ``locator._get_unit()``. """ self._locator = locator + self._ismajor = True self._tz = tz self.defaultfmt = defaultfmt self._formatter = DateFormatter(self.defaultfmt, tz) @@ -821,7 +822,16 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): rcParams['date.autoformatter.microsecond']} def __call__(self, x, pos=None): - locator_unit_scale = float(self._locator._get_unit()) + # Check if locator is still the one from the axis to format + if hasattr(self.axis, "get_major_locator"): + pot_locator = self.axis.get_major_locator() if self._ismajor \ + else self.axis.get_minor_locator() + if self._locator is not pot_locator: + self._locator = pot_locator + try: + locator_unit_scale = float(self._locator._get_unit()) + except AttributeError: + locator_unit_scale = 1 # Pick the first scale which is greater than the locator unit. fmt = next((fmt for scale, fmt in sorted(self.scaled.items()) if scale >= locator_unit_scale), diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index 5d93d8108e86..35e005346335 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -11,6 +11,7 @@ import matplotlib.pyplot as plt from matplotlib.cbook import MatplotlibDeprecationWarning import matplotlib.dates as mdates +import matplotlib.ticker as mticker def __has_pytz(): @@ -222,7 +223,7 @@ def test_DateFormatter(): def test_locator_set_formatter(): """ - Test if setting the locator only will update the formatter to use + Test if setting the locator only will update the AutoDateFormatter to use the new locator. """ plt.rcParams["date.autoformatter.minute"] = "%d %H:%M" @@ -240,6 +241,17 @@ def test_locator_set_formatter(): '30 09:30', '30 10:00', '30 10:30'] assert ticklabels == expected + ax.xaxis.set_major_locator(mticker.NullLocator()) + ax.xaxis.set_minor_locator(mdates.MinuteLocator((5, 55))) + decoy_loc = mdates.MinuteLocator((12, 27)) + ax.xaxis.set_minor_formatter(mdates.AutoDateFormatter(decoy_loc)) + + ax.xaxis.set_minor_locator(mdates.MinuteLocator((15, 45))) + fig.canvas.draw() + ticklabels = [tl.get_text() for tl in ax.get_xticklabels(which="minor")] + expected = ['30 08:15', '30 08:45', '30 09:15', '30 09:45', '30 10:15'] + assert ticklabels == expected + def test_date_formatter_strftime(): """ From 5dffdd13a43a655d099706e9ec44b182ef994ed0 Mon Sep 17 00:00:00 2001 From: ImportanceOfBeingErnest Date: Thu, 18 Oct 2018 20:55:55 +0200 Subject: [PATCH 3/3] Updatefmt with loc - introduce private locator setter --- lib/matplotlib/axis.py | 6 ++++-- lib/matplotlib/dates.py | 10 +++------- lib/matplotlib/ticker.py | 4 ++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 1292398e8299..359b1013ee37 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1567,8 +1567,6 @@ def set_minor_formatter(self, formatter): "matplotlib.ticker.Formatter") self.isDefault_minfmt = False self.minor.formatter = formatter - if hasattr(self.minor.formatter, "_ismajor"): - self.minor.formatter._ismajor = False formatter.set_axis(self) self.stale = True @@ -1585,6 +1583,8 @@ def set_major_locator(self, locator): "matplotlib.ticker.Locator") self.isDefault_majloc = False self.major.locator = locator + if self.major.formatter: + self.major.formatter._set_locator(locator) locator.set_axis(self) self.stale = True @@ -1601,6 +1601,8 @@ def set_minor_locator(self, locator): "matplotlib.ticker.Locator") self.isDefault_minloc = False self.minor.locator = locator + if self.minor.formatter: + self.minor.formatter._set_locator(locator) locator.set_axis(self) self.stale = True diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index d392c5f35bad..f9557d807e9d 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -806,7 +806,6 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): returned by ``locator._get_unit()``. """ self._locator = locator - self._ismajor = True self._tz = tz self.defaultfmt = defaultfmt self._formatter = DateFormatter(self.defaultfmt, tz) @@ -821,13 +820,10 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): 1. / (MUSECONDS_PER_DAY): rcParams['date.autoformatter.microsecond']} + def _set_locator(self, locator): + self._locator = locator + def __call__(self, x, pos=None): - # Check if locator is still the one from the axis to format - if hasattr(self.axis, "get_major_locator"): - pot_locator = self.axis.get_major_locator() if self._ismajor \ - else self.axis.get_minor_locator() - if self._locator is not pot_locator: - self._locator = pot_locator try: locator_unit_scale = float(self._locator._get_unit()) except AttributeError: diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 743ec642b48d..d39f2c41ab2e 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -301,6 +301,10 @@ def fix_minus(self, s): """ return s + def _set_locator(self, locator): + """ Subclasses may want to override this to set a locator. """ + pass + class IndexFormatter(Formatter): """