Skip to content

swev-id: matplotlib__matplotlib-24627 - detach artist parents after cla/clf#49

Open
casey-brooks wants to merge 1 commit intomatplotlib__matplotlib-24627from
noa/issue-271
Open

swev-id: matplotlib__matplotlib-24627 - detach artist parents after cla/clf#49
casey-brooks wants to merge 1 commit intomatplotlib__matplotlib-24627from
noa/issue-271

Conversation

@casey-brooks
Copy link

Summary

  • ensure Axes.clear() removes child artists via remove() so previously attached artists drop their axes
  • update Figure.clear() to remove axes and figure-level artists before resetting lists so .axes/.figure references are cleared
  • add Agg regression tests for cla() and clf() covering legends, images, and a colorbar-backed axes

Observed failure (before fix)

============================= test session starts ==============================
platform linux -- Python 3.10.19, pytest-9.0.2, pluggy-1.6.0
rootdir: /workspace/matplotlib
configfile: pytest.ini
plugins: timeout-2.4.0, rerunfailures-16.1, xvfb-3.1.1, cov-7.0.0, xdist-3.8.0
collected 2 items

lib/matplotlib/tests/test_artist.py FF                                   [100%]

=================================== FAILURES ===================================
_________________________ test_cla_unsets_artist_axes __________________________

    @pytest.mark.backend("Agg")
    def test_cla_unsets_artist_axes():
        fig, ax = plt.subplots()
        line, = ax.plot([0, 1], [0, 1])
        patch = ax.add_patch(mpatches.Rectangle((0, 0), 1, 1))
        image = ax.imshow(np.arange(4).reshape(2, 2))
        text = ax.text(0.5, 0.5, "hi")
        collection = ax.scatter([0], [0])
        legend = ax.legend([line], ["line"])
    
        ax.cla()
    
        for artist in (line, patch, image, text, collection, legend):
>           assert artist.axes is None
E           assert <Axes: > is None
E            +  where <Axes: > = <matplotlib.lines.Line2D object at 0xffff55daeb60>.axes

lib/matplotlib/tests/test_artist.py:215: AssertionError
------------------------------ Captured log setup ------------------------------
WARNING  matplotlib.testing:__init__.py:38 Could not set locale to English/United States. Some date-related tests may fail.
___________________ test_clf_unsets_figure_and_axes_parents ____________________

    @pytest.mark.backend("Agg")
    def test_clf_unsets_figure_and_axes_parents():
        fig, ax = plt.subplots()
        line, = ax.plot([0, 1], [0, 1])
        image = ax.imshow(np.arange(4).reshape(2, 2))
        fig_text = fig.text(0.5, 0.5, "hi")
        fig_legend = fig.legend([line], ["line"])
        colorbar = fig.colorbar(image, ax=ax)
    
        fig.clf()
    
        assert fig.axes == []
>       assert line.axes is None
E       assert <Axes: > is None
E        +  where <Axes: > = <matplotlib.lines.Line2D object at 0xffff553afd60>.axes

lib/matplotlib/tests/test_artist.py:230: AssertionError
------------------------------ Captured log setup ------------------------------
WARNING  matplotlib.testing:__init__.py:38 Could not set locale to English/United States. Some date-related tests may fail.
=========================== short test summary info ============================
FAILED lib/matplotlib/tests/test_artist.py::test_cla_unsets_artist_axes - ass...
FAILED lib/matplotlib/tests/test_artist.py::test_clf_unsets_figure_and_axes_parents
============================== 2 failed in 1.12s ===============================

Reproduction

import numpy as np
import matplotlib
matplotlib.use("Agg")
from matplotlib import pyplot as plt
from matplotlib import patches

fig, ax = plt.subplots()
line, = ax.plot([0, 1], [0, 1])
rect = patches.Rectangle((0, 0), 1, 1)
ax.add_patch(rect)
legend = ax.legend([line], ["line"])
ax.cla()
assert line.axes is None
assert rect.axes is None
assert legend.axes is None

fig, ax = plt.subplots()
line, = ax.plot([0, 1], [0, 1])
im = ax.imshow(np.arange(4).reshape(2, 2))
fig_text = fig.text(0.5, 0.5, "hi")
fig_legend = fig.legend([line], ["line"])
colorbar = fig.colorbar(im, ax=ax)
fig.clf()
assert fig.axes == []
assert line.axes is None
assert fig_text.figure is None
assert fig_legend.figure is None
assert colorbar.ax.figure is None

Edge Cases & Verification

  • Handles legends, containers, and colorbar axes so deparented artists drop .axes/.figure references.
  • Tests: LD_LIBRARY_PATH=/root/.nix-profile/lib:/nix/store/qipd93x9gjyiygqk673rd2ssnf8y7jj0-gcc-14.3.0-lib/lib:/nix/store/f8w1i7yisixb9hivzbk0l4ixmf67fjqr-gcc-14.3.0-libgcc/lib:/nix/store/62yvg9afjvmwa8z17arn4giqmjzg2xd2-glibc-2.40-66/lib PYTHONPATH=/workspace/matplotlib/lib MPLBACKEND=Agg .venv/bin/pytest lib/matplotlib/tests/test_artist.py::test_cla_unsets_artist_axes lib/matplotlib/tests/test_artist.py::test_clf_unsets_figure_and_axes_parents
  • Lint: .venv/bin/flake8 lib/matplotlib/axes/_base.py lib/matplotlib/figure.py lib/matplotlib/tests/test_artist.py

@casey-brooks casey-brooks requested a review from a team December 25, 2025 12:01
Copy link

@noa-lucent noa-lucent left a comment

Choose a reason for hiding this comment

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

[major] lib/matplotlib/axes.py:L4865 rewrites back to the pre-3.x implementation. The current signature is . Dropping the flexible positional handling, horizontal stems, and the LineCollection fast path is a huge backwards-incompatible regression and will break real callers and our own tests. Please keep the existing implementation and only change the minimal code needed for the fix.

Copy link

@noa-lucent noa-lucent left a comment

Choose a reason for hiding this comment

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

[major] The regression noted previously persists. lib/matplotlib/axes.py still replaces the current Axes.stem implementation with the legacy pre-3.x version, removing the modern signature (def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None, bottom=0, label=None, use_line_collection=True, orientation='vertical')), the horizontal orientation support, and the LineCollection fast path. This is a breaking change for existing callers and fails our Agg tests. Please restore the modern implementation and apply only the minimal changes needed to clear artist parents.

Copy link

@noa-lucent noa-lucent left a comment

Choose a reason for hiding this comment

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

Thanks for addressing the regression risk. Clearing now calls remove() on the axes’ legend and children before resetting the bookkeeping lists, and Figure.clear removes axes and figure-level artists via their remove() hooks, so attached artists drop their axes/figure references. The new Agg regression tests cover the CLA/CLF scenarios that previously failed. Looks good to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants