From ff7655277820046e991f4b2045523e638cebd2ac Mon Sep 17 00:00:00 2001 From: Tobias Megies Date: Wed, 9 Oct 2013 13:45:21 +0200 Subject: [PATCH 1/2] AutoDateFormatter: More customizable formatting This allows custom functions to be used for formatting in the style of FuncFormatter. --- lib/matplotlib/dates.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index b2ffaa0c38e8..5008af5dd8f5 100755 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -505,9 +505,25 @@ class AutoDateFormatter(ticker.Formatter): dictionary by doing:: - formatter = AutoDateFormatter() - formatter.scaled[1/(24.*60.)] = '%M:%S' # only show min and sec - + >>> formatter = AutoDateFormatter() + >>> formatter.scaled[1/(24.*60.)] = '%M:%S' # only show min and sec + + Custom `FunctionFormatter`s can also be used. The following example shows + how to use a custom format function to strip trailing zeros from decimal + seconds and adds the date to the first ticklabel:: + + >>> def my_format_function(x, pos=None): + ... x = matplotlib.dates.num2date(x) + ... if pos == 0: + ... fmt = '%D %H:%M:%S.%f' + ... else: + ... fmt = '%H:%M:%S.%f' + ... label = x.strftime(fmt) + ... label = label.rstrip("0") + ... label = label.rstrip(".") + ... return label + >>> from matplotlib.ticker import FuncFormatter + >>> formatter.scaled[1/(24.*60.)] = FuncFormatter(my_format_function) """ # This can be improved by providing some user-level direction on @@ -536,7 +552,7 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): 1. / 24.: '%H:%M:%S', 1. / (24. * 60.): '%H:%M:%S.%f'} - def __call__(self, x, pos=0): + def __call__(self, x, pos=None): scale = float(self._locator._get_unit()) fmt = self.defaultfmt @@ -545,8 +561,13 @@ def __call__(self, x, pos=0): fmt = self.scaled[k] break - self._formatter = DateFormatter(fmt, self._tz) - return self._formatter(x, pos) + if isinstance(fmt, six.string_types): + self._formatter = DateFormatter(fmt, self._tz) + return self._formatter(x, pos) + elif six.callable(fmt): + return fmt(x, pos) + else: + raise NotImplementedError() class rrulewrapper: From be0aafbcb1c3c581e71ed0763d930974e83522dc Mon Sep 17 00:00:00 2001 From: Phil Elson Date: Tue, 7 Jan 2014 09:57:04 +0000 Subject: [PATCH 2/2] Updated @megies' PR to include a test and some other tweaks. --- lib/matplotlib/dates.py | 22 +++++++++++------- .../test_dates/date_axvspan.png | Bin 16786 -> 14147 bytes lib/matplotlib/tests/test_dates.py | 16 +++++++++++-- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 5008af5dd8f5..f904f0b9e645 100755 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -539,8 +539,9 @@ class AutoDateFormatter(ticker.Formatter): def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): """ - Autofmt the date labels. The default format is the one to use - if none of the times in scaled match + Autoformat the date labels. The default format is the one to use + if none of the values in ``self.scaled`` are greater than the unit + returned by ``locator._get_unit()``. """ self._locator = locator self._tz = tz @@ -553,21 +554,24 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): 1. / (24. * 60.): '%H:%M:%S.%f'} def __call__(self, x, pos=None): - scale = float(self._locator._get_unit()) + locator_unit_scale = float(self._locator._get_unit()) fmt = self.defaultfmt - for k in sorted(self.scaled): - if k >= scale: - fmt = self.scaled[k] + # Pick the first scale which is greater than the locator unit. + for possible_scale in sorted(self.scaled): + if possible_scale >= locator_unit_scale: + fmt = self.scaled[possible_scale] break if isinstance(fmt, six.string_types): self._formatter = DateFormatter(fmt, self._tz) - return self._formatter(x, pos) + result = self._formatter(x, pos) elif six.callable(fmt): - return fmt(x, pos) + result = fmt(x, pos) else: - raise NotImplementedError() + raise TypeError('Unexpected type passed to {!r}.'.formatter(self)) + + return result class rrulewrapper: diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_axvspan.png b/lib/matplotlib/tests/baseline_images/test_dates/date_axvspan.png index f80c92569357be55a8b739f0d045b7d181b35c96..b43d926fdb7e807a97177a2c38ca86cd852ea913 100644 GIT binary patch literal 14147 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 literal 16786 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