diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 1f12bfd077ff..c65423f348df 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -621,11 +621,21 @@ def __get__(self, instance, cls): if self._major: instance.majorTicks = [] tick = instance._get_tick(major=True) + try: + tick.set_clip_path(instance.axes.patch) + except AttributeError: + pass + tick._apply_params(**instance._major_tick_kw) instance.majorTicks.append(tick) return instance.majorTicks else: instance.minorTicks = [] tick = instance._get_tick(major=False) + try: + tick.set_clip_path(instance.axes.patch) + except AttributeError: + pass + tick._apply_params(**instance._minor_tick_kw) instance.minorTicks.append(tick) return instance.minorTicks @@ -719,6 +729,12 @@ def __init__(self, axes, pickradius=15): majorTicks = _LazyTickList(major=True) minorTicks = _LazyTickList(major=False) + def _lazy_get_ticks_or_empty(self, *, major=True): + # Return ticks without triggering auto-instantiation. This is + # important for performance! + name = "majorTicks" if major else "minorTicks" + return vars(self).get(name, []) + def get_remove_overlapping_locs(self): return self._remove_overlapping_locs @@ -838,11 +854,11 @@ def set_tick_params(self, which='major', reset=False, **kw): else: if which in ['major', 'both']: self._major_tick_kw.update(kwtrans) - for tick in self.majorTicks: + for tick in self._lazy_get_ticks_or_empty(major=True): tick._apply_params(**kwtrans) if which in ['minor', 'both']: self._minor_tick_kw.update(kwtrans) - for tick in self.minorTicks: + for tick in self._lazy_get_ticks_or_empty(major=False): tick._apply_params(**kwtrans) # special-case label color to also apply to the offset text if 'labelcolor' in kwtrans: @@ -897,7 +913,8 @@ def _translate_tick_kw(kw): def set_clip_path(self, clippath, transform=None): martist.Artist.set_clip_path(self, clippath, transform) - for child in self.majorTicks + self.minorTicks: + for child in (self._lazy_get_ticks_or_empty(major=True) + + self._lazy_get_ticks_or_empty(major=False)): child.set_clip_path(clippath, transform) self.stale = True diff --git a/lib/matplotlib/spines.py b/lib/matplotlib/spines.py index b0b61a81ceb5..5ea681ef2d8b 100644 --- a/lib/matplotlib/spines.py +++ b/lib/matplotlib/spines.py @@ -373,6 +373,16 @@ def _adjust_location(self): @allow_rasterization def draw(self, renderer): + # The calls to get_x/yaxis_transform are necessary to set up the spine + # transforms properly in the case of rectilinear axes. (This was + # previously done implicitly on tick init, but now ticks are init'ed + # lazily at draw time.) Really, one just needs to call + # _ensure_position_is_set(), except that this breaks polar axes which + # are brittle. + self.axes.get_xaxis_transform('tick1') + self.axes.get_xaxis_transform('tick2') + self.axes.get_yaxis_transform('tick1') + self.axes.get_yaxis_transform('tick2') self._adjust_location() ret = super().draw(renderer) self.stale = False