diff --git a/doc/api/api_changes/2017-11-13-TH.rst b/doc/api/api_changes/2017-11-13-TH.rst new file mode 100644 index 000000000000..af55c993a708 --- /dev/null +++ b/doc/api/api_changes/2017-11-13-TH.rst @@ -0,0 +1,13 @@ +Internal handling of axis ticks optimized +----------------------------------------- + +No officially documented parts of the API have changed. However, you may have +implicitly relied on a certain behavior. + +`Axis.majorTicks` and `Axis.minorTicks` are deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The undocumented attributes `majorTicks` and `minorTicks` of +:class:`matplotlib.axis.Axis` are now explicitly considered private and may be +removed in the future. Please uses :meth:`matplotlib.axis.Axis.get_major_ticks` +and :meth:`matplotlib.axis.Axis.get_minor_ticks` only. diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 55322ce2666e..bf67a7ce7dc7 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -21,6 +21,7 @@ import matplotlib.units as munits import numpy as np import warnings +import itertools GRIDLINE_INTERPOLATION_STEPS = 180 @@ -625,6 +626,40 @@ class Ticker(object): formatter = None +class _LazyDefaultTickList(object): + """ + A lazy evaluating placeholder for the default tick list. + + On access the class replaces itself with the default 1-element list. We + use the lazy evaluation so that :meth:`matplotlib.axis.Axis.reset_ticks` + can be called multiple times without the overhead of initialzing every + time. + + https://github.com/matplotlib/matplotlib/issues/6664 + """ + def __init__(self, axis, major=True): + self.axis = axis + self.major = major + + def _instantiate_list(self): + if self.major: + self.axis.majorTicks = [self.axis._get_tick(major=True)] + return self.axis.majorTicks + else: + self.axis.minorTicks = [self.axis._get_tick(major=False)] + return self.axis.minorTicks + + def __iter__(self): + return iter(self._instantiate_list()) + + def __len__(self): + return len(self._instantiate_list()) + + def __getitem__(self, key): + l = self._instantiate_list() + return l[key] + + class Axis(artist.Artist): """ Public attributes @@ -781,13 +816,12 @@ def reset_ticks(self): # build a few default ticks; grow as necessary later; only # define 1 so properties set on ticks will be copied as they # grow - del self.majorTicks[:] - del self.minorTicks[:] - - self.majorTicks.extend([self._get_tick(major=True)]) - self.minorTicks.extend([self._get_tick(major=False)]) - self._lastNumMajorTicks = 1 - self._lastNumMinorTicks = 1 + if not isinstance(self.majorTicks, _LazyDefaultTickList): + del self.majorTicks[:] + self.majorTicks = _LazyDefaultTickList(self, major=True) + if not isinstance(self.minorTicks, _LazyDefaultTickList): + del self.minorTicks[:] + self.minorTicks = _LazyDefaultTickList(self, major=False) def set_tick_params(self, which='major', reset=False, **kw): """ @@ -872,7 +906,8 @@ def _translate_tick_kw(kw, to_init_kw=True): def set_clip_path(self, clippath, transform=None): artist.Artist.set_clip_path(self, clippath, transform) - for child in self.majorTicks + self.minorTicks: + for child in itertools.chain(iter(self.majorTicks), + iter(self.minorTicks)): child.set_clip_path(clippath, transform) self.stale = True @@ -1339,22 +1374,15 @@ def get_major_ticks(self, numticks=None): numticks = len(self.get_major_locator()()) if len(self.majorTicks) < numticks: # update the new tick label properties from the old + protoTick = self.majorTicks[0] for i in range(numticks - len(self.majorTicks)): tick = self._get_tick(major=True) - self.majorTicks.append(tick) - - if self._lastNumMajorTicks < numticks: - protoTick = self.majorTicks[0] - for i in range(self._lastNumMajorTicks, len(self.majorTicks)): - tick = self.majorTicks[i] if self._gridOnMajor: tick.gridOn = True self._copy_tick_props(protoTick, tick) + self.majorTicks.append(tick) - self._lastNumMajorTicks = numticks - ticks = self.majorTicks[:numticks] - - return ticks + return self.majorTicks[:numticks] def get_minor_ticks(self, numticks=None): 'get the minor tick instances; grow as necessary' @@ -1363,22 +1391,15 @@ def get_minor_ticks(self, numticks=None): if len(self.minorTicks) < numticks: # update the new tick label properties from the old + protoTick = self.minorTicks[0] for i in range(numticks - len(self.minorTicks)): tick = self._get_tick(major=False) - self.minorTicks.append(tick) - - if self._lastNumMinorTicks < numticks: - protoTick = self.minorTicks[0] - for i in range(self._lastNumMinorTicks, len(self.minorTicks)): - tick = self.minorTicks[i] if self._gridOnMinor: tick.gridOn = True self._copy_tick_props(protoTick, tick) + self.minorTicks.append(tick) - self._lastNumMinorTicks = numticks - ticks = self.minorTicks[:numticks] - - return ticks + return self.minorTicks[:numticks] def grid(self, b=None, which='major', **kwargs): """