@@ -561,11 +561,23 @@ def __get__(self, instance, owner):
561561 if self ._major :
562562 instance .majorTicks = []
563563 tick = instance ._get_tick (major = True )
564+ tick .clipbox = instance .clipbox
565+ tick ._clippath = instance ._clippath
566+ tick ._clipon = instance ._clipon
567+ tick .gridline .clipbox = instance .clipbox
568+ tick .gridline ._clippath = instance ._clippath
569+ tick .gridline ._clipon = instance ._clipon
564570 instance .majorTicks = [tick ]
565571 return instance .majorTicks
566572 else :
567573 instance .minorTicks = []
568574 tick = instance ._get_tick (major = False )
575+ tick .clipbox = instance .clipbox
576+ tick ._clippath = instance ._clippath
577+ tick ._clipon = instance ._clipon
578+ tick .gridline .clipbox = instance .clipbox
579+ tick .gridline ._clippath = instance ._clippath
580+ tick .gridline ._clipon = instance ._clipon
569581 instance .minorTicks = [tick ]
570582 return instance .minorTicks
571583
@@ -908,18 +920,45 @@ def reset_ticks(self):
908920 Each list starts with a single fresh Tick.
909921 """
910922 # Restore the lazy tick lists.
911- try :
912- del self .majorTicks
913- except AttributeError :
914- pass
915- try :
916- del self .minorTicks
917- except AttributeError :
918- pass
919- try :
920- self .set_clip_path (self .axes .patch )
921- except AttributeError :
922- pass
923+ had_major = bool (self .__dict__ .pop ('majorTicks' , None ))
924+ had_minor = bool (self .__dict__ .pop ('minorTicks' , None ))
925+ if had_major or had_minor :
926+ try :
927+ self .set_clip_path (self .axes .patch )
928+ except AttributeError :
929+ pass
930+
931+ def _existing_ticks (self , major = None ):
932+ """
933+ Yield already-materialized ticks without triggering the lazy descriptor.
934+
935+ `majorTicks` and `minorTicks` are `_LazyTickList` descriptors that
936+ create a fresh `.Tick` on first access. Several internal methods
937+ (`set_clip_path`, `set_tick_params`) need to touch every
938+ *already-materialized* tick without forcing materialization, because
939+ doing so would
940+
941+ (a) create throwaway Tick objects during ``Axes.__init__`` and
942+ ``Axes.__clear`` -- defeating the whole point of the lazy lists --
943+ and
944+
945+ (b) risk re-entering the
946+ ``Spine.set_position -> Axis.reset_ticks -> Axis.set_clip_path
947+ -> _LazyTickList.__get__ -> Tick.__init__ -> Spine.set_position``
948+ cascade.
949+
950+ Reading the instance ``__dict__`` directly bypasses the descriptor.
951+
952+ Parameters
953+ ----------
954+ major : bool, optional
955+ If True, yield only major ticks; if False, only minor ticks;
956+ if None (default), yield major followed by minor.
957+ """
958+ if major is None or major :
959+ yield from self .__dict__ .get ('majorTicks' , ())
960+ if major is None or not major :
961+ yield from self .__dict__ .get ('minorTicks' , ())
923962
924963 def minorticks_on (self ):
925964 """
@@ -988,11 +1027,11 @@ def set_tick_params(self, which='major', reset=False, **kwargs):
9881027 else :
9891028 if which in ['major' , 'both' ]:
9901029 self ._major_tick_kw .update (kwtrans )
991- for tick in self .majorTicks :
1030+ for tick in self ._existing_ticks ( major = True ) :
9921031 tick ._apply_params (** kwtrans )
9931032 if which in ['minor' , 'both' ]:
9941033 self ._minor_tick_kw .update (kwtrans )
995- for tick in self .minorTicks :
1034+ for tick in self ._existing_ticks ( major = False ) :
9961035 tick ._apply_params (** kwtrans )
9971036 # labelOn and labelcolor also apply to the offset text.
9981037 if 'label1On' in kwtrans or 'label2On' in kwtrans :
@@ -1131,7 +1170,7 @@ def _translate_tick_params(cls, kw, reverse=False):
11311170
11321171 def set_clip_path (self , path , transform = None ):
11331172 super ().set_clip_path (path , transform )
1134- for child in self .majorTicks + self . minorTicks :
1173+ for child in self ._existing_ticks () :
11351174 child .set_clip_path (path , transform )
11361175 self .stale = True
11371176
0 commit comments