-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[ENH]: Make savefig close plot by default #29782
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
Comments
I guess there's the use case where someone wants to save a plot, make some changes to it, and save it again? My two cents are that the complexity of changing the behavour here and introducing a new argument for |
... or closing via the window manager, given this is clearly aimed at interactive use. For certain I would be against this as the default - I'm not aware of any program that closes a document when you print it. |
I agree with @jklymak's argument and would strongly oppose that change. |
I'm not clear about this. @acampove do you show the figure at all? I can see a typical use case for just saving figures. While you nowadays don't have to go through pyplot for that, it's quite a long way from a standard on screen
to saving that figure without having to care about closing
One issue with Maybe we have to think broader. One issue is the different responsibilities of pyplot. It can be used as the state-based functional interface, where figure tracking and explicit close are needed. But it's also the entry point to our object based API, and there tracking and closing is a nuisance. With the mpl-gui concept we are trying to separate these, but that's focused around event loop and window management. While there's the Would it be an idea to opt out of pyplot figure tracking like Or - wilder thoughts:
|
I think it would be useful to have more information about the use-case. Possibly it is something like import matplotlib.pyplot as plt
plt.plot(my_data)
plt.savefig(...)
plt.plot(my_other_data)
plt.savefig(...) # why are both sets of data showing in the second file? To solve this, you either need to explicitly close the first figure that you didn't explicitly create, or you need to explicitly create the second figure. If the use-case is something like this, then I doubt that building more options into @acampove can you say more about your use-case and how you got here? |
Thank you for your replies. Yes, my usecase is me making multiple plots the way you show them. I have to always use the line: plt.savefig(...)
plt.close() which seems unnecessary, given that I do not use that plot after I save it anyway. I never use Cheers. |
OK, but the solution to this is to make separate figures: If you are worried about too many figures being open, then yes you need to close the figures. There is zero chance in my mind that Doing this as an option: If I had this annoyance, I would just do def my_print(fname):
plt.savefig(fname);
plt.close() and store that in a local package that I install via pip. |
If you never do from matplotilb.figure import Figure
fig = Figure()
ax = fig.subplots()
ax.plot()
# and other plotting
fig.savefig() If you do this in a function then the The problem is the global state that exists to make working interactively in a shell nice is getting in your way. I think it is better to just not use the global state rather then add epicycles to it to. [edited: fixed a typo noted by @jklymak ] |
@tacaswell I think you mean BTW, aside from the massive change to the docs, is there anything holding up mpl_gui? |
🤦🏻 fixed the typo. mpl_gui is held up on docs and then consensus that it makes sense / feel good to use. |
Do we have anything in the docs recommending this? It is news to me and I consider myself more informed than many users... |
We have at least https://matplotlib.org/stable/gallery/user_interfaces/web_application_server_sgskip.html Describing the pattern. But granted it's in a narrower context. And the FAQ primarily recommends pyplot https://matplotlib.org/stable/users/faq.html#generate-images-without-having-a-window-appear 😐 |
❗ From an API / design standpoint I find the proposal fundamentally reasonable Considering a typical lifecycle, you (1) create a figure, (2) add content and (3) output it. When outputting on screen ( Note the behavioral asymmetry between In [3]: plt.figure(1)
Out[3]: <Figure size 640x480 with 0 Axes>
In [4]: plt.get_fignums()
Out[4]: [1]
In [5]: plt.show()
In [6]: plt.get_fignums() # figure is gone after show()
Out[6]: []
In [7]: plt.figure(2)
Out[7]: <Figure size 640x480 with 0 Axes>
In [8]: plt.savefig('test.png')
In [9]: plt.get_fignums() # figure remains after savefig()
Out[9]: [2] Can we migrate to deregistering after savefig by default in a reasonable way? I believe yes. We can flag a figure that has been savfig'ed and issue a warning if that figure is used in follow-up pyplot commands. This allows users to explictly |
I don't. Saving and closing a figure are fundamentally different operations. You don't expect ctrl-s on a word document to also close it. I guess if you really wanted it you could make plt.savefig() close the figure, but Figure.savefig() should certainly not (as this Axes/Figure methods has no reason to interact with the pyplot machinery). But that's not a divergence I look forward to explaining in the docs or in person.
That's definitely a wrong assumption for me: often I save a version of a figure, add more data or tweak some presentational aspect, and save another version.
On practical grounds, this would be breaking a lot of currently existing workflows. Perhaps what could be done is adding a |
Well, the problem is that the current state is a major footgun. If you use https://matplotlib.org/stable/users/faq.html#generate-images-without-having-a-window-appear, and e.g. do that in a loop, you collect a lot of memory. The correct solution currently would be to
Both are not ideal in that code for outputting a figure to screen or file must be structurally different. This divergence is not something I want to explain in docs or in person. "Simply use I agree on Fundamentally, why do we have the asymmetry that
could equally said with show instead of save. |
When I work interactively in |
I forgot that this works because in Jupyter notebook/lab the initial image doesn't update ( I think (b/c) it's a rendered png) when changes are made in subsequent cells. Which possibly is a tangential/inline_backend problem but I think related in terms of expectations.
it seems like what would be good here is being able to use the fig/axes creation methods as context managers, which I think is what mpl-gui is trying to facilitate? something like: with plt.subplots() as fig, ax:
ax....
plt.savefig() |
There's
show() doesn't deregister the figure, it's closing the figure (e.g. by pressing the cross button, or by pressing "q") which does it. I honestly don't understand what asymmetry you're talking about (regardless of what I think of this idea). |
Agreed. If I do `plt.show(block=False)`, no figure is closed by this
function. There is no asymmetry, and I think changing the default behavior
after almost 20 years could break a lot of scripts for no real gain.
Explicit is better than implicit.
I'm also against having an rc param for this. I can't think of another
rcParam where changing its value fundamentally alters the meaning of the
implied current figure/axes. That's not a plotting style adjustment, and it
could lead to incorrect results if it was mistakenly applied.
…On Fri, Mar 28, 2025 at 8:17 AM Antony Lee ***@***.***> wrote:
Well, the problem is that the current state is a major footgun. If you use
https://matplotlib.org/stable/users/faq.html#generate-images-without-having-a-window-appear,
and e.g. do that in a loop, you collect a lot of memory.
There's rcParams["figure.max_open_warning"] that checks on that.
Fundamentally, why do we have the asymmetry that show() deregisters the
figure in pyplot but savefig() does not? To me, both functions are
comparable.
show() doesn't deregister the figure, it's closing the figure (e.g. by
pressing the cross button, or by pressing "q") which does it. I honestly
don't understand what asymmetry you're talking about (regardless of what I
think of this idea).
—
Reply to this email directly, view it on GitHub
<#29782 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACHF6EEHFETLLVFLL3URHL2WUVVJAVCNFSM6AAAAABZNE75JKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONRRGE4TOMBQGU>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
[image: anntzer]*anntzer* left a comment (matplotlib/matplotlib#29782)
<#29782 (comment)>
Well, the problem is that the current state is a major footgun. If you use
https://matplotlib.org/stable/users/faq.html#generate-images-without-having-a-window-appear,
and e.g. do that in a loop, you collect a lot of memory.
There's rcParams["figure.max_open_warning"] that checks on that.
Fundamentally, why do we have the asymmetry that show() deregisters the
figure in pyplot but savefig() does not? To me, both functions are
comparable.
show() doesn't deregister the figure, it's closing the figure (e.g. by
pressing the cross button, or by pressing "q") which does it. I honestly
don't understand what asymmetry you're talking about (regardless of what I
think of this idea).
—
Reply to this email directly, view it on GitHub
<#29782 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACHF6EEHFETLLVFLL3URHL2WUVVJAVCNFSM6AAAAABZNE75JKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONRRGE4TOMBQGU>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Plotting has the general structure (1) create a figure, (2) add content and (3) output. Output can be in two flavors "on screen" and "to file". The output phase ends when Or to put the question the other way round: Why is |
Because show()ing the figure means that one can attach various callbacks to it that call other functions? Once a figure is shown, you can press "l" to toggle the axes scale, you can click on the zoom/pan buttons to tweak axes limits, you can press "s" to save the figure... and you can press "q" to close and deregister the figure. (You wouldn't want "s" to also close the figure, right?) |
IMHO that's beside the point: These are all actions during the output phase (which can be long in interactive mode). I'm talking what happens at the end of the the output phase. In particular, I think we must compare
|
FWIW I spend a lot of time in the ipython console, effectively in interactive mode.
Sure, hence the proposal of having divergent behaviours between plt.savefig and Figure.savefig. |
Ok, let's have a look at that. How is your workflow? Do you use |
I'm not aware of any program in wide use over the last 50 years that conflates saving a document to file with clearing the document from memory (eg closing the document). I'm curious to hear examples. I regularly save to file and continue to use the figure for subsequent saves in standalone scripts:
I imagine many other people do as well, and I feel that it would be very unexpected for the figure to close if it is saved unless I asked it to.
With I am also not a fan of a new rcParams to fit every idiosyncratic use of the library. We have an explicit way of closing the figure ( |
As a first step, can we agree that there's an asymmetry between
I regularly save to a file and be done with the figure. Both are valid use cases and will be supported either way. The question is which is the more common one and thus should be simpler, and on which one do we put the burden for explicitly handling the use case (i.e. explicitly stating that the figure should be dergistered from pyplot or not). |
Sure, because they are orthogonal things.
Typical in
I'm not sure what GUI you are using, but all the ones I use have a disk icon than allows me to call |
It's (effectively, because of course I do things weirdly...)
I can (and regularly do so, in fact), in interactive mode. |
Again, I am curious for examples where, by default, saving a file also clears it from memory. "Simpler" to me means doing what is expected, not necessarily what leads to less typing. |
They are just two variants of the last step of the basic workflow (i) create the figure (ii) add content (iii) output the result.
I'm not talking about any possible operations in the GUI. I generate a visual output of the figure (file or gui), after that I can continue on the command line, but in one case the figure is gone whereas in the other it's not. |
This discussion is seriously running in circles, but once again, the figure is gone in neither case for me (in interactive mode). |
I suspect that when working interactively saving (or showing) multiple times is a lot more common, because the first attempt is rarely exactly what you want. IIRC when my institution first moved to python for data analysis one of the most common questions was "how do I modify my plot after I suspect that when running a script saving once is more common, but if it only makes one figure then you don't care whether that figure got closed before the end of the script. If the script generates many figures it is not much burden to add |
Yes we are going in (different) circles. Again, I'm talking about the non-interactive behavior of pyplot, i.e. Let's make an example: In my experience, switching between for i in range(10):
plt.figure()
plt.plot(data[i])
plt.show() When done with developing, I want to save the figures to file rather than showing them. Why is it unreasonable to expect that I can replace |
In the concrete example you give, it means that show() blocks at every iteration, and you have to close the figure again and again to advance the loop, instead of being able to inspect all the figures at once and close("all") once done. Perhaps that's indeed your workflow, but I would suggest that just calling ion() (or activating interactive mode in some other way, e.g. via |
I'm in a script, I don't have
but that requires three lines change between I'd then rather have one window pop up at a time. Since the windows appear in the same spot, I only have to move the mouse to the close symbol once and then have a decently efficient -> loop. Is there a better way for this scenario? Well, I could simply always have the close in there becaue it doesn't have an effect after
but that's really not intuitive for people who are mostly coming from using |
If I'm in a script I would just put a single (blocking, noninteractive) show() at the end of the loop. If I really don't want all the figures to pop up together then show()ing them one at a time is indeed a solution, but I tend to quickly get away from that because this means you can't move backwards in the list of figures, which is often what I need, so I usually go towards more complex solutions like binding key_press_event to be able to switch datasets by pressing up/down. |
I'm still very much convinced that our story for when the the pyplot state is cleared or not is inconsistent. I can accept the argument "save" does not nce mean "I'm done with the figure", and deregistering the figure should be explicit. But then I'd also expect that closing a (blocking) figure window But I concede for now, even though I think the behavior is suboptimal. To the strong proponents of
|
Problem
I have to always do:
this seems unnecessary, given that 99% of the time I need the plot in order to save it, once it is saved, I do not need it anymore. Wouldn't it be a better idea to just close the plot automatically, maybe add an option
for those users who do not want it closed.
Proposed solution
No response
The text was updated successfully, but these errors were encountered: