Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 50b009a

Browse files
QuLogicmeeseeksmachine
authored andcommitted
Backport PR matplotlib#23735: Correctly handle Axes subclasses that override cla
1 parent b4721e5 commit 50b009a

File tree

3 files changed

+106
-9
lines changed

3 files changed

+106
-9
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
``AXes`` subclasses should override ``clear`` instead of ``cla``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
For clarity, `.axes.Axes.clear` is now preferred over `.Axes.cla`. However, for
5+
backwards compatibility, the latter will remain as an alias for the former.
6+
7+
For additional compatibility with third-party libraries, Matplotlib will
8+
continue to call the ``cla`` method of any `~.axes.Axes` subclasses if they
9+
define it. In the future, this will no longer occur, and Matplotlib will only
10+
call the ``clear`` method in `~.axes.Axes` subclasses.
11+
12+
It is recommended to define only the ``clear`` method when on Matplotlib 3.6,
13+
and only ``cla`` for older versions.

‎lib/matplotlib/axes/_base.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ class _AxesBase(martist.Artist):
559559
_shared_axes = {name: cbook.Grouper() for name in _axis_names}
560560
_twinned_axes = cbook.Grouper()
561561

562+
_subclass_uses_cla = False
563+
562564
@property
563565
def _axis_map(self):
564566
"""A mapping of axis names, e.g. 'x', to `Axis` instances."""
@@ -699,6 +701,20 @@ def __init__(self, fig, rect,
699701
rcParams['ytick.major.right']),
700702
which='major')
701703

704+
def __init_subclass__(cls, **kwargs):
705+
parent_uses_cla = super(cls, cls)._subclass_uses_cla
706+
if 'cla' in cls.__dict__:
707+
_api.warn_deprecated(
708+
'3.6',
709+
pending=True,
710+
message=f'Overriding `Axes.cla` in {cls.__qualname__} is '
711+
'pending deprecation in %(since)s and will be fully '
712+
'deprecated in favor of `Axes.clear` in the future. '
713+
'Please report '
714+
f'this to the {cls.__module__!r} author.')
715+
cls._subclass_uses_cla = 'cla' in cls.__dict__ or parent_uses_cla
716+
super().__init_subclass__(**kwargs)
717+
702718
def __getstate__(self):
703719
state = super().__getstate__()
704720
# Prune the sharing & twinning info to only contain the current group.
@@ -1199,9 +1215,12 @@ def sharey(self, other):
11991215
self.set_ylim(y0, y1, emit=False, auto=other.get_autoscaley_on())
12001216
self.yaxis._scale = other.yaxis._scale
12011217

1202-
def clear(self):
1218+
def __clear(self):
12031219
"""Clear the Axes."""
1204-
# Note: this is called by Axes.__init__()
1220+
# The actual implementation of clear() as long as clear() has to be
1221+
# an adapter delegating to the correct implementation.
1222+
# The implementation can move back into clear() when the
1223+
# deprecation on cla() subclassing expires.
12051224

12061225
# stash the current visibility state
12071226
if hasattr(self, 'patch'):
@@ -1318,6 +1337,24 @@ def clear(self):
13181337

13191338
self.stale = True
13201339

1340+
def clear(self):
1341+
"""Clear the Axes."""
1342+
# Act as an alias, or as the superclass implementation depending on the
1343+
# subclass implementation.
1344+
if self._subclass_uses_cla:
1345+
self.cla()
1346+
else:
1347+
self.__clear()
1348+
1349+
def cla(self):
1350+
"""Clear the Axes."""
1351+
# Act as an alias, or as the superclass implementation depending on the
1352+
# subclass implementation.
1353+
if self._subclass_uses_cla:
1354+
self.__clear()
1355+
else:
1356+
self.clear()
1357+
13211358
class ArtistList(MutableSequence):
13221359
"""
13231360
A sublist of Axes children based on their type.
@@ -1481,10 +1518,6 @@ def texts(self):
14811518
return self.ArtistList(self, 'texts', 'add_artist',
14821519
valid_types=mtext.Text)
14831520

1484-
def cla(self):
1485-
"""Clear the Axes."""
1486-
self.clear()
1487-
14881521
def get_facecolor(self):
14891522
"""Get the facecolor of the Axes."""
14901523
return self.patch.get_facecolor()

‎lib/matplotlib/tests/test_axes.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -486,10 +486,61 @@ def test_inverted_cla():
486486
plt.close(fig)
487487

488488

489-
def test_cla_not_redefined():
489+
def test_subclass_clear_cla():
490+
# Ensure that subclasses of Axes call cla/clear correctly.
491+
# Note, we cannot use mocking here as we want to be sure that the
492+
# superclass fallback does not recurse.
493+
494+
with pytest.warns(match='Overriding `Axes.cla`'):
495+
class ClaAxes(Axes):
496+
def cla(self):
497+
nonlocal called
498+
called = True
499+
500+
with pytest.warns(match='Overriding `Axes.cla`'):
501+
class ClaSuperAxes(Axes):
502+
def cla(self):
503+
nonlocal called
504+
called = True
505+
super().cla()
506+
507+
class SubClaAxes(ClaAxes):
508+
pass
509+
510+
class ClearAxes(Axes):
511+
def clear(self):
512+
nonlocal called
513+
called = True
514+
515+
class ClearSuperAxes(Axes):
516+
def clear(self):
517+
nonlocal called
518+
called = True
519+
super().clear()
520+
521+
class SubClearAxes(ClearAxes):
522+
pass
523+
524+
fig = Figure()
525+
for axes_class in [ClaAxes, ClaSuperAxes, SubClaAxes,
526+
ClearAxes, ClearSuperAxes, SubClearAxes]:
527+
called = False
528+
ax = axes_class(fig, [0, 0, 1, 1])
529+
# Axes.__init__ has already called clear (which aliases to cla or is in
530+
# the subclass).
531+
assert called
532+
533+
called = False
534+
ax.cla()
535+
assert called
536+
537+
538+
def test_cla_not_redefined_internally():
490539
for klass in Axes.__subclasses__():
491-
# check that cla does not get redefined in our Axes subclasses
492-
assert 'cla' not in klass.__dict__
540+
# Check that cla does not get redefined in our Axes subclasses, except
541+
# for in the above test function.
542+
if 'test_subclass_clear_cla' not in klass.__qualname__:
543+
assert 'cla' not in klass.__dict__
493544

494545

495546
@check_figures_equal(extensions=["png"])

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /