Skip to content

Commit 7a283af

Browse files
Add SVG export button to Plotly modebar
Agent-Logs-Url: https://github.com/dandi/access-page/sessions/f5e6bf53-17ce-494e-88dd-b2eef852ebe1 Co-authored-by: CodyCBakerPhD <51133164+CodyCBakerPhD@users.noreply.github.com>
1 parent a1e064d commit 7a283af

1 file changed

Lines changed: 27 additions & 7 deletions

File tree

src/plots.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,26 @@ function applyTheme(layout) {
5757
return layout;
5858
}
5959

60+
// ── Shared Plotly config ─────────────────────────────────────────────────────
61+
// Adds a "Download as SVG" button to every plot's modebar alongside the
62+
// default "Download plot as a png" camera button.
63+
const PLOTLY_CONFIG = {
64+
modeBarButtonsToAdd: [
65+
{
66+
name: 'Download plot as SVG',
67+
icon: {
68+
// Simple download-arrow icon (Material Design "file_download")
69+
width: 24,
70+
height: 24,
71+
path: 'M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z',
72+
},
73+
click: function (gd) {
74+
Plotly.downloadImage(gd, { format: 'svg', filename: gd.id || 'dandi-plot' });
75+
},
76+
},
77+
],
78+
};
79+
6080
/**
6181
* Reads the saved theme preference from localStorage (defaulting to dark),
6282
* applies it to the <html> element and updates IS_DARK_MODE.
@@ -1238,7 +1258,7 @@ function load_over_time_plot(dandiset_id) {
12381258
layout.title.text = "Usage per week";
12391259
}
12401260

1241-
Plotly.newPlot(plot_element_id, plot_info, layout);
1261+
Plotly.newPlot(plot_element_id, plot_info, layout, PLOTLY_CONFIG);
12421262
attach_legend_tooltips(plot_element_id, ASSET_TYPE_DESCRIPTIONS);
12431263

12441264
// Table: show total bytes per time bin (sum across all asset types)
@@ -1366,7 +1386,7 @@ function load_over_time_plot(dandiset_id) {
13661386
layout.barmode = "stack";
13671387
layout.legend = { title: { text: "Dandiset" } };
13681388

1369-
Plotly.newPlot(plot_element_id, plot_info, layout);
1389+
Plotly.newPlot(plot_element_id, plot_info, layout, PLOTLY_CONFIG);
13701390

13711391
// Render archive table view even in grouped mode
13721392
const per_bin_titles = {
@@ -1459,7 +1479,7 @@ function load_over_time_plot(dandiset_id) {
14591479

14601480
const layout = build_over_time_layout(dates);
14611481

1462-
Plotly.newPlot(plot_element_id, plot_info, layout);
1482+
Plotly.newPlot(plot_element_id, plot_info, layout, PLOTLY_CONFIG);
14631483

14641484
// Render table view (sortable by column header click; default: bytes descending)
14651485
const date_col_labels = {
@@ -1580,7 +1600,7 @@ function load_dandiset_histogram() {
15801600
},
15811601
});
15821602

1583-
Plotly.newPlot(plot_element_id, plot_data, layout);
1603+
Plotly.newPlot(plot_element_id, plot_data, layout, PLOTLY_CONFIG);
15841604

15851605
// Render table view (sortable by column header click; default: bytes descending)
15861606
render_sortable_table("histogram_table", "", [
@@ -1667,7 +1687,7 @@ function load_per_asset_histogram(by_asset_summary_tsv_url) {
16671687
},
16681688
});
16691689

1670-
Plotly.newPlot(plot_element_id, plot_data, layout);
1690+
Plotly.newPlot(plot_element_id, plot_data, layout, PLOTLY_CONFIG);
16711691

16721692
// Render table view (sortable by column header click; default: bytes descending)
16731693
render_sortable_table("histogram_table", "Usage per asset", [
@@ -2038,7 +2058,7 @@ function load_geographic_heatmap(dandiset_id) {
20382058
},
20392059
});
20402060

2041-
Plotly.newPlot(plot_element_id, plot_info, layout);
2061+
Plotly.newPlot(plot_element_id, plot_info, layout, PLOTLY_CONFIG);
20422062
})
20432063
.catch((error) => {
20442064
console.error("Error:", error);
@@ -2205,7 +2225,7 @@ function load_geographic_choropleth(dandiset_id, plot_element_id, by_region_summ
22052225
],
22062226
});
22072227

2208-
Plotly.newPlot(plot_element_id, plot_info, layout).then(() => {
2228+
Plotly.newPlot(plot_element_id, plot_info, layout, PLOTLY_CONFIG).then(() => {
22092229
const el = document.getElementById(plot_element_id);
22102230
if (el && el._fullLayout && el._fullLayout.map && el._fullLayout.map._subplot) {
22112231
const map = el._fullLayout.map._subplot.map;

0 commit comments

Comments
 (0)