Skip to content

Commit d2fc3a4

Browse files
authored
Merge pull request #26164 from oscargus/noclearonregister
Only clear Axis once when creating an Axes
2 parents fff2a79 + b86c8fd commit d2fc3a4

File tree

9 files changed

+66
-43
lines changed

9 files changed

+66
-43
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
``Text.get_rotation_mode`` return value
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
Passing ``None`` as ``rotation_mode`` to `.Text` (the default value) or passing it to
5+
`.Text.set_rotation_mode` will make `.Text.get_rotation_mode` return ``"default"``
6+
instead of ``None``. The behaviour otherwise is the same.

lib/matplotlib/axes/_base.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -814,10 +814,10 @@ def get_window_extent(self, renderer=None):
814814

815815
def _init_axis(self):
816816
# This is moved out of __init__ because non-separable axes don't use it
817-
self.xaxis = maxis.XAxis(self)
817+
self.xaxis = maxis.XAxis(self, clear=False)
818818
self.spines.bottom.register_axis(self.xaxis)
819819
self.spines.top.register_axis(self.xaxis)
820-
self.yaxis = maxis.YAxis(self)
820+
self.yaxis = maxis.YAxis(self, clear=False)
821821
self.spines.left.register_axis(self.yaxis)
822822
self.spines.right.register_axis(self.yaxis)
823823

@@ -1275,7 +1275,7 @@ def __clear(self):
12751275
for axis in self._axis_map.values():
12761276
axis.clear() # Also resets the scale to linear.
12771277
for spine in self.spines.values():
1278-
spine.clear()
1278+
spine._clear() # Use _clear to not clear Axis again
12791279

12801280
self.ignore_existing_data_limits = True
12811281
self.callbacks = cbook.CallbackRegistry(

lib/matplotlib/axis.py

+28-18
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
_gridline_param_names = ['grid_' + name
3333
for name in _line_param_names + _line_param_aliases]
3434

35+
_MARKER_DICT = {
36+
'out': (mlines.TICKDOWN, mlines.TICKUP),
37+
'in': (mlines.TICKUP, mlines.TICKDOWN),
38+
'inout': ('|', '|'),
39+
}
40+
3541

3642
class Tick(martist.Artist):
3743
"""
@@ -87,11 +93,10 @@ def __init__(
8793
super().__init__()
8894

8995
if gridOn is None:
90-
if major and (mpl.rcParams['axes.grid.which']
91-
in ('both', 'major')):
96+
which = mpl.rcParams['axes.grid.which']
97+
if major and (which in ('both', 'major')):
9298
gridOn = mpl.rcParams['axes.grid']
93-
elif (not major) and (mpl.rcParams['axes.grid.which']
94-
in ('both', 'minor')):
99+
elif (not major) and (which in ('both', 'minor')):
95100
gridOn = mpl.rcParams['axes.grid']
96101
else:
97102
gridOn = False
@@ -209,7 +214,8 @@ def _apply_tickdir(self, tickdir):
209214
# further updates ticklabel positions using the new pads.
210215
if tickdir is None:
211216
tickdir = mpl.rcParams[f'{self.__name__}.direction']
212-
_api.check_in_list(['in', 'out', 'inout'], tickdir=tickdir)
217+
else:
218+
_api.check_in_list(['in', 'out', 'inout'], tickdir=tickdir)
213219
self._tickdir = tickdir
214220
self._pad = self._base_pad + self.get_tick_padding()
215221

@@ -436,11 +442,7 @@ def _get_text2_transform(self):
436442
def _apply_tickdir(self, tickdir):
437443
# docstring inherited
438444
super()._apply_tickdir(tickdir)
439-
mark1, mark2 = {
440-
'out': (mlines.TICKDOWN, mlines.TICKUP),
441-
'in': (mlines.TICKUP, mlines.TICKDOWN),
442-
'inout': ('|', '|'),
443-
}[self._tickdir]
445+
mark1, mark2 = _MARKER_DICT[self._tickdir]
444446
self.tick1line.set_marker(mark1)
445447
self.tick2line.set_marker(mark2)
446448

@@ -632,7 +634,7 @@ def __str__(self):
632634
return "{}({},{})".format(
633635
type(self).__name__, *self.axes.transAxes.transform((0, 0)))
634636

635-
def __init__(self, axes, *, pickradius=15):
637+
def __init__(self, axes, *, pickradius=15, clear=True):
636638
"""
637639
Parameters
638640
----------
@@ -641,6 +643,11 @@ def __init__(self, axes, *, pickradius=15):
641643
pickradius : float
642644
The acceptance radius for containment tests. See also
643645
`.Axis.contains`.
646+
clear : bool, default: True
647+
Whether to clear the Axis on creation. This is not required, e.g., when
648+
creating an Axis as part of an Axes, as ``Axes.clear`` will call
649+
``Axis.clear``.
650+
.. versionadded:: 3.8
644651
"""
645652
super().__init__()
646653
self._remove_overlapping_locs = True
@@ -674,7 +681,12 @@ def __init__(self, axes, *, pickradius=15):
674681
self._major_tick_kw = dict()
675682
self._minor_tick_kw = dict()
676683

677-
self.clear()
684+
if clear:
685+
self.clear()
686+
else:
687+
self.converter = None
688+
self.units = None
689+
678690
self._autoscale_on = True
679691

680692
@property
@@ -2353,8 +2365,6 @@ def set_ticks_position(self, position):
23532365
can be used if you don't want any ticks. 'none' and 'both'
23542366
affect only the ticks, not the labels.
23552367
"""
2356-
_api.check_in_list(['top', 'bottom', 'both', 'default', 'none'],
2357-
position=position)
23582368
if position == 'top':
23592369
self.set_tick_params(which='both', top=True, labeltop=True,
23602370
bottom=False, labelbottom=False)
@@ -2377,7 +2387,8 @@ def set_ticks_position(self, position):
23772387
self._tick_position = 'bottom'
23782388
self.offsetText.set_verticalalignment('top')
23792389
else:
2380-
assert False, "unhandled parameter not caught by _check_in_list"
2390+
_api.check_in_list(['top', 'bottom', 'both', 'default', 'none'],
2391+
position=position)
23812392
self.stale = True
23822393

23832394
def tick_top(self):
@@ -2599,8 +2610,6 @@ def set_ticks_position(self, position):
25992610
can be used if you don't want any ticks. 'none' and 'both'
26002611
affect only the ticks, not the labels.
26012612
"""
2602-
_api.check_in_list(['left', 'right', 'both', 'default', 'none'],
2603-
position=position)
26042613
if position == 'right':
26052614
self.set_tick_params(which='both', right=True, labelright=True,
26062615
left=False, labelleft=False)
@@ -2619,7 +2628,8 @@ def set_ticks_position(self, position):
26192628
self.set_tick_params(which='both', right=True, labelright=False,
26202629
left=True, labelleft=True)
26212630
else:
2622-
assert False, "unhandled parameter not caught by _check_in_list"
2631+
_api.check_in_list(['left', 'right', 'both', 'default', 'none'],
2632+
position=position)
26232633
self.stale = True
26242634

26252635
def tick_right(self):

lib/matplotlib/axis.pyi

+2-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ class Axis(martist.Artist):
105105
offsetText: Text
106106
labelpad: float
107107
pickradius: float
108-
def __init__(self, axes, *, pickradius: float = ...) -> None: ...
108+
def __init__(self, axes, *, pickradius: float = ...,
109+
clear: bool = ...) -> None: ...
109110
@property
110111
def isDefault_majloc(self) -> bool: ...
111112
@isDefault_majloc.setter

lib/matplotlib/projections/geo.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@ def __call__(self, x, pos=None):
3030
RESOLUTION = 75
3131

3232
def _init_axis(self):
33-
self.xaxis = maxis.XAxis(self)
34-
self.yaxis = maxis.YAxis(self)
35-
# Do not register xaxis or yaxis with spines -- as done in
36-
# Axes._init_axis() -- until GeoAxes.xaxis.clear() works.
37-
# self.spines['geo'].register_axis(self.yaxis)
33+
self.xaxis = maxis.XAxis(self, clear=False)
34+
self.yaxis = maxis.YAxis(self, clear=False)
35+
self.spines['geo'].register_axis(self.yaxis)
3836

3937
def clear(self):
4038
# docstring inherited

lib/matplotlib/projections/polar.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -846,11 +846,9 @@ def clear(self):
846846

847847
def _init_axis(self):
848848
# This is moved out of __init__ because non-separable axes don't use it
849-
self.xaxis = ThetaAxis(self)
850-
self.yaxis = RadialAxis(self)
851-
# Calling polar_axes.xaxis.clear() or polar_axes.yaxis.clear()
852-
# results in weird artifacts. Therefore we disable this for now.
853-
# self.spines['polar'].register_axis(self.yaxis)
849+
self.xaxis = ThetaAxis(self, clear=False)
850+
self.yaxis = RadialAxis(self, clear=False)
851+
self.spines['polar'].register_axis(self.yaxis)
854852

855853
def _set_lim_and_transforms(self):
856854
# A view limit where the minimum radius can be locked if the user

lib/matplotlib/spines.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,23 @@ def register_axis(self, axis):
214214
properties when needed.
215215
"""
216216
self.axis = axis
217-
if self.axis is not None:
218-
self.axis.clear()
219217
self.stale = True
220218

221219
def clear(self):
222220
"""Clear the current spine."""
223-
self._position = None # clear position
221+
self._clear()
224222
if self.axis is not None:
225223
self.axis.clear()
226224

225+
def _clear(self):
226+
"""
227+
Clear things directly related to the spine.
228+
229+
In this way it is possible to avoid clearing the Axis as well when calling
230+
from library code where it is known that the Axis is cleared separately.
231+
"""
232+
self._position = None # clear position
233+
227234
def _adjust_location(self):
228235
"""Automatically set spine bounds to the view interval."""
229236

lib/matplotlib/text.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ def __init__(self,
136136
super().__init__()
137137
self._x, self._y = x, y
138138
self._text = ''
139-
self._antialiased = mpl.rcParams['text.antialiased']
140139
self._reset_visual_defaults(
141140
text=text,
142141
color=color,
@@ -191,8 +190,8 @@ def _reset_visual_defaults(
191190
linespacing = 1.2 # Maybe use rcParam later.
192191
self.set_linespacing(linespacing)
193192
self.set_rotation_mode(rotation_mode)
194-
if antialiased is not None:
195-
self.set_antialiased(antialiased)
193+
self.set_antialiased(antialiased if antialiased is not None else
194+
mpl.rcParams['text.antialiased'])
196195

197196
def update(self, kwargs):
198197
# docstring inherited
@@ -303,11 +302,15 @@ def set_rotation_mode(self, m):
303302
Parameters
304303
----------
305304
m : {None, 'default', 'anchor'}
306-
If ``None`` or ``"default"``, the text will be first rotated, then
307-
aligned according to their horizontal and vertical alignments. If
308-
``"anchor"``, then alignment occurs before rotation.
305+
If ``"default"``, the text will be first rotated, then aligned according
306+
to their horizontal and vertical alignments. If ``"anchor"``, then
307+
alignment occurs before rotation. Passing ``None`` will set the rotation
308+
mode to ``"default"``.
309309
"""
310-
_api.check_in_list(["anchor", "default", None], rotation_mode=m)
310+
if m is None:
311+
m = "default"
312+
else:
313+
_api.check_in_list(("anchor", "default"), rotation_mode=m)
311314
self._rotation_mode = m
312315
self.stale = True
313316

lib/matplotlib/text.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Text(Artist):
4747
def get_rotation(self) -> float: ...
4848
def get_transform_rotates_text(self) -> bool: ...
4949
def set_rotation_mode(self, m: None | Literal["default", "anchor"]) -> None: ...
50-
def get_rotation_mode(self) -> None | Literal["default", "anchor"]: ...
50+
def get_rotation_mode(self) -> Literal["default", "anchor"]: ...
5151
def set_bbox(self, rectprops: dict[str, Any]) -> None: ...
5252
def get_bbox_patch(self) -> None | FancyBboxPatch: ...
5353
def update_bbox_position_size(self, renderer: RendererBase) -> None: ...

0 commit comments

Comments
 (0)