Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug]: subfigure artists not drawn interactively #28384

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

Closed
rcomer opened this issue Jun 12, 2024 · 7 comments · Fixed by #28397
Closed

[Bug]: subfigure artists not drawn interactively #28384

rcomer opened this issue Jun 12, 2024 · 7 comments · Fixed by #28397
Labels
Milestone

Comments

@rcomer
Copy link
Member

rcomer commented Jun 12, 2024

Bug summary

When artists are added to a subfigure in interactive mode, they do not appear until I force a draw by resizing the window.

Code for reproduction

$ ipython --matplotlib=qt
Python 3.12.3 | packaged by conda-forge | (main, Apr 15 2024, 18:38:13) [GCC 12.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.24.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import matplotlib.pyplot as plt

In [2]: fig = plt.figure()

In [3]: sfig1, sfig2 = fig.subfigures(ncols=2)

In [4]: sfig2.suptitle("My Title")
Out[4]: Text(0.5, 0.98, 'My Title')

In [5]: ax = sfig1.subplots()

In [6]: ax.plot([1, 3, 2])
Out[6]: [<matplotlib.lines.Line2D at 0x73a220908ce0>]

Actual outcome

Apparently empty figure
image

Expected outcome

If I resize the window, the artists appear
image

Additional information

No response

Operating system

Ubuntu

Matplotlib Version

main

Matplotlib Backend

QtAgg and TkAgg

Python version

3.12.3

Jupyter version

No response

Installation

git checkout

@tacaswell
Copy link
Member

Very likely the issue is that obj.stale is not propogating up from the sub-figure to the parent.

@jklymak
Copy link
Member

jklymak commented Jun 12, 2024

Huh. I never use interactive mode so didn't test that! Seems a pretty big oversight. Thanks for finding.

@tacaswell
Copy link
Member

diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py
index 9139b2ed26..9f764cc233 100644
--- a/lib/matplotlib/figure.py
+++ b/lib/matplotlib/figure.py
@@ -1636,6 +1636,8 @@ default: %(va)s
         sf = SubFigure(self, subplotspec, **kwargs)
         self.subfigs += [sf]
         sf._remove_method = self.subfigs.remove
+        sf.stale_callback = _stale_figure_callback
+        self.stale = True
         return sf
 
     def sca(self, a):

is the fix. I don't have time right now to add a test etc. I'll try to get to it later today but will not be at all angry if someone takes over.

@tacaswell tacaswell added this to the v3.9.1 milestone Jun 13, 2024
@tacaswell tacaswell added the status: has patch patch suggested, PR still needed label Jun 13, 2024
@rcomer
Copy link
Member Author

rcomer commented Jun 14, 2024

@tacaswell does it matter that that callback will currently only set the root figure to stale and not any intermediate subfigures when they are nested?

If it does matter, we can just wait for #28177 and then update the callback to work on self.get_figure(root=False).

@rcomer
Copy link
Member Author

rcomer commented Jun 14, 2024

Full disclosure: this is how far I got
main...rcomer:matplotlib:subfigure-stale

Currently the last line of the test fails. I tried and failed to create an example to show that this matters.

Sorry, I probably should have commented right after I did this to avoid duplicating effort.

@tacaswell
Copy link
Member

Ah, no worries. I was feeling guilty that my initial comment had too little detail and I was wasting your time digging!

I think waiting for #28177 to land might make sense, but it is not critical as either way, the thing that triggers the automatic re-rendering is the stale state of the top-level figure (via

def draw_all(cls, force=False):
"""
Redraw all stale managed figures, or, if *force* is True, all managed
figures.
"""
for manager in cls.get_all_fig_managers():
if force or manager.canvas.figure.stale:
manager.canvas.draw_idle()
which is called either via
ip.events.register("post_execute", _draw_all_if_interactive)
after executing a cell/line in IPython or
if _REPL_DISPLAYHOOK is _ReplDisplayHook.PLAIN:
fig.stale_callback = _auto_draw_if_interactive
in plain Python)

@rcomer
Copy link
Member Author

rcomer commented Jun 14, 2024

Thanks @tacaswell! So, when the top Figure is re-drawn, does it re-draw all the artists on it, or just those ones that are currently marked "stale"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants