diff --git a/examples/units/basic_units.py b/examples/units/basic_units.py index f8425f1ec45c..fa83f7643b1a 100644 --- a/examples/units/basic_units.py +++ b/examples/units/basic_units.py @@ -328,8 +328,12 @@ def axisinfo(unit, axis): label=unit.fullname, ) elif unit == degrees: + if rcParams['_internal.classic_mode']: + locator = ticker.ClassicAutoLocator() + else: + locator = ticker.AutoLocator() return units.AxisInfo( - majloc=ticker.AutoLocator(), + majloc=locator, majfmt=ticker.FormatStrFormatter(r'$%i^\circ$'), label=unit.fullname, ) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 3c578d431adc..333140f8c293 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -654,6 +654,7 @@ def __init__(self, axes, pickradius=15): # Initialize here for testing; later add API self._major_tick_kw = dict() self._minor_tick_kw = dict() + self._tick_space = None self.cla() self._set_scale('linear') @@ -710,7 +711,10 @@ def get_children(self): def cla(self): 'clear the current axis' - self.set_major_locator(mticker.AutoLocator()) + if rcParams['_internal.classic_mode']: + self.set_major_locator(mticker.ClassicAutoLocator()) + else: + self.set_major_locator(mticker.AutoLocator()) self.set_major_formatter(mticker.ScalarFormatter()) self.set_minor_locator(mticker.NullLocator()) self.set_minor_formatter(mticker.NullFormatter()) @@ -785,6 +789,7 @@ def set_tick_params(self, which='major', reset=False, **kw): for tick in self.minorTicks: tick._apply_params(**self._minor_tick_kw) self.stale = True + self._tick_space = None @staticmethod def _translate_tick_kw(kw, to_init_kw=True): @@ -1665,6 +1670,13 @@ def axis_date(self, tz=None): tz = pytz.timezone(tz) self.update_units(datetime.datetime(2009, 1, 1, 0, 0, 0, 0, tz)) + def get_tick_space(self): + """ + Return the estimated number of ticks that can fit on the axis. + """ + # Must be overridden in the subclass + raise NotImplementedError() + class XAxis(Axis): __name__ = 'xaxis' @@ -1988,6 +2000,18 @@ def set_default_intervals(self): self.axes.viewLim.intervalx = xmin, xmax self.stale = True + def get_tick_space(self): + if self._tick_space is None: + ends = self.axes.transAxes.transform([[0, 0], [1, 0]]) + length = ((ends[1][0] - ends[0][0]) / self.axes.figure.dpi) * 72.0 + tick = self._get_tick(True) + # There is a heuristic here that the aspect ratio of tick text + # is no more than 4:1 + size = tick.label1.get_size() * 4 + size *= np.cos(np.deg2rad(tick.label1.get_rotation())) + self._tick_space = np.floor(length / size) + return self._tick_space + class YAxis(Axis): __name__ = 'yaxis' @@ -2318,3 +2342,14 @@ def set_default_intervals(self): if not viewMutated: self.axes.viewLim.intervaly = ymin, ymax self.stale = True + + def get_tick_space(self): + if self._tick_space is None: + ends = self.axes.transAxes.transform([[0, 0], [0, 1]]) + length = ((ends[1][1] - ends[0][1]) / self.axes.figure.dpi) * 72.0 + tick = self._get_tick(True) + # Having a spacing of at least 2 just looks good. + size = tick.label1.get_size() * 2.0 + size *= np.cos(np.deg2rad(tick.label1.get_rotation())) + self._tick_space = np.floor(length / size) + return self._tick_space diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 450869878c14..d9aeb0b15ae9 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -1449,6 +1449,48 @@ def view_limits(self, dmin, dmax): return np.take(self.bin_boundaries(dmin, dmax), [0, -1]) +class AutoSpacedLocator(MaxNLocator): + """ + Behaves like a MaxNLocator, except N is automatically determined + from the length of the axis. + """ + def __init__(self, *args, **kwargs): + """ + Keyword args: + + *steps* + Sequence of nice numbers starting with 1 and ending with 10; + e.g., [1, 2, 4, 5, 10] + + *integer* + If True, ticks will take only integer values. + + *symmetric* + If True, autoscaling will result in a range symmetric + about zero. + + *prune* + ['lower' | 'upper' | 'both' | None] + Remove edge ticks -- useful for stacked or ganged plots + where the upper tick of one axes overlaps with the lower + tick of the axes above it. + If prune=='lower', the smallest tick will + be removed. If prune=='upper', the largest tick will be + removed. If prune=='both', the largest and smallest ticks + will be removed. If prune==None, no ticks will be removed. + + """ + if 'nbins' in kwargs: + raise ValueError( + 'AutoSpacedLocator does not take nbins as an argument') + self.set_params(**self.default_params) + self.set_params(**kwargs) + + def __call__(self): + self._nbins = max(self.axis.get_tick_space(), 3) + return super(AutoSpacedLocator, self).__call__() + + def decade_down(x, base=10): 'floor x to the nearest lower decade' if x == 0.0: @@ -1872,7 +1914,13 @@ def tick_values(self, vmin, vmax): return self.raise_if_exceeds(np.array(ticklocs)) -class AutoLocator(MaxNLocator): +class AutoLocator(AutoSpacedLocator): + def __init__(self): + AutoSpacedLocator.__init__(self, steps=[1, 2, 5, 10]) + + +class ClassicAutoLocator(MaxNLocator): + # Used only for classic style def __init__(self): MaxNLocator.__init__(self, nbins=9, steps=[1, 2, 5, 10]) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy