Skip to content

Deprecate auto-removal of overlapping Axes by plt.subplot{,2grid}. #22418

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

Merged
merged 1 commit into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/api/next_api_changes/deprecations/22418-AL.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Auto-removal of overlapping Axes by ``plt.subplot`` and ``plt.subplot2grid``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previously, `.pyplot.subplot` and `.pyplot.subplot2grid` would automatically
remove preexisting Axes that overlap with the newly added Axes. This behavior
was deemed confusing, and is now deprecated. Explicitly call ``ax.remove()``
on Axes that need to be removed.
29 changes: 15 additions & 14 deletions lib/matplotlib/pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1303,13 +1303,13 @@ def subplot(*args, **kwargs):

fig.sca(ax)

bbox = ax.bbox
axes_to_delete = []
for other_ax in fig.axes:
if other_ax == ax:
continue
if bbox.fully_overlaps(other_ax.bbox):
axes_to_delete.append(other_ax)
axes_to_delete = [other for other in fig.axes
if other != ax and ax.bbox.fully_overlaps(other.bbox)]
if axes_to_delete:
_api.warn_deprecated(
"3.6", message="Auto-removal of overlapping axes is deprecated "
"since %(since)s and will be removed %(removal)s; explicitly call "
"ax.remove() as needed.")
for ax_to_del in axes_to_delete:
delaxes(ax_to_del)

Expand Down Expand Up @@ -1596,13 +1596,14 @@ def subplot2grid(shape, loc, rowspan=1, colspan=1, fig=None, **kwargs):

subplotspec = gs.new_subplotspec(loc, rowspan=rowspan, colspan=colspan)
ax = fig.add_subplot(subplotspec, **kwargs)
bbox = ax.bbox
axes_to_delete = []
for other_ax in fig.axes:
if other_ax == ax:
continue
if bbox.fully_overlaps(other_ax.bbox):
axes_to_delete.append(other_ax)

axes_to_delete = [other for other in fig.axes
if other != ax and ax.bbox.fully_overlaps(other.bbox)]
if axes_to_delete:
_api.warn_deprecated(
"3.6", message="Auto-removal of overlapping axes is deprecated "
"since %(since)s and will be removed %(removal)s; explicitly call "
"ax.remove() as needed.")
for ax_to_del in axes_to_delete:
delaxes(ax_to_del)

Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ def test_inverted_cla():
assert not ax.xaxis_inverted()
assert ax.yaxis_inverted()

for ax in fig.axes:
ax.remove()
# 5. two shared axes. Inverting the leader axis should invert the shared
# axes; clearing the leader axis should bring axes in shared
# axes back to normal.
Expand Down
22 changes: 15 additions & 7 deletions lib/matplotlib/tests/test_pyplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ def test_subplot_replace_projection():
ax = plt.subplot(1, 2, 1)
ax1 = plt.subplot(1, 2, 1)
ax2 = plt.subplot(1, 2, 2)
# This will delete ax / ax1 as they fully overlap
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least one should be kept and the warning captured.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

ax3 = plt.subplot(1, 2, 1, projection='polar')
with pytest.warns(MatplotlibDeprecationWarning):
ax3 = plt.subplot(1, 2, 1, projection='polar')
ax4 = plt.subplot(1, 2, 1, projection='polar')
assert ax is not None
assert ax1 is ax
Expand All @@ -228,6 +228,7 @@ def test_subplot_kwarg_collision():
ax1 = plt.subplot(projection='polar', theta_offset=0)
ax2 = plt.subplot(projection='polar', theta_offset=0)
assert ax1 is ax2
ax1.remove()
ax3 = plt.subplot(projection='polar', theta_offset=1)
assert ax1 is not ax3
assert ax1 not in plt.gcf().axes
Expand Down Expand Up @@ -274,13 +275,16 @@ def test_subplot_projection_reuse():
assert ax1 is plt.gca()
# make sure we get it back if we ask again
assert ax1 is plt.subplot(111)
# remove it
ax1.remove()
# create a polar plot
ax2 = plt.subplot(111, projection='polar')
assert ax2 is plt.gca()
# this should have deleted the first axes
assert ax1 not in plt.gcf().axes
# assert we get it back if no extra parameters passed
assert ax2 is plt.subplot(111)
ax2.remove()
# now check explicitly setting the projection to rectilinear
# makes a new axes
ax3 = plt.subplot(111, projection='rectilinear')
Expand All @@ -302,15 +306,19 @@ def test_subplot_polar_normalization():


def test_subplot_change_projection():
created_axes = set()
ax = plt.subplot()
created_axes.add(ax)
projections = ('aitoff', 'hammer', 'lambert', 'mollweide',
'polar', 'rectilinear', '3d')
for proj in projections:
ax_next = plt.subplot(projection=proj)
assert ax_next is plt.subplot()
assert ax_next.name == proj
assert ax is not ax_next
ax = ax_next
ax.remove()
ax = plt.subplot(projection=proj)
assert ax is plt.subplot()
assert ax.name == proj
created_axes.add(ax)
# Check that each call created a new Axes.
assert len(created_axes) == 1 + len(projections)


def test_polar_second_call():
Expand Down