diff --git a/doc/users/recipes.rst b/doc/users/recipes.rst index 174241b79e7b..891b9d02beca 100644 --- a/doc/users/recipes.rst +++ b/doc/users/recipes.rst @@ -139,7 +139,7 @@ the x locations are formatted the same way the tick labels are, e.g., a higher degree of precision, e.g., giving us the exact date out mouse is hovering over. To fix the first problem, we can use :func:`matplotlib.figure.Figure.autofmt_xdate` and to fix the second -problem we can use the ``ax.fmt_xdata`` attribute which can be set to +problem we can use the ``ax.format_xdata`` attribute which can be set to any function that takes a scalar and returns a string. matplotlib has a number of date formatters built in, so we'll use one of those. @@ -157,7 +157,7 @@ a number of date formatters built in, so we'll use one of those. # use a more precise date string for the x axis locations in the # toolbar import matplotlib.dates as mdates - ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') + ax.format_xdata = mdates.DateFormatter('%Y-%m-%d').format_for_cursor plt.title('fig.autofmt_xdate fixes the labels') Now when you hover your mouse over the plotted data, you'll see date diff --git a/examples/api/custom_projection_example.py b/examples/api/custom_projection_example.py index 32018c534604..d0fba4a7c17f 100644 --- a/examples/api/custom_projection_example.py +++ b/examples/api/custom_projection_example.py @@ -291,12 +291,12 @@ class DegreeFormatter(Formatter): """ def __init__(self, round_to=1.0): + super(HammerAxes.DegreeFormatter, self).__init__() self._round_to = round_to - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): degrees = np.round(np.degrees(x) / self._round_to) * self._round_to - # \u00b0 : degree symbol - return "%d\u00b0" % degrees + return "%d\N{DEGREE SIGN}" % degrees def set_longitude_grid(self, degrees): """ diff --git a/examples/api/custom_scale_example.py b/examples/api/custom_scale_example.py index df8fe46d2737..dfd3aae59a2e 100644 --- a/examples/api/custom_scale_example.py +++ b/examples/api/custom_scale_example.py @@ -70,9 +70,8 @@ def set_default_locators_and_formatters(self, axis): value:: """ class DegreeFormatter(Formatter): - def __call__(self, x, pos=None): - # \u00b0 : degree symbol - return "%d\u00b0" % (np.degrees(x)) + def format_for_tick(self, x, pos=None): + return "%d\N{DEGREE SIGN}" % (np.degrees(x)) axis.set_major_locator(FixedLocator( np.radians(np.arange(-90, 90, 10)))) diff --git a/examples/api/date_demo.py b/examples/api/date_demo.py index 7e419bb9ee44..0f7702ea0b5b 100644 --- a/examples/api/date_demo.py +++ b/examples/api/date_demo.py @@ -52,7 +52,7 @@ # format the coords message box def price(x): return '$%1.2f' % x -ax.format_xdata = mdates.DateFormatter('%Y-%m-%d') +ax.format_xdata = mdates.DateFormatter('%Y-%m-%d').format_for_cursor ax.format_ydata = price ax.grid(True) diff --git a/examples/pylab_examples/contour_label_demo.py b/examples/pylab_examples/contour_label_demo.py index 42eb8f579406..d12a5508b47b 100644 --- a/examples/pylab_examples/contour_label_demo.py +++ b/examples/pylab_examples/contour_label_demo.py @@ -80,8 +80,7 @@ def __repr__(self): CS = plt.contour(X, Y, 100**Z, locator=plt.LogLocator()) fmt = ticker.LogFormatterMathtext() -fmt.create_dummy_axis() -plt.clabel(CS, CS.levels, fmt=fmt) +plt.clabel(CS, CS.levels, fmt=fmt.format_for_tick) plt.title("$100^Z$") plt.show() diff --git a/examples/pylab_examples/date_demo1.py b/examples/pylab_examples/date_demo1.py index 45fbf128840e..8e16c7db635e 100644 --- a/examples/pylab_examples/date_demo1.py +++ b/examples/pylab_examples/date_demo1.py @@ -45,8 +45,8 @@ # format the coords message box def price(x): return '$%1.2f' % x -ax.fmt_xdata = DateFormatter('%Y-%m-%d') -ax.fmt_ydata = price +ax.format_xdata = DateFormatter('%Y-%m-%d').format_for_cursor +ax.format_ydata = price ax.grid(True) fig.autofmt_xdate() diff --git a/examples/pylab_examples/date_demo_convert.py b/examples/pylab_examples/date_demo_convert.py index 693a6752a3ca..50b6f9befc9a 100644 --- a/examples/pylab_examples/date_demo_convert.py +++ b/examples/pylab_examples/date_demo_convert.py @@ -27,7 +27,7 @@ ax.xaxis.set_minor_locator(HourLocator(arange(0, 25, 6))) ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d')) -ax.fmt_xdata = DateFormatter('%Y-%m-%d %H:%M:%S') +ax.format_xdata = DateFormatter('%Y-%m-%d %H:%M:%S').format_for_cursor fig.autofmt_xdate() plt.show() diff --git a/examples/pylab_examples/date_index_formatter.py b/examples/pylab_examples/date_index_formatter.py index 1234bb5b5850..d66d5c1fc673 100644 --- a/examples/pylab_examples/date_index_formatter.py +++ b/examples/pylab_examples/date_index_formatter.py @@ -22,10 +22,11 @@ class MyFormatter(Formatter): def __init__(self, dates, fmt='%Y-%m-%d'): + super(MyFormatter, self).__init__() self.dates = dates self.fmt = fmt - def __call__(self, x, pos=0): + def format_for_tick(self, x, pos=0): 'Return the label for time x at position pos' ind = int(round(x)) if ind >= len(self.dates) or ind < 0: diff --git a/examples/pylab_examples/finance_work2.py b/examples/pylab_examples/finance_work2.py index 6fa0f3244e58..162bcad34fab 100644 --- a/examples/pylab_examples/finance_work2.py +++ b/examples/pylab_examples/finance_work2.py @@ -186,7 +186,7 @@ def moving_average_convergence(x, nslow=26, nfast=12): label.set_rotation(30) label.set_horizontalalignment('right') - ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') + ax.format_xdata = mdates.DateFormatter('%Y-%m-%d').format_for_cursor class MyLocator(mticker.MaxNLocator): diff --git a/examples/pylab_examples/newscalarformatter_demo.py b/examples/pylab_examples/newscalarformatter_demo.py index 1e525ad8cb6e..b17c42c63632 100644 --- a/examples/pylab_examples/newscalarformatter_demo.py +++ b/examples/pylab_examples/newscalarformatter_demo.py @@ -1,27 +1,6 @@ import matplotlib.pyplot as plt import numpy as np -from matplotlib.ticker import OldScalarFormatter, ScalarFormatter - -# Example 1 -x = np.arange(0, 1, .01) -fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2, figsize=(6, 6)) -fig.text(0.5, 0.975, 'The old formatter', - horizontalalignment='center', verticalalignment='top') -ax1.plot(x * 1e5 + 1e10, x * 1e-10 + 1e-5) -ax1.xaxis.set_major_formatter(OldScalarFormatter()) -ax1.yaxis.set_major_formatter(OldScalarFormatter()) - -ax2.plot(x * 1e5, x * 1e-4) -ax2.xaxis.set_major_formatter(OldScalarFormatter()) -ax2.yaxis.set_major_formatter(OldScalarFormatter()) - -ax3.plot(-x * 1e5 - 1e10, -x * 1e-5 - 1e-10) -ax3.xaxis.set_major_formatter(OldScalarFormatter()) -ax3.yaxis.set_major_formatter(OldScalarFormatter()) - -ax4.plot(-x * 1e5, -x * 1e-4) -ax4.xaxis.set_major_formatter(OldScalarFormatter()) -ax4.yaxis.set_major_formatter(OldScalarFormatter()) +from matplotlib.ticker import ScalarFormatter # Example 2 x = np.arange(0, 1, .01) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 6e9cddbd0445..969a598cb674 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2566,19 +2566,19 @@ def ticklabel_format(self, **kwargs): self.yaxis.major.formatter.set_scientific(sb) if scilimits is not None: if axis == 'both' or axis == 'x': - self.xaxis.major.formatter.set_powerlimits(scilimits) + self.xaxis.major.formatter.powerlimits = scilimits if axis == 'both' or axis == 'y': - self.yaxis.major.formatter.set_powerlimits(scilimits) + self.yaxis.major.formatter.powerlimits = scilimits if useOffset is not None: if axis == 'both' or axis == 'x': - self.xaxis.major.formatter.set_useOffset(useOffset) + self.xaxis.major.formatter.use_offset = useOffset if axis == 'both' or axis == 'y': - self.yaxis.major.formatter.set_useOffset(useOffset) + self.yaxis.major.formatter.use_offset = useOffset if useLocale is not None: if axis == 'both' or axis == 'x': - self.xaxis.major.formatter.set_useLocale(useLocale) + self.xaxis.major.formatter.use_locale = useLocale if axis == 'both' or axis == 'y': - self.yaxis.major.formatter.set_useLocale(useLocale) + self.yaxis.major.formatter.use_locale = useLocale except AttributeError: raise AttributeError( "This method only works with the ScalarFormatter.") @@ -3268,30 +3268,12 @@ def yaxis_date(self, tz=None): self.yaxis.axis_date(tz) def format_xdata(self, x): - """ - Return *x* string formatted. This function will use the attribute - self.fmt_xdata if it is callable, else will fall back on the xaxis - major formatter - """ - try: - return self.fmt_xdata(x) - except TypeError: - func = self.xaxis.get_major_formatter().format_data_short - val = func(x) - return val + return (self.fmt_xdata(x) if self.fmt_xdata is not None + else self.xaxis.get_major_formatter().format_for_cursor(x)) def format_ydata(self, y): - """ - Return y string formatted. This function will use the - :attr:`fmt_ydata` attribute if it is callable, else will fall - back on the yaxis major formatter - """ - try: - return self.fmt_ydata(y) - except TypeError: - func = self.yaxis.get_major_formatter().format_data_short - val = func(y) - return val + return (self.fmt_ydata(y) if self.fmt_ydata is not None + else self.yaxis.get_major_formatter().format_for_cursor(y)) def format_coord(self, x, y): """Return a format string formatting the *x*, *y* coord""" diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 8062ebc66e4a..76b2b9100e39 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -901,14 +901,14 @@ def iter_ticks(self): """ majorLocs = self.major.locator() majorTicks = self.get_major_ticks(len(majorLocs)) - self.major.formatter.set_locs(majorLocs) - majorLabels = [self.major.formatter(val, i) + self.major.formatter.locs = majorLocs + majorLabels = [self.major.formatter.format_for_tick(val, i) for i, val in enumerate(majorLocs)] minorLocs = self.minor.locator() minorTicks = self.get_minor_ticks(len(minorLocs)) - self.minor.formatter.set_locs(minorLocs) - minorLabels = [self.minor.formatter(val, i) + self.minor.formatter.locs = minorLocs + minorLabels = [self.minor.formatter.format_for_tick(val, i) for i, val in enumerate(minorLocs)] major_minor = [ @@ -1087,7 +1087,7 @@ def get_tightbbox(self, renderer): self._update_label_position(ticklabelBoxes, ticklabelBoxes2) self._update_offset_text_position(ticklabelBoxes, ticklabelBoxes2) - self.offsetText.set_text(self.major.formatter.get_offset()) + self.offsetText.set_text(self.major.formatter.offset_text) bb = [] @@ -1140,7 +1140,7 @@ def draw(self, renderer, *args, **kwargs): self.label.draw(renderer) self._update_offset_text_position(ticklabelBoxes, ticklabelBoxes2) - self.offsetText.set_text(self.major.formatter.get_offset()) + self.offsetText.set_text(self.major.formatter.offset_text) self.offsetText.draw(renderer) if 0: # draw the bounding boxes around the text for debug diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index ad6a145a9d12..0dd9a3599683 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -370,16 +370,16 @@ def update_ticks(self): called whenever the tick locator and/or tick formatter changes. """ ax = self.ax - ticks, ticklabels, offset_string = self._ticker() + ticks, ticklabels, offset_text = self._ticker() if self.orientation == 'vertical': ax.yaxis.set_ticks(ticks) ax.set_yticklabels(ticklabels) - ax.yaxis.get_major_formatter().set_offset_string(offset_string) + ax.yaxis.get_major_formatter().offset_text = offset_text else: ax.xaxis.set_ticks(ticks) ax.set_xticklabels(ticklabels) - ax.xaxis.get_major_formatter().set_offset_string(offset_string) + ax.xaxis.get_major_formatter().offset_text = offset_text def set_ticks(self, ticks, update_ticks=True): """ @@ -584,12 +584,12 @@ def _ticker(self): intv = self._values[0], self._values[-1] else: intv = self.vmin, self.vmax - locator.create_dummy_axis(minpos=intv[0]) - formatter.create_dummy_axis(minpos=intv[0]) - locator.set_view_interval(*intv) - locator.set_data_interval(*intv) - formatter.set_view_interval(*intv) - formatter.set_data_interval(*intv) + locator.set_axis({"minpos": intv[0]}) + formatter.set_axis({"minpos": intv[0]}) + locator.axis.set_view_interval(*intv) + locator.axis.set_data_interval(*intv) + formatter.axis.set_view_interval(*intv) + formatter.axis.set_data_interval(*intv) b = np.array(locator()) if isinstance(locator, ticker.LogLocator): @@ -599,10 +599,9 @@ def _ticker(self): eps = (intv[1] - intv[0]) * 1e-10 b = b[(b <= intv[1] + eps) & (b >= intv[0] - eps)] ticks = self._locate(b) - formatter.set_locs(b) - ticklabels = [formatter(t, i) for i, t in enumerate(b)] - offset_string = formatter.get_offset() - return ticks, ticklabels, offset_string + formatter.locs = b + ticklabels = [formatter.format_for_tick(t, i) for i, t in enumerate(b)] + return ticks, ticklabels, formatter.offset_text def _process_values(self, b=None): ''' diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index fbd0bf480cda..29e3c9c1e2a9 100755 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -470,12 +470,13 @@ def __init__(self, fmt, tz=None): *fmt* is a :func:`strftime` format string; *tz* is the :class:`tzinfo` instance. """ + super(DateFormatter, self).__init__() if tz is None: tz = _get_rc_timezone() self.fmt = fmt self.tz = tz - def __call__(self, x, pos=0): + def format_for_tick(self, x, pos=0): if x == 0: raise ValueError('DateFormatter found a value of x=0, which is ' 'an illegal date. This usually occurs because ' @@ -601,13 +602,14 @@ def __init__(self, t, fmt, tz=None): *t* is a sequence of dates (floating point days). *fmt* is a :func:`strftime` format string. """ + super(IndexDateFormatter, self).__init__() if tz is None: tz = _get_rc_timezone() self.t = t self.fmt = fmt self.tz = tz - def __call__(self, x, pos=0): + def format_for_tick(self, x, pos=0): 'Return the label for time *x* at position *pos*' ind = int(np.round(x)) if ind >= len(self.t) or ind <= 0: @@ -681,6 +683,7 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): if none of the values in ``self.scaled`` are greater than the unit returned by ``locator._get_unit()``. """ + super(AutoDateFormatter, self).__init__() self._locator = locator self._tz = tz self.defaultfmt = defaultfmt @@ -694,7 +697,7 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): 1. / (SEC_PER_DAY): rcParams['date.autoformatter.second']} - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): locator_unit_scale = float(self._locator._get_unit()) fmt = self.defaultfmt @@ -706,7 +709,7 @@ def __call__(self, x, pos=None): if isinstance(fmt, six.string_types): self._formatter = DateFormatter(fmt, self._tz) - result = self._formatter(x, pos) + result = self._formatter.format_for_tick(x, pos) elif six.callable(fmt): result = fmt(x, pos) else: @@ -1130,9 +1133,6 @@ def get_locator(self, dmin, dmax): locator = MicrosecondLocator(interval, tz=self.tz) locator.set_axis(self.axis) - - locator.set_view_interval(*self.axis.get_view_interval()) - locator.set_data_interval(*self.axis.get_data_interval()) return locator @@ -1357,14 +1357,6 @@ def set_axis(self, axis): self._wrapped_locator.set_axis(axis) return DateLocator.set_axis(self, axis) - def set_view_interval(self, vmin, vmax): - self._wrapped_locator.set_view_interval(vmin, vmax) - return DateLocator.set_view_interval(self, vmin, vmax) - - def set_data_interval(self, vmin, vmax): - self._wrapped_locator.set_data_interval(vmin, vmax) - return DateLocator.set_data_interval(self, vmin, vmax) - def __call__(self): # if no data have been set, this will tank with a ValueError try: diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index 338deec8279d..504a0ebc9d98 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -30,9 +30,10 @@ class ThetaFormatter(Formatter): unit of radians into degrees and adds a degree symbol. """ def __init__(self, round_to=1.0): + super(GeoAxes.ThetaFormatter, self).__init__() self._round_to = round_to - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): degrees = (x / np.pi) * 180.0 degrees = np.round(degrees / self._round_to) * self._round_to if rcParams['text.usetex'] and not rcParams['text.latex.unicode']: diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index a52e343bb07e..db9a359f5ffa 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -171,7 +171,7 @@ class ThetaFormatter(Formatter): Used to format the *theta* tick labels. Converts the native unit of radians into degrees and adds a degree symbol. """ - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): # \u00b0 : degree symbol if rcParams['text.usetex'] and not rcParams['text.latex.unicode']: return r"$%0.0f^\circ$" % ((x / np.pi) * 180.0) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 23feaf7f57be..c0ec1a8a5c01 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -59,7 +59,7 @@ from matplotlib.patches import Polygon, Rectangle, Circle, Arrow from matplotlib.widgets import SubplotTool, Button, Slider, Widget -from .ticker import TickHelper, Formatter, FixedFormatter, NullFormatter,\ +from .ticker import Formatter, FixedFormatter, NullFormatter,\ FuncFormatter, FormatStrFormatter, ScalarFormatter,\ LogFormatter, LogFormatterExponent, LogFormatterMathtext,\ Locator, IndexLocator, FixedLocator, NullLocator,\ diff --git a/lib/matplotlib/testing/jpl_units/StrConverter.py b/lib/matplotlib/testing/jpl_units/StrConverter.py index cdf44d903b07..9aa7750e7a2e 100644 --- a/lib/matplotlib/testing/jpl_units/StrConverter.py +++ b/lib/matplotlib/testing/jpl_units/StrConverter.py @@ -127,7 +127,6 @@ def convert( value, unit, axis ): axis.set_ticklabels( labels ) # we have to do the following lines to make ax.autoscale_view work loc = axis.get_major_locator() - loc.set_bounds( ticks[0], ticks[-1] ) if ( isXAxis ): ax.set_xlim( ticks[0], ticks[-1] ) diff --git a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py index c5e3307e1d66..5fb407766a70 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py +++ b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py @@ -89,7 +89,7 @@ def axisinfo( unit, axis ): # If we want degrees for a polar plot, use the PolarPlotFormatter majfmt = polar.PolarAxes.ThetaFormatter() else: - majfmt = U.UnitDblFormatter( useOffset = False ) + majfmt = U.UnitDblFormatter() return units.AxisInfo( majfmt = majfmt, label = label ) diff --git a/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py b/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py index b4ccb1d21b09..8b186162a4cd 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py +++ b/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py @@ -23,25 +23,9 @@ __all__ = [ 'UnitDblFormatter' ] #=========================================================================== -class UnitDblFormatter( ticker.ScalarFormatter ): - """The formatter for UnitDbl data types. This allows for formatting - with the unit string. - """ - def __init__( self, *args, **kwargs ): - 'The arguments are identical to matplotlib.ticker.ScalarFormatter.' - ticker.ScalarFormatter.__init__( self, *args, **kwargs ) - - def __call__( self, x, pos = None ): - 'Return the format for tick val x at position pos' - if len(self.locs) == 0: - return '' - else: - return str(x) - - def format_data_short( self, value ): - "Return the value formatted in 'short' format." - return str(value) - - def format_data( self, value ): - "Return the value formatted into a string." - return str(value) +class UnitDblFormatter(ticker.Formatter): + """The formatter for UnitDbl data types. This allows for formatting + with the unit string. + """ + def format_for_tick(self, value, pos=None): + return str(value) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf index ec3ad7f1ce74..f199a3f75e79 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png index 457a4cdcbfae..602e54029b6e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg index 20b200e11b39..b46dda5771bd 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg @@ -27,7 +27,7 @@ z " style="fill:#ffffff;"/> - @@ -57,20 +57,20 @@ L 518.400024 43.2 +" id="md6960c55f4" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="me8e5a1c3e0" style="stroke:#000000;stroke-width:0.5;"/> - + @@ -115,22 +115,22 @@ Q 6.59375 54.828125 13.0625 64.515625 Q 19.53125 74.21875 31.78125 74.21875 " id="DejaVuSans-30"/> - + - - + + - + - + @@ -160,22 +160,22 @@ Q 44.1875 33.984375 37.640625 27.21875 Q 31.109375 20.453125 19.1875 8.296875 " id="DejaVuSans-32"/> - + - - + + - + - + @@ -199,22 +199,22 @@ L 4.890625 26.703125 z " id="DejaVuSans-34"/> - + - - + + - + - + @@ -249,22 +249,22 @@ Q 40.921875 74.21875 44.703125 73.484375 Q 48.484375 72.75 52.59375 71.296875 " id="DejaVuSans-36"/> - + - - + + - + - + @@ -307,56 +307,70 @@ Q 25.390625 66.40625 21.84375 63.234375 Q 18.3125 60.0625 18.3125 54.390625 " id="DejaVuSans-38"/> - + - - + + - + - + - + - - + + - + - + - + - - + + - + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -472,152 +495,153 @@ z +" id="me44b38b30c" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="mda8a1b39f7" style="stroke:#000000;stroke-width:0.5;"/> - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - + - - - + + + - - - - - - + + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf index e871bd270bf2..980ebc1fe854 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf and b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png index 01d086b738d9..a0867256ee74 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png and b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg index 589c70359f61..c869f0953d3d 100644 --- a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg +++ b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg @@ -27,7 +27,7 @@ z " style="fill:#ffffff;"/> - +" id="m75a748e1cc" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="m0255bfac70" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -197,20 +197,20 @@ L 0 4 +" id="mb9b80b1413" style="stroke:#000000;stroke-width:0.5;"/> - + +" id="mc0c71078d8" style="stroke:#000000;stroke-width:0.5;"/> - + @@ -236,7 +236,7 @@ Q 6.59375 54.828125 13.0625 64.515625 Q 19.53125 74.21875 31.78125 74.21875 " id="DejaVuSans-30"/> - + @@ -244,12 +244,12 @@ Q 19.53125 74.21875 31.78125 74.21875 - + - + @@ -269,7 +269,7 @@ L 12.40625 0 z " id="DejaVuSans-31"/> - + @@ -277,12 +277,12 @@ z - + - + @@ -312,7 +312,7 @@ Q 44.1875 33.984375 37.640625 27.21875 Q 31.109375 20.453125 19.1875 8.296875 " id="DejaVuSans-32"/> - + @@ -320,12 +320,12 @@ Q 31.109375 20.453125 19.1875 8.296875 - + - + @@ -363,7 +363,7 @@ Q 53.90625 49.265625 50.4375 45.09375 Q 46.96875 40.921875 40.578125 39.3125 " id="DejaVuSans-33"/> - + @@ -371,12 +371,12 @@ Q 46.96875 40.921875 40.578125 39.3125 - + - + @@ -400,7 +400,7 @@ L 4.890625 26.703125 z " id="DejaVuSans-34"/> - + @@ -408,12 +408,12 @@ z - + - + @@ -444,7 +444,7 @@ Q 14.890625 38.140625 10.796875 36.28125 z " id="DejaVuSans-35"/> - + @@ -452,12 +452,12 @@ z - + - + @@ -492,7 +492,7 @@ Q 40.921875 74.21875 44.703125 73.484375 Q 48.484375 72.75 52.59375 71.296875 " id="DejaVuSans-36"/> - + @@ -500,12 +500,12 @@ Q 48.484375 72.75 52.59375 71.296875 - + - + @@ -521,7 +521,7 @@ L 8.203125 64.59375 z " id="DejaVuSans-37"/> - + @@ -529,12 +529,12 @@ z - + - + @@ -577,7 +577,7 @@ Q 25.390625 66.40625 21.84375 63.234375 Q 18.3125 60.0625 18.3125 54.390625 " id="DejaVuSans-38"/> - + @@ -585,12 +585,12 @@ Q 18.3125 60.0625 18.3125 54.390625 - + - + @@ -625,14 +625,28 @@ Q 16.21875 41.5 20.09375 36.953125 Q 23.96875 32.421875 30.609375 32.421875 " id="DejaVuSans-39"/> - + - + + - - - - + + + + + @@ -675,7 +690,7 @@ z " style="fill:#ffffff;"/> - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -833,120 +848,120 @@ L 518.4 43.2 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -962,7 +977,7 @@ z " style="fill:#ffffff;"/> - - + - + - + @@ -1016,17 +1031,17 @@ L 274.909091 231.709091 - + - + - + @@ -1034,17 +1049,17 @@ L 274.909091 231.709091 - + - + - + @@ -1052,17 +1067,17 @@ L 274.909091 231.709091 - + - + - + @@ -1070,17 +1085,17 @@ L 274.909091 231.709091 - + - + - + @@ -1088,17 +1103,17 @@ L 274.909091 231.709091 - + - + - + @@ -1106,17 +1121,17 @@ L 274.909091 231.709091 - + - + - + @@ -1124,17 +1139,17 @@ L 274.909091 231.709091 - + - + - + @@ -1142,17 +1157,17 @@ L 274.909091 231.709091 - + - + - + @@ -1160,27 +1175,28 @@ L 274.909091 231.709091 - + - + - + - - - - - + + + + + + @@ -1188,17 +1204,17 @@ L 274.909091 231.709091 - + - + - + @@ -1206,17 +1222,17 @@ L 274.909091 231.709091 - + - + - + @@ -1224,17 +1240,17 @@ L 274.909091 231.709091 - + - + - + @@ -1242,17 +1258,17 @@ L 274.909091 231.709091 - + - + - + @@ -1260,17 +1276,17 @@ L 274.909091 231.709091 - + - + - + @@ -1278,17 +1294,17 @@ L 274.909091 231.709091 - + - + - + @@ -1296,17 +1312,17 @@ L 274.909091 231.709091 - + - + - + @@ -1314,17 +1330,17 @@ L 274.909091 231.709091 - + - + - + @@ -1332,17 +1348,17 @@ L 274.909091 231.709091 - + - + - + @@ -1350,27 +1366,28 @@ L 274.909091 231.709091 - + - + - + - - - - - + + + + + + @@ -1385,7 +1402,7 @@ z " style="fill:#ffffff;"/> - - + - + - + @@ -1439,176 +1456,176 @@ L 518.4 231.709091 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + - + - - - + + + + + + + + @@ -1637,120 +1665,120 @@ z - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1758,17 +1786,17 @@ z - - + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/test_backend_ps.py b/lib/matplotlib/tests/test_backend_ps.py index ab346a4d0a41..b92479bd49fa 100644 --- a/lib/matplotlib/tests/test_backend_ps.py +++ b/lib/matplotlib/tests/test_backend_ps.py @@ -13,6 +13,8 @@ from matplotlib import patheffects from matplotlib.testing.decorators import cleanup, knownfailureif +from nose.tools import assert_equal + needs_ghostscript = knownfailureif( matplotlib.checkdep_ghostscript()[0] is None, @@ -51,8 +53,8 @@ def _test_savefig_to_stringio(format='ps', use_log=False): # could change from run to run, such as the time. values = [re.sub(b'%%.*?\n', b'', x) for x in values] - assert values[0] == values[1] - assert values[1] == values[2].replace(b'\r\n', b'\n') + assert_equal(values[0], values[1]) + assert_equal(values[1], values[2].replace(b'\r\n', b'\n')) for buffer in buffers: buffer.close() @@ -112,13 +114,13 @@ def test_composite_image(): fig.savefig(ps, format="ps") ps.seek(0) buff = ps.read() - assert buff.count(six.b(' colorimage')) == 1 + assert_equal(buff.count(six.b(' colorimage')), 1) plt.rcParams['image.composite_image'] = False with io.BytesIO() as ps: fig.savefig(ps, format="ps") ps.seek(0) buff = ps.read() - assert buff.count(six.b(' colorimage')) == 2 + assert_equal(buff.count(six.b(' colorimage')), 2) @cleanup diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index 54afc633bf7e..c830c488d90c 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -216,7 +216,7 @@ def test_date_formatter_callable(): formatter = mdates.AutoDateFormatter(locator) formatter.scaled[-10] = callable_formatting_function - assert_equal(formatter([datetime.datetime(2014, 12, 25)]), + assert_equal(formatter.format_for_tick([datetime.datetime(2014, 12, 25)]), ['25-12//2014']) @@ -271,9 +271,9 @@ def test_empty_date_with_year_formatter(): def test_auto_date_locator(): def _create_auto_date_locator(date1, date2): locator = mdates.AutoDateLocator() - locator.create_dummy_axis() - locator.set_view_interval(mdates.date2num(date1), - mdates.date2num(date2)) + locator.set_axis({}) + locator.axis.set_view_interval(mdates.date2num(date1), + mdates.date2num(date2)) return locator d1 = datetime.datetime(1990, 1, 1) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 438be20aa7ce..557fd3607e09 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -161,7 +161,8 @@ def test_SymmetricalLogLocator_set_params(): def _logfe_helper(formatter, base, locs, i, expected_result): vals = base**locs - labels = [formatter(x, pos) for (x, pos) in zip(vals, i)] + labels = [formatter.format_for_tick(x, pos).replace("\N{MINUS SIGN}", "-") + for (x, pos) in zip(vals, i)] nose.tools.assert_equal(labels, expected_result) @@ -182,31 +183,31 @@ def get_view_interval(self): formatter.axis = FakeAxis(1, base**4) yield _logfe_helper, formatter, base, i, i, expected_result - # Should be a blank string for non-integer powers if labelOnlyBase=True - formatter = mticker.LogFormatterExponent(base=10, labelOnlyBase=True) + # Should be a blank string for non-integer powers if label_minor is False. + formatter = mticker.LogFormatterExponent(base=10, label_minor=False) formatter.axis = FakeAxis() - nose.tools.assert_equal(formatter(10**0.1), '') + nose.tools.assert_equal(formatter.format_for_tick(10**0.1), '') # Otherwise, non-integer powers should be nicely formatted locs = np.array([0.1, 0.00001, np.pi, 0.2, -0.2, -0.00001]) i = range(len(locs)) expected_result = ['0.1', '1e-05', '3.14', '0.2', '-0.2', '-1e-05'] for base in [2, 5, 10, np.pi, np.e]: - formatter = mticker.LogFormatterExponent(base, labelOnlyBase=False) + formatter = mticker.LogFormatterExponent(base, label_minor=True) formatter.axis = FakeAxis(1, base**10) yield _logfe_helper, formatter, base, locs, i, expected_result expected_result = ['3', '5', '12', '42'] locs = np.array([3, 5, 12, 42], dtype='float') for base in [2, 5.0, 10.0, np.pi, np.e]: - formatter = mticker.LogFormatterExponent(base, labelOnlyBase=False) + formatter = mticker.LogFormatterExponent(base, label_minor=True) formatter.axis = FakeAxis(1, base**50) yield _logfe_helper, formatter, base, locs, i, expected_result def _pprint_helper(value, domain, expected): fmt = mticker.LogFormatter() - label = fmt.pprint_val(value, domain) + label = fmt._pprint_val(value, domain) nose.tools.assert_equal(label, expected) @@ -354,17 +355,17 @@ def test_use_offset(): for use_offset in [True, False]: with matplotlib.rc_context({'axes.formatter.useoffset': use_offset}): tmp_form = mticker.ScalarFormatter() - nose.tools.assert_equal(use_offset, tmp_form.get_useOffset()) + nose.tools.assert_equal(use_offset, tmp_form._use_offset) def test_formatstrformatter(): # test % style formatter tmp_form = mticker.FormatStrFormatter('%05d') - nose.tools.assert_equal('00002', tmp_form(2)) + nose.tools.assert_equal('00002', tmp_form.format_for_tick(2)) # test str.format() style formatter tmp_form = mticker.StrMethodFormatter('{x:05d}') - nose.tools.assert_equal('00002', tmp_form(2)) + nose.tools.assert_equal('00002', tmp_form.format_for_tick(2)) if __name__ == '__main__': import nose diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 7455d03365a2..5781e70eb93b 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -24,7 +24,7 @@ formatter:: - ax.get_xaxis().get_major_formatter().set_useOffset(False) + ax.get_xaxis().get_major_formatter().use_offset = False set the rcParam ``axes.formatter.useoffset=False`` to turn it off globally, or set a different formatter. @@ -157,13 +157,13 @@ import decimal import locale import math +import warnings + import numpy as np from matplotlib import rcParams from matplotlib import cbook from matplotlib import transforms as mtransforms -import warnings - if six.PY3: long = int @@ -175,10 +175,15 @@ def _mathdefault(s): math font already matches the default font, so we don't need to do that anymore. """ - if rcParams['_internal.classic_mode']: - return '\\mathdefault{%s}' % s + assert s[0] == s[-1] == "$" + if rcParams["_internal.classic_mode"] and not rcParams["text.usetex"]: + return r"$\mathdefault{{{}}}$".format(s[1:-1]) else: - return '{%s}' % s + return s + + +def _unicode_minus(s): + return s.replace("-", "\N{MINUS SIGN}") class _DummyAxis(object): @@ -207,534 +212,398 @@ def get_tick_space(self): return 9 -class TickHelper(object): - axis = None - - def set_axis(self, axis): - self.axis = axis - - def create_dummy_axis(self, **kwargs): - if self.axis is None: - self.axis = _DummyAxis(**kwargs) - - def set_view_interval(self, vmin, vmax): - self.axis.set_view_interval(vmin, vmax) +class _TickHelper(object): + def __init__(self): + self.axis = None - def set_data_interval(self, vmin, vmax): - self.axis.set_data_interval(vmin, vmax) + def set_axis(self, axis_or_kw): + if isinstance(axis_or_kw, dict): + self.axis = _DummyAxis(**axis_or_kw) + else: + self.axis = axis_or_kw - def set_bounds(self, vmin, vmax): - self.set_view_interval(vmin, vmax) - self.set_data_interval(vmin, vmax) +class Formatter(_TickHelper): + def __init__(self): + super(Formatter, self).__init__() + self._locs = [] + self._offset_text = "" -class Formatter(TickHelper): - """ - Convert the tick location to a string - """ - # some classes want to see all the locs to help format - # individual ones - locs = [] + @property + def locs(self): + return self._locs - def __call__(self, x, pos=None): - """Return the format for tick val x at position pos; pos=None - indicated unspecified""" - raise NotImplementedError('Derived must override') + @locs.setter + def locs(self, locs): + self._locs = np.asarray(locs) - def format_data(self, value): - return self.__call__(value) + @property + def offset_text(self): + return self._offset_text - def format_data_short(self, value): - """return a short string version""" - return self.format_data(value) + @offset_text.setter + def offset_text(self, s): + self._offset_text = s - def get_offset(self): - return '' + def format_for_tick(self, value, pos=None): + return "" - def set_locs(self, locs): - self.locs = locs - - def fix_minus(self, s): - """ - Some classes may want to replace a hyphen for minus with the - proper unicode symbol (U+2212) for typographical correctness. - The default is to not replace it. - - Note, if you use this method, e.g., in :meth:`format_data` or - call, you probably don't want to use it for - :meth:`format_data_short` since the toolbar uses this for - interactive coord reporting and I doubt we can expect GUIs - across platforms will handle the unicode correctly. So for - now the classes that override :meth:`fix_minus` should have an - explicit :meth:`format_data_short` method - """ - return s - - -class IndexFormatter(Formatter): - """ - format the position x to the nearest i-th label where i=int(x+0.5) - """ - def __init__(self, labels): - self.labels = labels - self.n = len(labels) - - def __call__(self, x, pos=None): - """Return the format for tick val x at position pos; pos=None - indicated unspecified""" - i = int(x + 0.5) - if i < 0: - return '' - elif i >= self.n: - return '' - else: - return self.labels[i] + def format_for_cursor(self, value): + return self.format_for_tick(value) class NullFormatter(Formatter): - 'Always return the empty string' - - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - return '' + """Always return the empty string. + """ class FixedFormatter(Formatter): - 'Return fixed strings for tick labels' - def __init__(self, seq): - """ - *seq* is a sequence of strings. For positions ``i < len(seq)`` return - *seq[i]* regardless of *x*. Otherwise return '' - """ - self.seq = seq - self.offset_string = '' - - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - if pos is None or pos >= len(self.seq): - return '' - else: - return self.seq[pos] + """Return fixed strings for tick labels. + """ - def get_offset(self): - return self.offset_string + def __init__(self, seq): + super(FixedFormatter, self).__init__() + self._seq = seq - def set_offset_string(self, ofs): - self.offset_string = ofs + def format_for_tick(self, x, pos=None): + """Return the format for tick val *x* at position *pos*. + """ + return self._seq[pos] if pos < len(self._seq) else "" class FuncFormatter(Formatter): - """ - User defined function for formatting + """User defined function for formatting. The function should take in two inputs (tick value *x* and position *pos*) - and return a string + and return a string. """ - def __init__(self, func): - self.func = func - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - return self.func(x, pos) + def __init__(self, func): + super(FuncFormatter, self).__init__() + self.format_for_tick = func class FormatStrFormatter(Formatter): + """Use an old-style ('%' operator) format string to format the tick. """ - Use an old-style ('%' operator) format string to format the tick - """ - def __init__(self, fmt): - self.fmt = fmt - - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - return self.fmt % x - -class StrMethodFormatter(Formatter): - """ - Use a new-style format string (as used by `str.format()`) - to format the tick. The field formatting must be labeled `x`. - """ def __init__(self, fmt): - self.fmt = fmt + super(FormatStrFormatter, self).__init__() + self._fmt = fmt - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - return self.fmt.format(x=x) + def format_for_tick(self, x, pos=None): + return self._fmt % x -class OldScalarFormatter(Formatter): - """ - Tick location is a plain old number. +class StrMethodFormatter(Formatter): + """Use a new-style format string (as used by `str.format()`) to + format the tick. The field formatting must be labeled `x` and/or + `pos`. """ - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - xmin, xmax = self.axis.get_view_interval() - d = abs(xmax - xmin) - - return self.pprint_val(x, d) - - def pprint_val(self, x, d): - #if the number is not too big and it's an int, format it as an - #int - if abs(x) < 1e4 and x == int(x): - return '%d' % x + def __init__(self, fmt): + super(StrMethodFormatter, self).__init__() + self._fmt = fmt - if d < 1e-2: - fmt = '%1.3e' - elif d < 1e-1: - fmt = '%1.3f' - elif d > 1e5: - fmt = '%1.1e' - elif d > 10: - fmt = '%1.1f' - elif d > 1: - fmt = '%1.2f' - else: - fmt = '%1.3f' - s = fmt % x - #print d, x, fmt, s - tup = s.split('e') - if len(tup) == 2: - mantissa = tup[0].rstrip('0').rstrip('.') - sign = tup[1][0].replace('+', '') - exponent = tup[1][1:].lstrip('0') - s = '%se%s%s' % (mantissa, sign, exponent) - else: - s = s.rstrip('0').rstrip('.') - return s + def format_for_tick(self, x, pos=None): + return self._fmt.format(x=x, pos=pos) class ScalarFormatter(Formatter): - """ - Tick location is a plain old number. If useOffset==True and the data range - is much smaller than the data average, then an offset will be determined - such that the tick labels are meaningful. Scientific notation is used for - data < 10^-n or data >= 10^m, where n and m are the power limits set using + """Tick location is a plain old number. If use_offset==True + and the data range is much smaller than the data average, then + an offset will be determined such that the tick labels are + meaningful. Scientific notation is used for data < 10^-n or + data >= 10^m, where n and m are the power limits set using set_powerlimits((n,m)). The defaults for these are controlled by the axes.formatter.limits rc parameter. - """ def __init__(self, useOffset=None, useMathText=None, useLocale=None): - # useOffset allows plotting small data ranges with large offsets: for - # example: [1+1e-9,1+2e-9,1+3e-9] useMathText will render the offset - # and scientific notation in mathtext - - if useOffset is None: - useOffset = rcParams['axes.formatter.useoffset'] - self.set_useOffset(useOffset) - self._usetex = rcParams['text.usetex'] - if useMathText is None: - useMathText = rcParams['axes.formatter.use_mathtext'] - self._useMathText = useMathText - self.orderOfMagnitude = 0 - self.format = '' + super(ScalarFormatter, self).__init__() + self._use_offset = (useOffset if useOffset is not None + else rcParams["axes.formatter.useoffset"]) + self._usetex = rcParams["text.usetex"] + self._use_mathtext = (useMathText if useMathText is not None + else rcParams["axes.formatter.use_mathtext"]) + self._use_locale = (useLocale if useLocale is not None + else rcParams["axes.formatter.use_locale"]) self._scientific = True self._powerlimits = rcParams['axes.formatter.limits'] - if useLocale is None: - useLocale = rcParams['axes.formatter.use_locale'] - self._useLocale = useLocale - - def get_useOffset(self): - return self._useOffset - - def set_useOffset(self, val): - if val in [True, False]: - self.offset = 0 - self._useOffset = val - else: - self._useOffset = False - self.offset = val - - useOffset = property(fget=get_useOffset, fset=set_useOffset) - - def get_useLocale(self): - return self._useLocale - - def set_useLocale(self, val): - if val is None: - self._useLocale = rcParams['axes.formatter.use_locale'] - else: - self._useLocale = val - - useLocale = property(fget=get_useLocale, fset=set_useLocale) - - def fix_minus(self, s): - """use a unicode minus rather than hyphen""" - if rcParams['text.usetex'] or not rcParams['axes.unicode_minus']: - return s - else: - return s.replace('-', '\u2212') - - def __call__(self, x, pos=None): - 'Return the format for tick val *x* at position *pos*' - if len(self.locs) == 0: - return '' - else: - s = self.pprint_val(x) - return self.fix_minus(s) - - def set_scientific(self, b): - '''True or False to turn scientific notation on or off - see also :meth:`set_powerlimits` - ''' - self._scientific = bool(b) - - def set_powerlimits(self, lims): - ''' - Sets size thresholds for scientific notation. - - e.g., ``formatter.set_powerlimits((-3, 4))`` sets the pre-2007 default - in which scientific notation is used for numbers less than 1e-3 or - greater than 1e4. - See also :meth:`set_scientific`. - ''' - if len(lims) != 2: - raise ValueError("'lims' must be a sequence of length 2") + self._offset = 0 + self._oom = self._tick_precision = self._cursor_precision = None + + def _format_maybe_locale(self, fmt, *args): + return (locale.format_string(fmt, *args) if self._use_locale + else fmt % args) + + @property + def locs(self): + return self._locs + + @locs.setter + def locs(self, locs): + self._locs = np.asarray(locs) + self._update() + + @property + def use_offset(self): + return self._use_offset + + @use_offset.setter + def use_offset(self, b): + self._use_offset = b + self._update() + + @property + def use_locale(self): + return self._use_locale + + @use_locale.setter + def use_locale(self, b): + self._use_locale = b + self._update() + + @property + def scientific(self): + return self._scientific + + @scientific.setter + def scientific(self, b): + self._scientific = b + self._update() + + @property + def powerlimits(self): + return self._powerlimits + + @powerlimits.setter + def powerlimits(self, lims): self._powerlimits = lims + self._update() - def format_data_short(self, value): - """return a short formatted string representation of a number""" - if self._useLocale: - return locale.format_string('%-12g', (value,)) - else: - return '%-12g' % value + def _update(self): + self._set_offset() + self._set_oom() + self._set_precision() - def format_data(self, value): - 'return a formatted string representation of a number' - if self._useLocale: - s = locale.format_string('%1.10e', (value,)) - else: - s = '%1.10e' % value - s = self._formatSciNotation(s) - return self.fix_minus(s) - - def get_offset(self): - """Return scientific notation, plus offset""" - if len(self.locs) == 0: - return '' - s = '' - if self.orderOfMagnitude or self.offset: - offsetStr = '' - sciNotStr = '' - if self.offset: - offsetStr = self.format_data(self.offset) - if self.offset > 0: - offsetStr = '+' + offsetStr - if self.orderOfMagnitude: - if self._usetex or self._useMathText: - sciNotStr = self.format_data(10 ** self.orderOfMagnitude) + def _set_offset(self): + locs = self.locs + if not self._use_offset: + self._offset = 0 + return + # Restrict to visible ticks. + vmin, vmax = sorted(self.axis.get_view_interval()) + locs = locs[(vmin <= locs) & (locs <= vmax)] + if not len(locs): + self._offset = 0 + return + lmin, lmax = locs.min(), locs.max() + # min, max comparing absolute values (we want division to round towards + # zero so we work on absolute values). + abs_min, abs_max = sorted(map(abs, [lmin, lmax])) + # Only use offset if there are at least two ticks, every tick has the + # same sign, and if the span is small compared to the absolute values. + if (lmin == lmax or lmin <= 0 <= lmax or + (abs_max - abs_min) / abs_max >= 1e-2): + self._offset = 0 + return + sign = math.copysign(1, lmin) + # What is the smallest power of ten such that abs_min and abs_max are + # equal up to that precision? + oom = 10. ** math.ceil(math.log10(abs_max)) + while True: + if abs_min // oom != abs_max // oom: + oom *= 10 + break + oom /= 10 + if (abs_max - abs_min) / oom <= 1e-2: + # Handle the case of straddling a multiple of a large power of ten + # (relative to the span). + # What is the smallest power of ten such that abs_min and abs_max + # at most 1 apart? + oom = 10. ** math.ceil(math.log10(abs_max)) + while True: + if abs_max // oom - abs_min // oom > 1: + oom *= 10 + break + oom /= 10 + self._offset = sign * (abs_max // oom) * oom + + def _set_oom(self): + # If scientific notation is to be used, find the appropriate exponent. + # If using an offset, find the exponent after applying the offset. + if self._scientific: + locs = self.locs + vmin, vmax = sorted(self.axis.get_view_interval()) + # Restrict to visible ticks. + locs = locs[(vmin <= locs) & (locs <= vmax)] + if len(locs): + deltas = np.abs(locs - self._offset) + # Don't take tiny, nonzero tick values into account. + deltas = deltas[deltas > 1e-10 * deltas.max()] + if len(deltas): + oom = int(math.floor(math.log10(deltas.min()))) + self._oom = (oom if (oom <= self._powerlimits[0] or + oom >= self._powerlimits[1]) + else 0) else: - sciNotStr = '1e%d' % self.orderOfMagnitude - if self._useMathText: - if sciNotStr != '': - sciNotStr = r'\times%s' % _mathdefault(sciNotStr) - s = ''.join(('$', sciNotStr, _mathdefault(offsetStr), '$')) - elif self._usetex: - if sciNotStr != '': - sciNotStr = r'\times%s' % sciNotStr - s = ''.join(('$', sciNotStr, offsetStr, '$')) + self._oom = 0 else: - s = ''.join((sciNotStr, offsetStr)) - - return self.fix_minus(s) - - def set_locs(self, locs): - 'set the locations of the ticks' - self.locs = locs - if len(self.locs) > 0: - vmin, vmax = self.axis.get_view_interval() - d = abs(vmax - vmin) - if self._useOffset: - self._set_offset(d) - self._set_orderOfMagnitude(d) - self._set_format(vmin, vmax) + self._oom = 0 + else: + self._oom = 0 - def _set_offset(self, range): - # offset of 20,001 is 20,000, for example + def _set_precision(self): locs = self.locs - - if locs is None or not len(locs) or range == 0: - self.offset = 0 - return vmin, vmax = sorted(self.axis.get_view_interval()) - locs = np.asarray(locs) + # Restrict to visible ticks. locs = locs[(vmin <= locs) & (locs <= vmax)] - ave_loc = np.mean(locs) - if len(locs) and ave_loc: # dont want to take log10(0) - ave_oom = math.floor(math.log10(np.mean(np.absolute(locs)))) - range_oom = math.floor(math.log10(range)) - - if np.absolute(ave_oom - range_oom) >= 3: # four sig-figs - p10 = 10 ** range_oom - if ave_loc < 0: - self.offset = (math.ceil(np.max(locs) / p10) * p10) - else: - self.offset = (math.floor(np.min(locs) / p10) * p10) + # Tick precision. + if len(locs): + ticks = np.abs(locs - self._offset) / 10. ** self._oom + # Don't take tiny, nonzero tick values into account. + ticks = ticks[ticks > 1e-10 * ticks.max()] + if len(ticks): + thresh = 10. ** (math.floor(math.log10(ticks.min())) - 3) + precision = 0 + while (np.abs(np.round(ticks, precision) - ticks).max() > + thresh): + precision += 1 + # Work around rounding errors, e.g. test_formatter_large_small: + # increase scale and recompute precision. + if (self._oom and + np.abs(np.round(ticks, precision)).min() >= 10): + self._oom += 1 + self._set_precision() + return + self._tick_precision = precision else: - self.offset = 0 - - def _set_orderOfMagnitude(self, range): - # if scientific notation is to be used, find the appropriate exponent - # if using an numerical offset, find the exponent after applying the - # offset - if not self._scientific: - self.orderOfMagnitude = 0 - return - locs = np.absolute(self.locs) - if self.offset: - oom = math.floor(math.log10(range)) + self._tick_precision = 0 else: - if locs[0] > locs[-1]: - val = locs[0] + self._tick_precision = 0 + # Cursor precision. + self._cursor_precision = ( + 3 - int(math.floor(math.log10(vmax - vmin)))) if vmax > vmin else 0 + + @property + def offset_text(self): + if self._oom or self._offset: + if self._offset: + offset_str = self._format_offset() else: - val = locs[-1] - if val == 0: - oom = 0 + offset_str = "" + if self._oom: + if self._use_mathtext or rcParams["text.usetex"]: + sci_not_str = "$10^{{{}}}$".format(self._oom) + else: + sci_not_str = "1e{}".format(self._oom) else: - oom = math.floor(math.log10(val)) - if oom <= self._powerlimits[0]: - self.orderOfMagnitude = oom - elif oom >= self._powerlimits[1]: - self.orderOfMagnitude = oom - else: - self.orderOfMagnitude = 0 - - def _set_format(self, vmin, vmax): - # set the format string to format all the ticklabels - if len(self.locs) < 2: - # Temporarily augment the locations with the axis end points. - _locs = list(self.locs) + [vmin, vmax] - else: - _locs = self.locs - locs = (np.asarray(_locs) - self.offset) / 10. ** self.orderOfMagnitude - loc_range = np.ptp(locs) - # Curvilinear coordinates can yield two identical points. - if loc_range == 0: - loc_range = np.max(np.abs(locs)) - # Both points might be zero. - if loc_range == 0: - loc_range = 1 - if len(self.locs) < 2: - # We needed the end points only for the loc_range calculation. - locs = locs[:-2] - loc_range_oom = int(math.floor(math.log10(loc_range))) - # first estimate: - sigfigs = max(0, 3 - loc_range_oom) - # refined estimate: - thresh = 1e-3 * 10 ** loc_range_oom - while sigfigs >= 0: - if np.abs(locs - np.round(locs, decimals=sigfigs)).max() < thresh: - sigfigs -= 1 + sci_not_str = "" + if self._use_mathtext or rcParams["text.usetex"]: + assert offset_str[0] == offset_str[-1] == "$" + if sci_not_str: + assert sci_not_str[0] == sci_not_str[-1] == "$" + s = r"$\times {} {}$".format( + sci_not_str[1:-1], offset_str[1:-1]) + else: + s = offset_str + return _mathdefault(s) else: - break - sigfigs += 1 - self.format = '%1.' + str(sigfigs) + 'f' - if self._usetex: - self.format = '$%s$' % self.format - elif self._useMathText: - self.format = '$%s$' % _mathdefault(self.format) - - def pprint_val(self, x): - xp = (x - self.offset) / (10. ** self.orderOfMagnitude) - if np.absolute(xp) < 1e-8: - xp = 0 - if self._useLocale: - return locale.format_string(self.format, (xp,)) - else: - return self.format % xp - - def _formatSciNotation(self, s): - # transform 1e+004 into 1e4, for example - if self._useLocale: - decimal_point = locale.localeconv()['decimal_point'] - positive_sign = locale.localeconv()['positive_sign'] - else: - decimal_point = '.' - positive_sign = '+' - tup = s.split('e') - try: - significand = tup[0].rstrip('0').rstrip(decimal_point) - sign = tup[1][0].replace(positive_sign, '') - exponent = tup[1][1:].lstrip('0') - if self._useMathText or self._usetex: - if significand == '1' and exponent != '': - # reformat 1x10^y as 10^y - significand = '' - if exponent: - exponent = '10^{%s%s}' % (sign, exponent) - if significand and exponent: - return r'%s{\times}%s' % (significand, exponent) + if sci_not_str: + s = "\N{MULTIPLICATION SIGN}{}{}".format( + sci_not_str, offset_str) else: - return r'%s%s' % (significand, exponent) + s = offset_str + return _unicode_minus(s) + else: + return "" + + def _format_offset(self): + offset = self._offset + # How many significant digits are needed to represent offset to + # 10 ** (oom - tick_precision)? + precision = ( + (int(math.floor(math.log10(abs(offset)))) if offset else 0) + + self._tick_precision - self._oom + 1) + if .0001 <= abs(offset) < 10000 or offset == 0: + # %g doesn't use scientific notation in this range. + s = (self._format_maybe_locale("%#-+.*g", precision, offset). + rstrip(locale.localeconv()["decimal_point"] + if self._use_locale else ".")) + if self._use_mathtext or rcParams["text.usetex"]: + return "${}$".format(s) else: - s = ('%se%s%s' % (significand, sign, exponent)).rstrip('e') return s - except IndexError: - return s + exp = int(math.floor(math.log10(abs(offset)))) + significand = offset / 10. ** exp + # 1 digit before decimal point, (precision - 1) after. + significand_s = self._format_maybe_locale( + "%-+.*f", precision - 1, significand) + if self._use_mathtext or rcParams["text.usetex"]: + return r"${} \times 10^{{{}}}$".format(significand_s, exp) + else: + return "{}e{}".format(significand_s, exp) + + def format_for_tick(self, value, pos=None): + # Get rid of signed zeros (sic). + scaled = round((value - self._offset) / 10. ** self._oom, + self._tick_precision) + if scaled == 0: + scaled = 0 + s = self._format_maybe_locale("%-.*f", self._tick_precision, scaled) + if self._use_mathtext or rcParams["text.usetex"]: + return _mathdefault("${}$".format(s)) + else: + return _unicode_minus(s) + + def format_for_cursor(self, value): + # How many significant digits needed to represent value to + # 10 ** -cursor_precision? + precision = ( + math.floor(math.log10(abs(value))) + self._cursor_precision + if value else self._cursor_precision) + 1 + return _unicode_minus( + self._format_maybe_locale("%#-.*g", precision, value)) class LogFormatter(Formatter): + """Format values for log axis. """ - Format values for log axis; - """ - def __init__(self, base=10.0, labelOnlyBase=True): + def __init__(self, base=10., label_minor=False): """ - *base* is used to locate the decade tick, - which will be the only one to be labeled if *labelOnlyBase* - is ``False`` + *base* is used to locate the decade tick, which will be the only + one to be labeled if *label_minor* is ``False``. """ - self._base = base + 0.0 - self.labelOnlyBase = labelOnlyBase + super(LogFormatter, self).__init__() + self.base = base + self.label_minor = label_minor - def base(self, base): - """change the *base* for labeling - warning: should always match the - base used for :class:`LogLocator`""" - self._base = base - - def label_minor(self, labelOnlyBase): - 'switch on/off minor ticks labeling' - self.labelOnlyBase = labelOnlyBase - - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): """Return the format for tick val *x* at position *pos*""" - vmin, vmax = self.axis.get_view_interval() - d = abs(vmax - vmin) - b = self._base + vmin, vmax = sorted(self.axis.get_view_interval()) + d = vmax - vmin + b = self.base if x == 0.0: return '0' sign = np.sign(x) # only label the decades fx = math.log(abs(x)) / math.log(b) - isDecade = is_close_to_int(fx) - if not isDecade and self.labelOnlyBase: - s = '' + is_decade = is_close_to_int(fx) + if not (is_decade or self.label_minor): + s = "" elif x > 10000: s = '%1.0e' % x elif x < 1: s = '%1.0e' % x else: - s = self.pprint_val(x, d) + s = self._pprint_val(x, d) if sign == -1: s = '-%s' % s + return _unicode_minus(s) - return self.fix_minus(s) - - def format_data(self, value): - b = self.labelOnlyBase - self.labelOnlyBase = False - value = cbook.strip_math(self.__call__(value)) - self.labelOnlyBase = b - return value - - def format_data_short(self, value): - 'return a short formatted string representation of a number' - return '%-12g' % value - - def pprint_val(self, x, d): + def _pprint_val(self, x, d): #if the number is not too big and it's an int, format it as an #int if abs(x) < 1e4 and x == int(x): @@ -766,38 +635,39 @@ def pprint_val(self, x, d): s = s.rstrip('0').rstrip('.') return s + def format_for_cursor(self, value): + 'return a short formatted string representation of a number' + return '%-12g' % value + class LogFormatterExponent(LogFormatter): """ Format values for log axis; using ``exponent = log_base(value)`` """ - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): """Return the format for tick val *x* at position *pos*""" vmin, vmax = self.axis.get_view_interval() vmin, vmax = mtransforms.nonsingular(vmin, vmax, expander=0.05) d = abs(vmax - vmin) - b = self._base + b = self.base if x == 0: return '0' sign = np.sign(x) # only label the decades fx = math.log(abs(x)) / math.log(b) - isDecade = is_close_to_int(fx) - if not isDecade and self.labelOnlyBase: - s = '' - elif abs(fx) > 10000: - s = '%1.0g' % fx - elif abs(fx) < 1: + is_decade = is_close_to_int(fx) + if not (is_decade or self.label_minor): + s = "" + elif abs(fx) < 1 or abs(fx) > 10000: s = '%1.0g' % fx else: fd = math.log(abs(d)) / math.log(b) - s = self.pprint_val(fx, fd) + s = self._pprint_val(fx, fd) if sign == -1: s = '-%s' % s - - return self.fix_minus(s) + return _unicode_minus(s) class LogFormatterMathtext(LogFormatter): @@ -805,22 +675,18 @@ class LogFormatterMathtext(LogFormatter): Format values for log axis; using ``exponent = log_base(value)`` """ - def __call__(self, x, pos=None): + def format_for_tick(self, x, pos=None): 'Return the format for tick val *x* at position *pos*' - b = self._base - usetex = rcParams['text.usetex'] + b = self.base # only label the decades if x == 0: - if usetex: - return '$0$' - else: - return '$%s$' % _mathdefault('0') + return _mathdefault("$0$") fx = math.log(abs(x)) / math.log(b) is_decade = is_close_to_int(fx) - sign_string = '-' if x < 0 else '' + sign_string = '-' if x < 0 else "" # use string formatting of the base if it is not an integer if b % 1 == 0.0: @@ -828,46 +694,35 @@ def __call__(self, x, pos=None): else: base = '%s' % b - if not is_decade and self.labelOnlyBase: - return '' + if not (is_decade or self.label_minor): + return "" elif not is_decade: - if usetex: - return (r'$%s%s^{%.2f}$') % \ - (sign_string, base, fx) - else: - return ('$%s$' % _mathdefault( - '%s%s^{%.2f}' % - (sign_string, base, fx))) + return _mathdefault(r"$%s%s^{%.2f}$" % + (sign_string, base, fx)) else: - if usetex: - return (r'$%s%s^{%d}$') % (sign_string, - base, - nearest_long(fx)) - else: - return ('$%s$' % _mathdefault( - '%s%s^{%d}' % - (sign_string, base, nearest_long(fx)))) + return _mathdefault(r"$%s%s^{%d}$" % + (sign_string, base, round(fx))) class LogitFormatter(Formatter): - '''Probability formatter (using Math text)''' - def __call__(self, x, pos=None): - s = '' + ""'Probability formatter (using Math text)""' + def format_for_tick(self, x, pos=None): + s = "" if 0.01 <= x <= 0.99: s = '{:.2f}'.format(x) elif x < 0.01: if is_decade(x): - s = '$10^{{{:.0f}}}$'.format(np.log10(x)) + s = _mathdefault('$10^{{{:.0f}}}$'.format(np.log10(x))) else: - s = '${:.5f}$'.format(x) + s = _mathdefault('${:.5f}$'.format(x)) else: # x > 0.99 if is_decade(1-x): - s = '$1-10^{{{:.0f}}}$'.format(np.log10(1-x)) + s = _mathdefault('$1-10^{{{:.0f}}}$'.format(np.log10(1-x))) else: - s = '$1-{:.5f}$'.format(1-x) + s = _mathdefault('$1-{:.5f}$'.format(1-x)) return s - def format_data_short(self, value): + def format_for_cursor(self, value): 'return a short formatted string representation of a number' return '%-12g' % value @@ -878,10 +733,6 @@ class EngFormatter(Formatter): plus a specified unit, e.g., 10 MHz instead of 1e7. """ - # the unicode for -6 is the greek letter mu - # commeted here due to bug in pep8 - # (https://github.com/jcrocholl/pep8/issues/271) - # The SI engineering prefixes ENG_PREFIXES = { -24: "y", @@ -890,7 +741,7 @@ class EngFormatter(Formatter): -15: "f", -12: "p", -9: "n", - -6: "\u03bc", + -6: "\N{MICRO SIGN}", -3: "m", 0: "", 3: "k", @@ -904,14 +755,18 @@ class EngFormatter(Formatter): } def __init__(self, unit="", places=None): + super(EngFormatter, self).__init__() self.unit = unit self.places = places - def __call__(self, x, pos=None): - s = "%s%s" % (self.format_eng(x), self.unit) - return self.fix_minus(s) + def format_for_tick(self, x, pos=None): + s = "%s%s" % (self._format_eng(x), self.unit) + if rcParams["text.usetex"]: + return _mathdefault(s) + else: + return _unicode_minus(s) - def format_eng(self, num): + def _format_eng(self, num): """ Formats a number in engineering notation, appending a letter representing the power of 1000 of the original number. Some examples: @@ -963,7 +818,7 @@ def format_eng(self, num): return formatted.strip() -class Locator(TickHelper): +class Locator(_TickHelper): """ Determine the tick locations; @@ -1072,6 +927,7 @@ class IndexLocator(Locator): """ def __init__(self, base, offset): 'place ticks on the i-th data points where (i-offset)%base==0' + super(IndexLocator, self).__init__() self._base = base self.offset = offset @@ -1104,6 +960,7 @@ class FixedLocator(Locator): """ def __init__(self, locs, nbins=None): + super(FixedLocator, self).__init__() self.locs = np.asarray(locs) self.nbins = nbins if self.nbins is not None: @@ -1172,6 +1029,7 @@ def __init__(self, numticks=None, presets=None): """ Use presets to set locs based on lom. A dict mapping vmin, vmax->locs """ + super(LinearLocator, self).__init__() self.numticks = numticks if presets is None: self.presets = {} @@ -1286,6 +1144,7 @@ class MultipleLocator(Locator): """ def __init__(self, base=1.0): + super(MultipleLocator, self).__init__() self._base = Base(base) def set_params(self, base): @@ -1391,6 +1250,7 @@ def __init__(self, *args, **kwargs): # I left "trim" out; it defaults to True, and it is not # clear that there is any use case for False, so we may # want to remove that kwarg. EF 2010/04/18 + super(MaxNLocator, self).__init__() if args: kwargs['nbins'] = args[0] if len(args) > 1: @@ -1507,15 +1367,6 @@ def decade_up(x, base=10): return base ** lx -def nearest_long(x): - if x == 0: - return long(0) - elif x > 0: - return long(x + 0.5) - else: - return long(x - 0.5) - - def is_decade(x, base=10): if not np.isfinite(x): return False @@ -1528,7 +1379,7 @@ def is_decade(x, base=10): def is_close_to_int(x): if not np.isfinite(x): return False - return abs(x - nearest_long(x)) < 1e-10 + return abs(x - round(x)) < 1e-10 class LogLocator(Locator): @@ -1540,6 +1391,7 @@ def __init__(self, base=10.0, subs=[1.0], numdecs=4, numticks=15): """ place ticks on the location= base**i*subs[j] """ + super(LogLocator, self).__init__() self.base(base) self.subs(subs) self.numticks = numticks @@ -1678,6 +1530,7 @@ def __init__(self, transform, subs=None): """ place ticks on the location= base**i*subs[j] """ + super(SymmetricalLogLocator, self).__init__() self._transform = transform if subs is None: self._subs = [1.0] @@ -1840,6 +1693,7 @@ def __init__(self, minor=False): """ place ticks on the logit locations """ + super(LogitLocator, self).__init__() self.minor = minor def set_params(self, minor=None): @@ -1924,7 +1778,7 @@ def __init__(self): nbins = 9 else: nbins = 'auto' - MaxNLocator.__init__(self, nbins=nbins, steps=[1, 2, 5, 10]) + super(AutoLocator, self).__init__(nbins=nbins, steps=[1, 2, 5, 10]) class AutoMinorLocator(Locator): @@ -1941,6 +1795,7 @@ def __init__(self, n=None): If *n* is omitted or None, it will be set to 5 or 4. """ + super(AutoMinorLocator, self).__init__() self.ndivs = n def __call__(self): @@ -1998,6 +1853,7 @@ class OldAutoLocator(Locator): """ def __init__(self): + super(OldAutoLocator, self).__init__() self._locator = LinearLocator() def __call__(self): @@ -2052,11 +1908,9 @@ def get_locator(self, d): return locator -__all__ = ('TickHelper', 'Formatter', 'FixedFormatter', - 'NullFormatter', 'FuncFormatter', 'FormatStrFormatter', - 'StrMethodFormatter', 'ScalarFormatter', 'LogFormatter', - 'LogFormatterExponent', 'LogFormatterMathtext', 'Locator', - 'IndexLocator', 'FixedLocator', 'NullLocator', - 'LinearLocator', 'LogLocator', 'AutoLocator', - 'MultipleLocator', 'MaxNLocator', 'AutoMinorLocator', - 'SymmetricalLogLocator') +__all__ = ['Formatter', 'FixedFormatter', 'NullFormatter', 'FuncFormatter', + 'FormatStrFormatter', 'StrMethodFormatter', 'ScalarFormatter', + 'LogFormatter', 'LogFormatterExponent', 'LogFormatterMathtext', + 'Locator', 'IndexLocator', 'FixedLocator', 'NullLocator', + 'LinearLocator', 'LogLocator', 'AutoLocator', 'MultipleLocator', + 'MaxNLocator', 'AutoMinorLocator', 'SymmetricalLogLocator'] diff --git a/lib/mpl_toolkits/axes_grid1/axes_grid.py b/lib/mpl_toolkits/axes_grid1/axes_grid.py index 6f07a196ca7b..5903f7ad7d46 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_grid.py +++ b/lib/mpl_toolkits/axes_grid1/axes_grid.py @@ -61,17 +61,17 @@ def _config_axes_deprecated(self, X, Y): linewidth=0.01, zorder=-1) ax.add_artist(self.patch) - ticks, ticklabels, offset_string = self._ticker() + ticks, ticklabels, offset_text = self._ticker() if self.orientation == 'vertical': ax.set_yticks(ticks) ax.set_yticklabels(ticklabels) - ax.yaxis.get_major_formatter().set_offset_string(offset_string) + ax.yaxis.get_major_formatter().offset_text = offset_text else: ax.set_xticks(ticks) ax.set_xticklabels(ticklabels) - ax.xaxis.get_major_formatter().set_offset_string(offset_string) + ax.xaxis.get_major_formatter().offset_text = offset_text class CbarAxesBase(object): diff --git a/lib/mpl_toolkits/axisartist/axis_artist.py b/lib/mpl_toolkits/axisartist/axis_artist.py index 6b1904673f71..a78ccb0835c2 100644 --- a/lib/mpl_toolkits/axisartist/axis_artist.py +++ b/lib/mpl_toolkits/axisartist/axis_artist.py @@ -1376,7 +1376,7 @@ def _init_offsetText(self, direction): def _update_offsetText(self): - self.offsetText.set_text( self.axis.major.formatter.get_offset() ) + self.offsetText.set_text(self.axis.major.formatter.offset_text) self.offsetText.set_size(self.major_ticklabels.get_size()) offset = self.major_ticklabels.get_pad() + self.major_ticklabels.get_size() + 2. self.offsetText.xyann= (0, offset) diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index 83d65db86055..80fb45a55b05 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -275,13 +275,13 @@ def get_tick_iterators(self, axes): major = self.axis.major majorLocs = major.locator() - major.formatter.set_locs(majorLocs) - majorLabels = [major.formatter(val, i) for i, val in enumerate(majorLocs)] + major.formatter.locs = majorLocs + majorLabels = [major.formatter.format_for_tick(val, i) for i, val in enumerate(majorLocs)] minor = self.axis.minor minorLocs = minor.locator() - minor.formatter.set_locs(minorLocs) - minorLabels = [minor.formatter(val, i) for i, val in enumerate(minorLocs)] + minor.formatter.locs = minorLocs + minorLabels = [minor.formatter.format_for_tick(val, i) for i, val in enumerate(minorLocs)] trans_tick = self.get_tick_transform(axes) @@ -386,13 +386,13 @@ def get_tick_iterators(self, axes): major = self.axis.major majorLocs = major.locator() - major.formatter.set_locs(majorLocs) - majorLabels = [major.formatter(val, i) for i, val in enumerate(majorLocs)] + major.formatter.locs = majorLocs + majorLabels = [major.formatter.format_for_tick(val, i) for i, val in enumerate(majorLocs)] minor = self.axis.minor minorLocs = minor.locator() - minor.formatter.set_locs(minorLocs) - minorLabels = [minor.formatter(val, i) for i, val in enumerate(minorLocs)] + minor.formatter.locs = minorLocs + minorLabels = [minor.formatter.format_for_tick(val, i) for i, val in enumerate(minorLocs)] tr2ax = axes.transData + axes.transAxes.inverted() diff --git a/lib/mpl_toolkits/axisartist/grid_finder.py b/lib/mpl_toolkits/axisartist/grid_finder.py index 5f882d697ac2..6293de69ec47 100644 --- a/lib/mpl_toolkits/axisartist/grid_finder.py +++ b/lib/mpl_toolkits/axisartist/grid_finder.py @@ -264,16 +264,18 @@ def __init__(self, nbins = 10, steps = None, mticker.MaxNLocator.__init__(self, nbins, steps=steps, trim=trim, integer=integer, symmetric=symmetric, prune=prune) - self.create_dummy_axis() + self.set_axis({}) self._factor = None def __call__(self, v1, v2): if self._factor is not None: - self.set_bounds(v1*self._factor, v2*self._factor) + self.axis.set_data_interval(v1*self._factor, v2*self._factor) + self.axis.set_view_interval(v1*self._factor, v2*self._factor) locs = mticker.MaxNLocator.__call__(self) return np.array(locs), len(locs), self._factor else: - self.set_bounds(v1, v2) + self.axis.set_data_interval(v1, v2) + self.axis.set_view_interval(v1, v2) locs = mticker.MaxNLocator.__call__(self) return np.array(locs), len(locs), None @@ -304,8 +306,9 @@ def set_factor(self, f): class FormatterPrettyPrint(object): def __init__(self, useMathText=True): - self._fmt = mticker.ScalarFormatter(useMathText=useMathText, useOffset=False) - self._fmt.create_dummy_axis() + self._fmt = mticker.ScalarFormatter( + useMathText=useMathText, useOffset=False) + self._fmt.set_axis({}) self._ignore_factor = True def __call__(self, direction, factor, values): @@ -314,8 +317,8 @@ def __call__(self, direction, factor, values): factor = 1. values = [v/factor for v in values] #values = [v for v in values] - self._fmt.set_locs(values) - return [self._fmt(v) for v in values] + self._fmt.locs = values + return [self._fmt.format_for_tick(v) for v in values] class DictFormatter(object): diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 1e2fc5b19829..5b0f078f619f 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -1323,25 +1323,25 @@ def ticklabel_format(self, **kwargs) : try: if sb is not None: if axis in ['both', 'z']: - self.xaxis.major.formatter.set_scientific(sb) + self.xaxis.major.formatter.scientific = sb if axis in ['both', 'y']: - self.yaxis.major.formatter.set_scientific(sb) + self.yaxis.major.formatter.scientific = sb if axis in ['both', 'z'] : - self.zaxis.major.formatter.set_scientific(sb) + self.zaxis.major.formatter.scientific = sb if scilimits is not None: if axis in ['both', 'x']: - self.xaxis.major.formatter.set_powerlimits(scilimits) + self.xaxis.major.formatter.powerlimits = scilimits if axis in ['both', 'y']: - self.yaxis.major.formatter.set_powerlimits(scilimits) + self.yaxis.major.formatter.powerlimits = scilimits if axis in ['both', 'z']: - self.zaxis.major.formatter.set_powerlimits(scilimits) + self.zaxis.major.formatter.powerlimits = scilimits if useOffset is not None: if axis in ['both', 'x']: - self.xaxis.major.formatter.set_useOffset(useOffset) + self.xaxis.major.formatter.use_offset = useOffset if axis in ['both', 'y']: - self.yaxis.major.formatter.set_useOffset(useOffset) + self.yaxis.major.formatter.use_offset = useOffset if axis in ['both', 'z']: - self.zaxis.major.formatter.set_useOffset(useOffset) + self.zaxis.major.formatter.use_offset = useOffset except AttributeError: raise AttributeError( "This method only works with the ScalarFormatter.") diff --git a/lib/mpl_toolkits/mplot3d/axis3d.py b/lib/mpl_toolkits/mplot3d/axis3d.py index ad07fea32160..9d20e35a0588 100755 --- a/lib/mpl_toolkits/mplot3d/axis3d.py +++ b/lib/mpl_toolkits/mplot3d/axis3d.py @@ -123,8 +123,8 @@ def init3d(self): def get_tick_positions(self): majorLocs = self.major.locator() - self.major.formatter.set_locs(majorLocs) - majorLabels = [self.major.formatter(val, i) for i, val in enumerate(majorLocs)] + self.major.formatter.locs = majorLocs + majorLabels = [self.major.formatter.format_for_tick(val, i) for i, val in enumerate(majorLocs)] return majorLabels, majorLocs def get_major_ticks(self, numticks=None): @@ -224,8 +224,8 @@ def draw(self, renderer): # Rudimentary clipping majorLocs = [loc for loc in majorLocs if locmin <= loc <= locmax] - self.major.formatter.set_locs(majorLocs) - majorLabels = [self.major.formatter(val, i) + self.major.formatter.locs = majorLocs + majorLabels = [self.major.formatter.format_for_tick(val, i) for i, val in enumerate(majorLocs)] mins, maxs, centers, deltas, tc, highs = self._get_coord_info(renderer) @@ -302,7 +302,7 @@ def draw(self, renderer): pos = copy.copy(outeredgep) pos = move_from_center(pos, centers, labeldeltas, axmask) olx, oly, olz = proj3d.proj_transform(pos[0], pos[1], pos[2], renderer.M) - self.offsetText.set_text( self.major.formatter.get_offset() ) + self.offsetText.set_text(self.major.formatter.offset_text) self.offsetText.set_position( (olx, oly) ) angle = art3d.norm_text_angle(math.degrees(math.atan2(dy, dx))) self.offsetText.set_rotation(angle)