From a6b5299336a15acd5dc215e0884d0a0df1d90846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Zabalza?= Date: Tue, 26 Jul 2016 08:57:25 +0100 Subject: [PATCH 1/2] use scalars below a min exponent in LogFormatterMathtext --- lib/matplotlib/rcsetup.py | 1 + lib/matplotlib/tests/test_ticker.py | 14 ++++++++++++++ lib/matplotlib/ticker.py | 9 +++++++++ matplotlibrc.template | 1 + 4 files changed, 25 insertions(+) diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 1fc24148c0a4..64e39ab71670 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1082,6 +1082,7 @@ def validate_animation_writer_path(p): 'axes.formatter.use_locale': [False, validate_bool], # Use the current locale to format ticks 'axes.formatter.use_mathtext': [False, validate_bool], + 'axes.formatter.min_exponent': [0, validate_int], # minimum exponent to format in scientific notation 'axes.formatter.useoffset': [True, validate_bool], 'axes.unicode_minus': [True, validate_bool], 'axes.color_cycle': [ diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 59deeaef892a..8ce49525aff9 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -251,6 +251,20 @@ def get_view_interval(self): formatter.axis = FakeAxis(1, base**50) yield _logfe_helper, formatter, base, locs, i, expected_result +def test_LogFormatterMathtext_min_exponent(): + fmt = mticker.LogFormatterMathtext() + + with matplotlib.rc_context({'axes.formatter.min_exponent': 0}): + assert fmt(1) == '${10^{0}}$' + assert fmt(1e-2) == '${10^{-2}}$' + assert fmt(1e2) == '${10^{2}}$' + + with matplotlib.rc_context({'axes.formatter.min_exponent': 3}): + assert fmt(1) == '${1}$' + assert fmt(1e-2) == '${0.01}$' + assert fmt(1e2) == '${100}$' + assert fmt(1e-3) == '${10^{-3}}$' + assert fmt(1e3) == '${10^{3}}$' def _pprint_helper(value, domain, expected): fmt = mticker.LogFormatter() diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index a2be7cbd805e..0a1ada102eae 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -959,6 +959,7 @@ def __call__(self, x, pos=None): """ b = self._base usetex = rcParams['text.usetex'] + min_exp = rcParams['axes.formatter.min_exponent'] # only label the decades if x == 0: @@ -969,6 +970,8 @@ def __call__(self, x, pos=None): fx = math.log(abs(x)) / math.log(b) is_decade = is_close_to_int(fx) + if is_decade: + fx = nearest_long(fx) sign_string = '-' if x < 0 else '' @@ -980,6 +983,12 @@ def __call__(self, x, pos=None): if not is_decade and self.labelOnlyBase: return '' + elif np.abs(fx) < min_exp: + if usetex: + return r'${0}{1:g}$'.format(sign_string, x) + else: + return '${0}$'.format(_mathdefault( + '{0}{1:g}'.format(sign_string, x))) elif not is_decade: if usetex: return (r'$%s%s^{%.2f}$') % \ diff --git a/matplotlibrc.template b/matplotlibrc.template index 9b96f90cbcee..6e565f3d94fa 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -315,6 +315,7 @@ backend : $TEMPLATE_BACKEND # separator in the fr_FR locale. #axes.formatter.use_mathtext : False # When True, use mathtext for scientific # notation. +#axes.formatter.min_exponent: 0 # minimum exponent to format in scientific notation #axes.formatter.useoffset : True # If True, the tick label formatter # will default to labeling ticks relative # to an offset when the data range is very From 50fe54e3ac4072a512eb41095b99c74f3457a440 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 1 Aug 2016 16:57:53 -0400 Subject: [PATCH 2/2] Fix text alignment --- lib/matplotlib/axis.py | 19 +++++++++++++++++++ lib/matplotlib/text.py | 13 +++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index b722e2602903..2911cab3c526 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -1098,6 +1098,9 @@ def get_tick_padding(self): return max(values) return 0.0 + def _adjust_ticks(self, renderer, ticks_to_draw): + pass + @allow_rasterization def draw(self, renderer, *args, **kwargs): 'Draw the axis lines, grid lines, tick lines and labels' @@ -1110,6 +1113,8 @@ def draw(self, renderer, *args, **kwargs): ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(ticks_to_draw, renderer) + self._adjust_ticks(renderer, ticks_to_draw) + for tick in ticks_to_draw: tick.draw(renderer) @@ -1680,6 +1685,20 @@ class XAxis(Axis): __name__ = 'xaxis' axis_name = 'x' + def _adjust_ticks(self, renderer, ticks_to_draw): + heights = [] + for tick in ticks_to_draw: + label1 = tick.label1 + text = label1.get_text() + is_math = label1.is_math_text(text) + _, h, _ = renderer.get_text_width_height_descent( + text, label1.get_fontproperties(), is_math) + heights.append(h) + max_height = max(heights) + + for tick, h in zip(ticks_to_draw, heights): + tick.label1.set_offset((0, max_height - h)) + def contains(self, mouseevent): """Test whether the mouse event occured in the x axis. """ diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 5cc75f719abd..f01bdc785564 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -233,6 +233,7 @@ def __init__(self, linespacing = 1.2 # Maybe use rcParam later. self._linespacing = linespacing self.set_rotation_mode(rotation_mode) + self._offset = (0, 0) self.update(kwargs) def update(self, kwargs): @@ -773,12 +774,13 @@ def draw(self, renderer): textobj._set_gc_clip(gc) angle = textobj.get_rotation() + ox, oy = self._offset for line, wh, x, y in info: mtext = textobj if len(info) == 1 else None - x = x + posx - y = y + posy + x = x + posx + ox + y = y + posy - oy if renderer.flipy(): y = canvash - y clean_line, ismath = textobj.is_math_text(line) @@ -803,6 +805,13 @@ def draw(self, renderer): renderer.close_group('text') self.stale = False + def set_offset(self, offset): + """ + Set extra offset (in pixel space) to be applied immediately + before drawing the text. + """ + self._offset = offset + def get_color(self): "Return the color of the text" return self._color