-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix clearing subfigures #22138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix clearing subfigures #22138
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -913,6 +913,45 @@ def _break_share_link(ax, grouper): | |||||||||
# Break link between any twinned axes | ||||||||||
_break_share_link(ax, ax._twinned_axes) | ||||||||||
|
||||||||||
def clf(self, keep_observers=False): | ||||||||||
""" | ||||||||||
Clear the figure. | ||||||||||
|
||||||||||
Parameters | ||||||||||
---------- | ||||||||||
keep_observers: bool, default: False | ||||||||||
Set *keep_observers* to True if, for example, | ||||||||||
a gui widget is tracking the Axes in the figure. | ||||||||||
""" | ||||||||||
self.suppressComposite = None | ||||||||||
self.callbacks = cbook.CallbackRegistry() | ||||||||||
|
||||||||||
# first clear the axes in any subfigures | ||||||||||
for subfig in self.subfigs: | ||||||||||
subfig.clf(keep_observers=keep_observers) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
self.subfigs = [] | ||||||||||
|
||||||||||
for ax in tuple(self.axes): # Iterate over the copy. | ||||||||||
ax.cla() | ||||||||||
self.delaxes(ax) # Remove ax from self._axstack. | ||||||||||
|
||||||||||
self.artists = [] | ||||||||||
self.lines = [] | ||||||||||
self.patches = [] | ||||||||||
self.texts = [] | ||||||||||
self.images = [] | ||||||||||
self.legends = [] | ||||||||||
if not keep_observers: | ||||||||||
self._axobservers = cbook.CallbackRegistry() | ||||||||||
self._suptitle = None | ||||||||||
self._supxlabel = None | ||||||||||
self._supylabel = None | ||||||||||
|
||||||||||
self.stale = True | ||||||||||
|
||||||||||
# synonym for `clf`.""" | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra trailing quotes. |
||||||||||
clear = clf | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
# Note: in the docstring below, the newlines in the examples after the | ||||||||||
# calls to legend() allow replacing it with figlegend() to generate the | ||||||||||
# docstring of pyplot.figlegend. | ||||||||||
|
@@ -2801,40 +2840,13 @@ def set_figheight(self, val, forward=True): | |||||||||
self.set_size_inches(self.get_figwidth(), val, forward=forward) | ||||||||||
|
||||||||||
def clf(self, keep_observers=False): | ||||||||||
""" | ||||||||||
Clear the figure. | ||||||||||
|
||||||||||
Set *keep_observers* to True if, for example, | ||||||||||
a gui widget is tracking the Axes in the figure. | ||||||||||
""" | ||||||||||
self.suppressComposite = None | ||||||||||
self.callbacks = cbook.CallbackRegistry() | ||||||||||
|
||||||||||
for ax in tuple(self.axes): # Iterate over the copy. | ||||||||||
ax.cla() | ||||||||||
self.delaxes(ax) # Remove ax from self._axstack. | ||||||||||
|
||||||||||
# docstring inherited | ||||||||||
super().clf(keep_observers=keep_observers) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
# FigureBase.clf does not clear toolbars, as | ||||||||||
# only Figure can have toolbars | ||||||||||
toolbar = self.canvas.toolbar | ||||||||||
if toolbar is not None: | ||||||||||
toolbar.update() | ||||||||||
self._axstack = _AxesStack() | ||||||||||
self.artists = [] | ||||||||||
self.lines = [] | ||||||||||
self.patches = [] | ||||||||||
self.texts = [] | ||||||||||
self.images = [] | ||||||||||
self.legends = [] | ||||||||||
if not keep_observers: | ||||||||||
self._axobservers = cbook.CallbackRegistry() | ||||||||||
self._suptitle = None | ||||||||||
self._supxlabel = None | ||||||||||
self._supylabel = None | ||||||||||
|
||||||||||
self.stale = True | ||||||||||
|
||||||||||
def clear(self, keep_observers=False): | ||||||||||
"""Clear the figure -- synonym for `clf`.""" | ||||||||||
self.clf(keep_observers=keep_observers) | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
@_finalize_rasterization | ||||||||||
@allow_rasterization | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -709,6 +709,87 @@ def test_removed_axis(): | |
fig.canvas.draw() | ||
|
||
|
||
def test_figure_clear(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a mild preference to split each of these cases into its own test, but maybe that you can keep re-using the same figure is part of the test? |
||
# we test the following figure clearing scenarios: | ||
fig = plt.figure() | ||
|
||
# a) an empty figure | ||
fig.clear() | ||
assert fig.axes == [] | ||
|
||
# b) a figure with a single unnested axes | ||
ax = fig.add_subplot(111) | ||
fig.clear() | ||
assert fig.axes == [] | ||
|
||
# c) a figure multiple unnested axes | ||
axes = [fig.add_subplot(2, 1, i+1) for i in range(2)] | ||
fig.clear() | ||
assert fig.axes == [] | ||
|
||
# d) a figure with a subfigure | ||
gs = fig.add_gridspec(ncols=2, nrows=1) | ||
subfig = fig.add_subfigure(gs[0]) | ||
subaxes = subfig.add_subplot(111) | ||
fig.clear() | ||
assert subfig not in fig.subfigs | ||
assert fig.axes == [] | ||
|
||
# e) a figure with a subfigure and a subplot | ||
subfig = fig.add_subfigure(gs[0]) | ||
subaxes = subfig.add_subplot(111) | ||
mainaxes = fig.add_subplot(gs[1]) | ||
|
||
# e.1) removing just the axes leaves the subplot | ||
mainaxes.remove() | ||
assert fig.axes == [subaxes] | ||
|
||
# e.2) removing just the subaxes leaves the subplot | ||
# and subfigure | ||
mainaxes = fig.add_subplot(gs[1]) | ||
subaxes.remove() | ||
assert fig.axes == [mainaxes] | ||
assert subfig in fig.subfigs | ||
|
||
# e.3) clearing the subfigure leaves the subplot | ||
subaxes = subfig.add_subplot(111) | ||
assert mainaxes in fig.axes | ||
assert subaxes in fig.axes | ||
subfig.clear() | ||
assert subfig in fig.subfigs | ||
assert subaxes not in subfig.axes | ||
assert subaxes not in fig.axes | ||
assert mainaxes in fig.axes | ||
|
||
# e.4) clearing the whole thing | ||
subaxes = subfig.add_subplot(111) | ||
fig.clear() | ||
assert fig.axes == [] | ||
assert fig.subfigs == [] | ||
|
||
# f) multiple subfigures | ||
subfigs = [fig.add_subfigure(gs[i]) for i in [0, 1]] | ||
subaxes = [sfig.add_subplot(111) for sfig in subfigs] | ||
assert all(ax in fig.axes for ax in subaxes) | ||
assert all(sfig in fig.subfigs for sfig in subfigs) | ||
|
||
# f.1) clearing only one subfigure | ||
subfigs[0].clear() | ||
assert subaxes[0] not in fig.axes | ||
assert subaxes[1] in fig.axes | ||
assert subfigs[1] in fig.subfigs | ||
|
||
# f.2) clearing the whole thing | ||
subfigs[1].clear() | ||
subfigs = [fig.add_subfigure(gs[i]) for i in [0, 1]] | ||
subaxes = [sfig.add_subplot(111) for sfig in subfigs] | ||
assert all(ax in fig.axes for ax in subaxes) | ||
assert all(sfig in fig.subfigs for sfig in subfigs) | ||
fig.clear() | ||
assert fig.subfigs == [] | ||
assert fig.axes == [] | ||
|
||
|
||
@mpl.style.context('mpl20') | ||
def test_picking_does_not_stale(): | ||
fig, ax = plt.subplots() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.