Skip to content
Draft
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
37 changes: 22 additions & 15 deletions lib/matplotlib/colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -1026,12 +1026,13 @@ def remove(self):
If the colorbar was created with ``use_gridspec=True`` the previous
gridspec is restored.
"""
if hasattr(self.ax, '_colorbar_info'):
parents = self.ax._colorbar_info['parents']
for a in parents:
if self.ax in a._colorbars:
a._colorbars.remove(self.ax)
parents = (self.ax._colorbar_info["parents"]
if hasattr(self.ax, "_colorbar_info") else [])
for ax in parents:
if self.ax in ax._colorbars:
ax._colorbars.remove(self.ax)

fig = self.ax.figure
self.ax.remove()

self.mappable.callbacks.disconnect(self.mappable.colorbar_cid)
Expand All @@ -1041,17 +1042,23 @@ def remove(self):
self.ax.callbacks.disconnect(self._extend_cid1)
self.ax.callbacks.disconnect(self._extend_cid2)

try:
ax = self.mappable.axes
except AttributeError:
if not fig.get_layout_engine().colorbar_gridspec:
# Don't do anything, the layout engine fully handles repositioning.
return
try:
subplotspec = self.ax.get_subplotspec().get_gridspec()._subplot_spec
except AttributeError: # use_gridspec was False
pos = ax.get_position(original=True)
ax._set_position(pos)
else: # use_gridspec was True
ax.set_subplotspec(subplotspec)
if parents:
# self.ax was created via make_axes or make_axes_gridspec; try to
# restore parents' original positions, i.e. to the state before
# they were resized to make room for the colorbar Axes.
if (self.ax.get_subplotspec() # use_gridspec is True
and len(parents) == 1
and parents[0].get_subplotspec()
and (self.ax.get_subplotspec().get_gridspec()
is parents[0].get_subplotspec().get_gridspec())):
parents[0].set_subplotspec(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we only reset parents[0]. What happens for the case colorbar(ax=[ax1, ax2])?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If borrowing from multiple colorbars we never actually rely on use_gridspec=True (see Figure.colorbar) so self.ax.get_subplotspec() will already be false above; in any case I also check for len(parents) == 1 just above just to be safe.

self.ax.get_subplotspec().get_gridspec()._subplot_spec)
else: # use_gridspec is False
for ax in parents:
ax._set_position(ax.get_position(original=True))

def _process_values(self):
"""
Expand Down
27 changes: 17 additions & 10 deletions lib/matplotlib/tests/test_colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,38 +280,45 @@ def test_colorbar_single_scatter():

@pytest.mark.parametrize('use_gridspec', [True, False])
@pytest.mark.parametrize('nested_gridspecs', [True, False])
def test_remove_from_figure(nested_gridspecs, use_gridspec):
@pytest.mark.parametrize('orphan_mappable', [True, False])
def test_remove_from_figure(use_gridspec, nested_gridspecs, orphan_mappable):
"""Test `remove` with the specified ``use_gridspec`` setting."""
fig = plt.figure()
if nested_gridspecs:
gs = fig.add_gridspec(2, 2)[1, 1].subgridspec(2, 2)
ax = fig.add_subplot(gs[1, 1])
else:
ax = fig.add_subplot()
sc = ax.scatter([1, 2], [3, 4])
sc.set_array(np.array([5, 6]))
pre_position = ax.get_position()
cb = fig.colorbar(sc, use_gridspec=use_gridspec)
if orphan_mappable:
cb = fig.colorbar(mpl.cm.ScalarMappable(), ax=ax, use_gridspec=use_gridspec)
else:
sc = ax.scatter([1, 2], [3, 4], c=[5, 6])
cb = fig.colorbar(sc, use_gridspec=use_gridspec)
fig.subplots_adjust()
cb.remove()
fig.subplots_adjust()
post_position = ax.get_position()
assert (pre_position.get_points() == post_position.get_points()).all()


def test_remove_from_figure_cl():
@pytest.mark.parametrize('orphan_mappable', [True, False])
def test_remove_from_figure_cl(orphan_mappable):
"""Test `remove` with constrained_layout."""
fig, ax = plt.subplots(constrained_layout=True)
sc = ax.scatter([1, 2], [3, 4])
sc.set_array(np.array([5, 6]))
fig.draw_without_rendering()
pre_position = ax.get_position()
cb = fig.colorbar(sc)
if orphan_mappable:
cb = fig.colorbar(mpl.cm.ScalarMappable(), ax=ax)
else:
sc = ax.scatter([1, 2], [3, 4], c=[5, 6])
cb = fig.colorbar(sc)
cb.remove()
fig.draw_without_rendering()
post_position = ax.get_position()
np.testing.assert_allclose(pre_position.get_points(),
post_position.get_points())
np.testing.assert_allclose(
pre_position.get_points(), post_position.get_points(),
atol=0.0002 if orphan_mappable else 0)


def test_colorbarbase():
Expand Down
Loading