-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Simpler "pyplotless" use pattern. #14024
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
Conversation
Huh, as a somewhat knowledgeable user, I had zero idea that So, I think that we can go ahead and try to disassociate the GUI integration from pyplot, or we can just accept that some basic things get done in pyplot that have nothing to do w/ the |
The problem of |
Forgetting about our current concept of "block", I'd expect you could |
So effectively figure.show() would behave like plt.show(block=False), except that the process does not end at the end of the program? I guess that can work, too. |
Thats how I'd expect a GUI to behave, but no doubt I'm missing a subtlety somewhere... |
Would
be showing fig1 as well? |
Whether a call to |
I think we should in general prepare for a way to reshow closed pyplot figures. This is currently one of the most annoying restrictions users face, i.e.
[*] "No way" in the sense of......you don't want to do this:
|
I’m not understanding the situation where the user expects a figure to be able to be reopened. If I click the little red x I expect whatever was there to disappear. You could argue that it could prompt to save but otherwise? |
Sure, you could register a callback to a |
By "save", I meant saving as an image. I'm 👎 on saving figures so they can be resurrected as an interactive thing later. At the most practical, such figures won't survive changes of matplotlib versions if any internal organization of the objects has changed. Pickle, itself, became incompatible between py2.x and py3.x (I'll never willingly use pickle again). Overall it just seems like a lot of hassle. And why? Users should be able to re-create the figure from their script and not rely on manual fiddling with the GUI or a bunch of manual typing in the REPL. I admit this is not a universal opinion, but I think having figures that robustly resurrect themselves is really hard from a developers perspective, and not a good idea from the user's perspective. |
Matplotlib supports pickling of figures just fine (of course in- and output versions must be the same!) and there is a bunch of tests for that, so this is an existing feature, not for debate here. I only mentionned it as workaround for reshowing a figure. And I mentionned the desire for reshowing a figure here, because I think it needs to be taken into account when designing |
@ImportanceOfBeingErnest re-show()ing a figure basically just works with this PR. |
I see. I was missing the fact that apparently closed figures keep their manager. But that wouldn't be the case for a pickled figure, right? This is what happens
gives
Not sure if it should work though. |
A manager is (holding) a GUI widget, so it's going to be tricky to pickle :p matplotlib/lib/matplotlib/figure.py Line 2008 in db5fb66
matplotlib/lib/matplotlib/figure.py Line 2037 in db5fb66
Probably just a matter of replacing restore_to_pylab by a tristate for the behavior on unpickling:
but this can clearly be done separately from (after?) this PR. |
Yes pickling is again a bad example, I suppose. Let's just take
which will also not have a manager. If that is expected, maybe a better error message should tell people exactly which figures they can show this way. |
That should just be a matter of calling |
""" | ||
Show all figures. | ||
|
||
`show` blocks by calling `mainloop` if *block* is ``True``, or if it | ||
is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in | ||
`interactive` mode. | ||
""" | ||
managers = Gcf.get_all_fig_managers() | ||
managers = ([figure.canvas.manager for figure in figures] |
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.
This should be more forgiving to canvases without managers?
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.
I don't think ignoring (silently or not) figures we can't show because they have no manager is really helpful?
One idea would be to auto-setup a manager for them, though.
I am 👍 on this. |
Semi OT: While I see the reason behind this approach, |
The problem of |
Right now, if one does not want to use pyplot (e.g., batch use), one can do from matplotlib.figure import Figure fig = Figure(); ... <plot> ...; fig.savefig(...) but it is impossible to show() the figure interactively (i.e. pyplot cannot "adopt" the figure) e.g. for debugging. This patch makes it possible: with it, one can do fig = plt.new_figure_manager(num).canvas.figure ... <plot> ... fig.savefig() plt.show(figures=[fig]) Note that this does *not* register the figure with pyplot; in particular *fig* is garbage-collected when it goes out of scope, does not participate in gcf(); etc. So this is "pyplotless" in the sense that there is no global figure registry anymore, but pyplot still stays in charge of the GUI integration. Obviously the `plt.new_figure_manager(num).canvas.figure` expression could / should be encapsulated in a helper function, up to bikeshedding. The `num` parameter is needed as matplotlib currently uses it to set the figure title, but that can easily be made optional too. Finally note that `plt.show([fig])` would be a nicer API, but right now the first parameter to plt.show is `block`, which is undergoing transition to kwonly. IOW the end-goal would be e.g. # intentionally terrible name as placeholder :) fig = plt.new_figure_not_globally_registered("some title") ... <plot> ... fig.savefig() plt.show([fig])
I know it's not that simple :sad:. |
Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you need a review or guidance to move the PR forward! If you do not plan on continuing the work, please let us know so that we can either find someone to take the PR over, or close it. |
Mplgui basically solves this issue. Now we just need a path to merging it! |
Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you need a review or guidance to move the PR forward! If you do not plan on continuing the work, please let us know so that we can either find someone to take the PR over, or close it. |
This is basically tracked by the mplgui work. |
cf. mailing list discussion on garbage collection.
Right now, if one does not want to use pyplot (e.g., batch use), one can
do
but it is impossible to show() the figure interactively (i.e. pyplot
cannot "adopt" the figure) e.g. for debugging.
This patch makes it possible: with it, one can do
Note that this does not register the figure with pyplot; in particular
fig is garbage-collected when it goes out of scope, does not
participate in gcf(); etc. So this is "pyplotless" in the sense that
there is no global figure registry anymore, but pyplot still stays in
charge of the GUI integration.
Obviously the
plt.new_figure_manager(num).canvas.figure
expressioncould / should be encapsulated in a helper function, up to bikeshedding.
The
num
parameter is needed as matplotlib currently uses it to set thefigure title, but that can easily be made optional too.
Finally note that
plt.show([fig])
would be a nicer API, but right nowthe first parameter to plt.show is
block
, which is undergoingtransition to kwonly.
IOW the end-goal would be e.g.
some more thoughts:
While this "logically" belongs to pyplot in the sense that pyplot is in charge of the GUI integration, this doesn't actually interact with any of the pyplot plotting functions that operate on gcf()/gca(), so perhaps it may be better (to avoid user confusion) to have a separate submodule just hosting
new_figure_not_globally_registered
andshow
(in which case the latter could have the "better" APIshow([fig], *, block=False)
immediately).Currently the
num
argument to new_figure_manager needs to be an int, but note that plt.figure() supports both int and string and the logic to support both can easily be pushed down to new_figure_manager... but preferably after merging #13569 and #13581.PR Summary
PR Checklist