Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3fe222c

Browse files
committed
fix
1 parent d0bb8ff commit 3fe222c

1 file changed

Lines changed: 85 additions & 48 deletions

File tree

lib/matplotlib/axis.py

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -550,36 +550,19 @@ def __init__(self, major):
550550
def __get__(self, instance, owner):
551551
if instance is None:
552552
return self
553-
else:
554-
# instance._get_tick() can itself try to access the majorTicks
555-
# attribute (e.g. in certain projection classes which override
556-
# e.g. get_xaxis_text1_transform). In order to avoid infinite
557-
# recursion, first set the majorTicks on the instance temporarily
558-
# to an empty list. Then create the tick; note that _get_tick()
559-
# may call reset_ticks(). Therefore, the final tick list is
560-
# created and assigned afterwards.
561-
if self._major:
562-
instance.majorTicks = []
563-
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
570-
instance.majorTicks = [tick]
571-
return instance.majorTicks
572-
else:
573-
instance.minorTicks = []
574-
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
581-
instance.minorTicks = [tick]
582-
return instance.minorTicks
553+
# instance._get_tick() can itself try to access the majorTicks
554+
# attribute (e.g. in certain projection classes which override
555+
# e.g. get_xaxis_text1_transform). In order to avoid infinite
556+
# recursion, first set the majorTicks on the instance temporarily
557+
# to an empty list. Then create the tick; note that _get_tick()
558+
# may call reset_ticks(). Therefore, the final tick list is
559+
# created and assigned afterwards.
560+
attr = 'majorTicks' if self._major else 'minorTicks'
561+
setattr(instance, attr, [])
562+
tick = instance._get_tick(major=self._major)
563+
instance._propagate_axis_state_to_tick(tick)
564+
setattr(instance, attr, [tick])
565+
return getattr(instance, attr)
583566

584567

585568
class Axis(martist.Artist):
@@ -858,17 +841,76 @@ def get_children(self):
858841
return [self.label, self.offsetText,
859842
*self.get_major_ticks(), *self.get_minor_ticks()]
860843

844+
def _propagate_axis_state_to_tick(self, tick):
845+
"""
846+
Copy Axis state that a lazily-created Tick would otherwise miss.
847+
848+
Two things on the Axis were captured at Axes-construction time and
849+
need to flow through to a Tick built later by `_LazyTickList`:
850+
851+
1. Clip state (``clipbox`` / ``_clippath`` / ``_clipon``) -- set on
852+
the Axis by `Axis.set_clip_path`, which runs during
853+
``Axes.__clear`` before the Tick exists. Only the Tick itself
854+
and its gridline receive clip (matching `Tick.set_clip_path`).
855+
2. Per-Artist rcParams (`path.sketch`, `path.effects`) -- captured
856+
by `Artist.__init__` from the current `rcParams`. The Axis
857+
captured them at Axes-construction time, which may have been
858+
inside a ``plt.xkcd()`` / ``rc_context`` that has since exited;
859+
re-stamp them on every sub-artist of the fresh Tick so the
860+
rendered output matches the pre-lazy code path.
861+
"""
862+
for artist in (tick, tick.gridline):
863+
artist.clipbox = self.clipbox
864+
artist._clippath = self._clippath
865+
artist._clipon = self._clipon
866+
for artist in (tick, tick.tick1line, tick.tick2line, tick.gridline,
867+
tick.label1, tick.label2):
868+
artist._sketch = self._sketch
869+
artist._path_effects = self._path_effects
870+
871+
def _tick_kw_from_rcparams(self, major):
872+
"""
873+
Snapshot the rcParam-derived kwargs for a fresh `.Tick`.
874+
875+
`Tick.__init__` reads a handful of rcParams (size, width, color,
876+
grid styling, ...) when the corresponding kwarg is None. With lazy
877+
tick lists the Tick can be materialized long after the Axis was
878+
created -- e.g. inside a ``plt.xkcd()`` context whose ``__exit__``
879+
has already run -- which would silently yield different values
880+
than the eager pre-lazy behaviour. Freezing the relevant rcParams
881+
into the kw dict at init/clear time restores parity with that
882+
pre-lazy path.
883+
"""
884+
name = f"{self.axis_name}tick" # 'xtick' or 'ytick'
885+
major_minor = "major" if major else "minor"
886+
rc = mpl.rcParams
887+
labelcolor = rc[f"{name}.labelcolor"]
888+
if cbook._str_equal(labelcolor, "inherit"):
889+
labelcolor = rc[f"{name}.color"]
890+
return {
891+
"gridOn": rc["axes.grid"] and rc["axes.grid.which"] in ("both", major_minor),
892+
"size": rc[f"{name}.{major_minor}.size"],
893+
"width": rc[f"{name}.{major_minor}.width"],
894+
"pad": rc[f"{name}.{major_minor}.pad"],
895+
"color": rc[f"{name}.color"],
896+
"labelcolor": labelcolor,
897+
"labelsize": rc[f"{name}.labelsize"],
898+
"tickdir": rc[f"{name}.direction"],
899+
"grid_color": mpl._val_or_rc(
900+
None, f"grid.{major_minor}.color", "grid.color"),
901+
"grid_linestyle": mpl._val_or_rc(
902+
None, f"grid.{major_minor}.linestyle", "grid.linestyle"),
903+
"grid_linewidth": mpl._val_or_rc(
904+
None, f"grid.{major_minor}.linewidth", "grid.linewidth"),
905+
"grid_alpha": mpl._val_or_rc(
906+
None, f"grid.{major_minor}.alpha", "grid.alpha"),
907+
}
908+
861909
def _reset_major_tick_kw(self):
862-
self._major_tick_kw.clear()
863-
self._major_tick_kw['gridOn'] = (
864-
mpl.rcParams['axes.grid'] and
865-
mpl.rcParams['axes.grid.which'] in ('both', 'major'))
910+
self._major_tick_kw = self._tick_kw_from_rcparams(major=True)
866911

867912
def _reset_minor_tick_kw(self):
868-
self._minor_tick_kw.clear()
869-
self._minor_tick_kw['gridOn'] = (
870-
mpl.rcParams['axes.grid'] and
871-
mpl.rcParams['axes.grid.which'] in ('both', 'minor'))
913+
self._minor_tick_kw = self._tick_kw_from_rcparams(major=False)
872914

873915
def clear(self):
874916
"""
@@ -899,13 +941,10 @@ def clear(self):
899941
# Clear the callback registry for this axis, or it may "leak"
900942
self.callbacks = cbook.CallbackRegistry(signals=["units"])
901943

902-
# whether the grids are on
903-
self._major_tick_kw['gridOn'] = (
904-
mpl.rcParams['axes.grid'] and
905-
mpl.rcParams['axes.grid.which'] in ('both', 'major'))
906-
self._minor_tick_kw['gridOn'] = (
907-
mpl.rcParams['axes.grid'] and
908-
mpl.rcParams['axes.grid.which'] in ('both', 'minor'))
944+
# Snapshot rcParams-derived tick kwargs so lazily-materialized
945+
# Ticks see the same values the eager (pre-lazy) code path did.
946+
self._reset_major_tick_kw()
947+
self._reset_minor_tick_kw()
909948
self.reset_ticks()
910949

911950
self._converter = None
@@ -939,9 +978,7 @@ def _existing_ticks(self, major=None):
939978
doing so would
940979
941980
(a) create throwaway Tick objects during ``Axes.__init__`` and
942-
``Axes.__clear`` -- defeating the whole point of the lazy lists --
943-
and
944-
981+
``Axes.__clear``
945982
(b) risk re-entering the
946983
``Spine.set_position -> Axis.reset_ticks -> Axis.set_clip_path
947984
-> _LazyTickList.__get__ -> Tick.__init__ -> Spine.set_position``

0 commit comments

Comments
 (0)