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

Skip to content

[ENH]: pre-set file name for GUI save dialog in rcParams #27774

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
FilipDominec opened this issue Feb 12, 2024 · 15 comments · Fixed by #27776
Closed

[ENH]: pre-set file name for GUI save dialog in rcParams #27774

FilipDominec opened this issue Feb 12, 2024 · 15 comments · Fixed by #27776
Labels
Community support Users in need of help.

Comments

@FilipDominec
Copy link

FilipDominec commented Feb 12, 2024

Problem

While there is an obvious way to specify the output image format as well as directory where GUI suggests to export your interactive plot, like this:

 matplotlib.rcParams["savefig.format"] = "pdf"
 matplotlib.rcParams["savefig.directory"] = ...

there is no easy way to suggest the file base name, and it always defaults to practically useless "Figure_1" or so.

Rationale 1: I often process & plot a lot of scientific datasets with long names that encode a bunch of useful parameters. My scripts would therefore save me significant amount of time if e.g. for "abcd123.dat" they suggested to export into "abcd123.*".

Rationale 2: One old question about this can be found on SO (https://stackoverflow.com/questions/41680007/how-to-change-default-filename-from-matplotlib-navigationtoolbar-in-a-pyqt5-appl) and the proposed solution requires monkey-patching Matplotlib functions - which is ugly, tedious and most importantly, the suggested code did not work anymore.

Proposed solution

Let's allow users to change the filename too, allowing one to simply set:

 matplotlib.rcParams["savefig.basename"] = ...
@FilipDominec
Copy link
Author

FilipDominec commented Feb 12, 2024

A related enhancement would be to add support for something like

matplotlib.rcParams["tk.window_title"]

as currently the window gets named as "Figure 1" and changing it requires further hacking. Both described settings should really be one-liners.

This both looks fairly easy to accomplish. With your approval, I can try making a PR.

@FilipDominec FilipDominec changed the title [ENH]: [ENH]: pre-set file name for GUI save dialog in rcParams Feb 12, 2024
@FilipDominec
Copy link
Author

FilipDominec commented Feb 12, 2024

Returning to the aforementioned Stack Overflow link, I found out that this one line will set suggested filename:

fig.canvas.get_default_filename = lambda: 'new_default_name.png'

Yet it is not really systematic from programmer's point of view, so I still believe RC params should better do the job.

@rcomer
Copy link
Member

rcomer commented Feb 12, 2024

It looks like one option is

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

ax.plot([0, 1])

fig.canvas.manager.set_window_title('foo')

plt.show()

(tested with Matplotlib v3.8.2 and QtAgg).

I think it would be odd to have an rcParam for this because usually rcParams are things you want to have the same across multiple figures (and defaults are set in the matplotlibrc file). For file names you presumably want a different setting for each figure.

@timhoffm
Copy link
Member

timhoffm commented Feb 12, 2024

I'm do for fully understand you use case. Questions/comments:

  • You save a lot through the GUI save dialog? Even with a better suggested file name that's quite cumbersome. Can't you simply fig.savefig(filename) from your script?

  • IMHO a rcParam is not suitable for a figure filename. RcParams are global, but you'll want a figure-specific filename most of the time. It dosn't really help to be able to change the default filename to another constant like "my_plot.png"

  • you said

    for "abcd123.dat" they suggested to export into "abcd123.*".

    We cannot do this fully automatic. Matplotlib does not know where your data comes from. You would have to supply the name to Matplotlib. E.g. directly through savefig() or via the window title (see comment by @rcomer above), which gets used as filename suggestion.

@FilipDominec
Copy link
Author

Thank you both for your quick answers!

So apparently there exist solutions for both my problems, although these have rather to be searched in the object model of Matplotlib and not in its RC params.

I must admit I don't find such a structure very user friendly, but let's consider this topic settled.

@timhoffm: you are right that for many files one should use non-interactive processing with savefig(), but I am developing cross-platform tools for a scientfic team and I want my colleagues to have full control over how and where the file gets exported.

@timhoffm
Copy link
Member

I must admit I don't find such a structure very user friendly, but let's consider this topic settled.

This is through separation of concerns. The figure is a logical entity, the canvas is a backend specific rendering entity, e.g. a pixel buffer of your GUI framework. The manager is the controller if you want us to pop up a window Vito the canvas for you. So window information is naturally connected to the manager. But I agree, we could make this more discoverable. - and be it only by adding an example to https://matplotlib.org/devdocs/api/backend_bases_api.html#matplotlib.backend_bases.FigureManagerBase.set_window_title.

but I am developing cross-platform tools for a scientfic team and I want my colleagues to have full control over how and where the file gets exported.

If you anticipate, that your users need to save a lot, you may consider creating you own window in the gui framework of your choice, and embedding a Matplotlib figure into this. This would allow you to place a line edit with the suggested filename and a "save" button right next to the plot. (You'd wire the save button to call savefig with the name from the line edit.) That way, your users have full control, but saving with a default name is only a single click for them.

@FilipDominec
Copy link
Author

Thank you all. Today I finished the small application based on matplotlib's interactive figure https://github.com/FilipDominec/FZU14_Raman_maps, so anybody wanting some inspiration can simply copy the working code from there.

@anntzer
Copy link
Contributor

anntzer commented Feb 12, 2024

FWIW I've have had a def set_default_filename(fig, name) helper essentially implemented as in #27774 (comment) (with extra handling for the default directory and extension) since a long time ago in my utils.py.

@FilipDominec
Copy link
Author

@anntzer I would be certainly interested in learning some tricks from your utils.py.

@rcomer rcomer added Community support Users in need of help. and removed New feature labels Feb 12, 2024
@anntzer
Copy link
Contributor

anntzer commented Feb 12, 2024

The actual implementation of my helper is

def set_default_filename(fig, name):
    """Set the default filename when saving a figure to an image."""
    name = Path(name)

    def get_default_filename():
        old_default = Path(type(fig.canvas).get_default_filename(fig.canvas))
        return str(old_default.parent /
                   name.with_suffix(name.suffix or old_default.suffix))

    fig.canvas.get_default_filename = get_default_filename

which, as mentioned above, specifically takes care of the default directory and extension as well (both when name specifies an extension and when it doesn't).

@timhoffm
Copy link
Member

timhoffm commented Feb 12, 2024

@anntzer since you seem to adapt the default filename as well: Would you say, it's reasonable to add a more direct way to set the default name? I.e. most simply add an attribute that get_default_filename() checks first before inferring a name.

@anntzer
Copy link
Contributor

anntzer commented Feb 12, 2024

Sure, I guess that would be nice, in the sense that at least two users could have made use of that? Ideally, the user should be able to set just a filename or an absolute path (overriding savefig.directory... I guess all relative paths should be relative to savefig.directory), and include an extension or not.

@timhoffm
Copy link
Member

Agreed. I assume an attribute Canvas.default_filename (default None) and a bit of logic in Canvas.get_default_filename() should do the trick.

Since you're a user, do you want to bring in a PR? 😀

@anntzer
Copy link
Contributor

anntzer commented Feb 13, 2024

no :) as usual, the suggested implementation above is freely donated to whoever wants to PR it.

@timhoffm
Copy link
Member

It's not important enough to me to pick this up, but if somebody is interested, #27774 (comment) is a reasonable extension and we would accept a PR.

Impaler343 pushed a commit to Impaler343/matplotlib that referenced this issue Mar 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Community support Users in need of help.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants