Skip to content

Use plot title as default filename for "Download plot" button#7828

Open
emilykl wants to merge 6 commits into
v4.0from
5124-feature
Open

Use plot title as default filename for "Download plot" button#7828
emilykl wants to merge 6 commits into
v4.0from
5124-feature

Conversation

@emilykl

@emilykl emilykl commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Addresses #5124

  • Use layout.title.text as default download filename when neither config.toImageButtonOptions.filename or gd.fn are defined.
    • "slugify" title by lowercasing, removing HTML tags, removing some special characters, and replacing whitespace with hyphens
    • Ignore MathJax titles entirely, to avoid generating horrible filenames like ihbarfracdpsidt=-v-frac-hbar^22mnabla^2p.png
    • Add helper function to get title from _fullLayout (so that template values are respected) while ignoring the "Click to add title" placeholder
  • Change fallback filename to plot-image rather than newplot
  • Change notifier wording for image download slightly, to better match button tooltip (remove references to "snapshot")
  • Add/modify tests for the above

Steps for testing

  1. Pull this branch and run devtools (npm run start)
  2. Load any plot in the devtools
  3. Click the "Download plot as PNG" button (camera icon) and verify that the downloaded plot filename corresponds to the plot title
  4. Repeat for several more plots, including the below:
    a. scatter_marker_line_dash (normal example, filename should match)
    b. bar-like_traces_tozero (title is defined in template, filename should match)
    c. automargin-small-width (no title, should default to plot-image.png)
    d. mathjax (MathJax title, should default to plot-image.png)

@emilykl emilykl requested a review from camdecoster June 8, 2026 21:15
@archmoj

archmoj commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Nice!
What's the expected behavior when title.text is set to a dot?

Plotly.newPlot(gd, [{y: [1, 2]}], {title: {text: "."}});

Right now it returns png.png!

Comment thread src/snapshot/download.js
// so ignore the title entirely if it contains LaTeX markup
if (!svgTextUtils.matchTex(plotTitle)) {
potentialFilename = Lib.slugify(plotTitle, 40);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You may also consider adding the subtitle.text if present.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm open to that, but I'm having trouble thinking of a real-world example where adding the subtitle would result in a better filename.

I suppose maybe in the case where you have multiple plots with the same title but different subtitles, that could differentiate the filenames.

Do you have any particular examples in mind?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here is a common example where subtitle could be used to provide the time stamp of the graph.

Plotly.newPlot(gd, [{y: [1, 2]}], {title: {text: "Hourly Temp. (°C) Forecast - Montréal", subtitle: {text: "9 June 2026"}}});

@emilykl

emilykl commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Nice! What's the expected behavior when title.text is set to a dot?

Plotly.newPlot(gd, [{y: [1, 2]}], {title: {text: "."}});

Right now it returns png.png!

Good catch!! That's a wild edge case, I guess I would have expected it to return ..png, which also isn't a good outcome.

I suppose . should either be treated the same as whitespace characters, or simply removed, I'll make that change.

@emilykl

emilykl commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Nice! What's the expected behavior when title.text is set to a dot?

Plotly.newPlot(gd, [{y: [1, 2]}], {title: {text: "."}});

Right now it returns png.png!

Good catch!! That's a wild edge case, I guess I would have expected it to return ..png, which also isn't a good outcome.

I suppose . should either be treated the same as whitespace characters, or simply removed, I'll make that change.

@archmoj Updated — I added . to the list of forbidden characters, so it will be removed, and therefore a plot with the title . results in a download named `plot-image.png.

Comment thread src/lib/slugify.js
// precompile for speed
var HTML_TAGS_REGEX = /<[^>]*>/g; // anything contained in < > tags
var FORBIDDEN_CHARS_REGEX = /[\\/:*?"<>|$`'(){}[\],]/g; // Characters in the set: \/:*?"<>|$`'(){}[],
var FORBIDDEN_CHARS_REGEX = /[\\/:*?"<>|$%&!@#~.^`'(){}[\],]/g; // Characters in the set: \/:*?"<>|$%&!@#~.^`'(){}[],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How about equal sign?

the equal sign ( = ) is classified as a forbidden character in filenames across several operating systems (like MS-DOS) and is strongly discouraged on modern systems like Windows.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also + and ; could/should be added to the list.

Comment thread src/lib/slugify.js
.replace(UNICODE_REPLACEMENT_CHAR_REGEX, '') // Drop Unicode replacement chars left by previous step
.replace(HTML_TAGS_REGEX, ' ') // Remove < > tags, such as <br> (replace with space)
.replace(FORBIDDEN_CHARS_REGEX, '') // Remove forbidden filename characters
.toLowerCase() // Lowercase everything

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure about lowering the case.

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