From 42c9601d8456fe73c82ecad8afd4897a130868e6 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:18:27 -0400 Subject: [PATCH 1/4] add button placeholder which shows chart JSON --- src/components/modebar/buttons.js | 10 ++++++++++ src/components/modebar/manage.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index a67fd18b0f0..413c0824b46 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -85,6 +85,16 @@ modeBarButtons.editInChartStudio = { } }; +modeBarButtons.uploadToCloud = { + name: 'uploadToCloud', + title: function(gd) { return _(gd, 'Upload to Cloud'); }, + icon: Icons.disk, + click: function(gd) { + var fig = Plots.graphJson(gd, false, 'keepdata', 'object', true, true); + alert(JSON.stringify(fig, null, 2)); + } +}; + modeBarButtons.zoom2d = { name: 'zoom2d', _cat: 'zoom', diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 3c9a4626192..d6b485be428 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -144,7 +144,7 @@ function getButtonGroups(gd) { } // buttons common to all plot types - var commonGroup = ['toImage']; + var commonGroup = ['toImage', 'uploadToCloud']; if(context.showEditInChartStudio) commonGroup.push('editInChartStudio'); else if(context.showSendToCloud) commonGroup.push('sendDataToCloud'); addGroup(commonGroup); From 8ce55121a3f1c80726c65d6daf38bb250bb93e59 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Mon, 11 May 2026 14:00:13 -0400 Subject: [PATCH 2/4] add icon --- src/components/modebar/buttons.js | 8 +++----- src/components/modebar/cloud.js | 11 +++++++++++ src/fonts/ploticon.js | 6 ++++++ 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 src/components/modebar/cloud.js diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index 413c0824b46..c6b44f088b8 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -4,6 +4,7 @@ var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var axisIds = require('../../plots/cartesian/axis_ids'); var Icons = require('../../fonts/ploticon'); +var uploadToCloud = require('./cloud').uploadToCloud; var eraseActiveShape = require('../shapes/draw').eraseActiveShape; var Lib = require('../../lib'); var _ = Lib._; @@ -88,11 +89,8 @@ modeBarButtons.editInChartStudio = { modeBarButtons.uploadToCloud = { name: 'uploadToCloud', title: function(gd) { return _(gd, 'Upload to Cloud'); }, - icon: Icons.disk, - click: function(gd) { - var fig = Plots.graphJson(gd, false, 'keepdata', 'object', true, true); - alert(JSON.stringify(fig, null, 2)); - } + icon: Icons.cloudupload, + click: uploadToCloud, }; modeBarButtons.zoom2d = { diff --git a/src/components/modebar/cloud.js b/src/components/modebar/cloud.js new file mode 100644 index 00000000000..915c26904ff --- /dev/null +++ b/src/components/modebar/cloud.js @@ -0,0 +1,11 @@ +var Plots = require('../../plots/plots'); + + +function uploadToCloud(gd) { + var fig = Plots.graphJson(gd, false, 'keepdata', 'object', true, true); + alert(JSON.stringify(fig, null, 2)); +} + +module.exports = { + uploadToCloud: uploadToCloud +}; \ No newline at end of file diff --git a/src/fonts/ploticon.js b/src/fonts/ploticon.js index f9f496f7ed0..53fdbedbe40 100644 --- a/src/fonts/ploticon.js +++ b/src/fonts/ploticon.js @@ -103,6 +103,12 @@ module.exports = { path: 'm214-7h429v214h-429v-214z m500 0h72v500q0 8-6 21t-11 20l-157 156q-5 6-19 12t-22 5v-232q0-22-15-38t-38-16h-322q-22 0-37 16t-16 38v232h-72v-714h72v232q0 22 16 38t37 16h465q22 0 38-16t15-38v-232z m-214 518v178q0 8-5 13t-13 5h-107q-7 0-13-5t-5-13v-178q0-8 5-13t13-5h107q7 0 13 5t5 13z m357-18v-518q0-22-15-38t-38-16h-750q-23 0-38 16t-16 38v750q0 22 16 38t38 16h517q23 0 50-12t42-26l156-157q16-15 27-42t11-49z', transform: 'matrix(1 0 0 -1 0 850)' }, + cloudupload: { + width: 640, + height: 640, + path: 'M176 544C96.5 544 32 479.5 32 400C32 336.6 73 282.8 129.9 263.5C128.6 255.8 128 248 128 240C128 160.5 192.5 96 272 96C327.4 96 375.5 127.3 399.6 173.1C413.8 164.8 430.4 160 448 160C501 160 544 203 544 256C544 271.7 540.2 286.6 533.5 299.7C577.5 320 608 364.4 608 416C608 486.7 550.7 544 480 544L176 544zM337 255C327.6 245.6 312.4 245.6 303.1 255L231.1 327C221.7 336.4 221.7 351.6 231.1 360.9C240.5 370.2 255.7 370.3 265 360.9L296 329.9L296 432C296 445.3 306.7 456 320 456C333.3 456 344 445.3 344 432L344 329.9L375 360.9C384.4 370.3 399.6 370.3 408.9 360.9C418.2 351.5 418.3 336.3 408.9 327L336.9 255z', + transform: 'matrix(1 0 0 1 -15 -15)' + }, drawopenpath: { width: 70, height: 70, From ad9ddfcd4c0c12b4f9eb7457700bd2b6b282295f Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 14 May 2026 12:08:58 -0400 Subject: [PATCH 3/4] use existing sendChartToCloud function --- src/components/modebar/buttons.js | 25 ++++--------------------- src/components/modebar/cloud.js | 11 ----------- src/components/modebar/manage.js | 5 ++--- src/plot_api/plot_config.js | 30 +++++++----------------------- src/plots/plots.js | 10 +++++++--- 5 files changed, 20 insertions(+), 61 deletions(-) delete mode 100644 src/components/modebar/cloud.js diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index c6b44f088b8..3b14de06760 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -4,7 +4,6 @@ var Registry = require('../../registry'); var Plots = require('../../plots/plots'); var axisIds = require('../../plots/cartesian/axis_ids'); var Icons = require('../../fonts/ploticon'); -var uploadToCloud = require('./cloud').uploadToCloud; var eraseActiveShape = require('../shapes/draw').eraseActiveShape; var Lib = require('../../lib'); var _ = Lib._; @@ -68,31 +67,15 @@ modeBarButtons.toImage = { } }; -modeBarButtons.sendDataToCloud = { - name: 'sendDataToCloud', - title: function(gd) { return _(gd, 'Edit in Chart Studio'); }, - icon: Icons.disk, - click: function(gd) { - Plots.sendDataToCloud(gd); - } -}; - -modeBarButtons.editInChartStudio = { - name: 'editInChartStudio', - title: function(gd) { return _(gd, 'Edit in Chart Studio'); }, - icon: Icons.pencil, +modeBarButtons.sendChartToCloud = { + name: 'sendChartToCloud', + title: function(gd) { return _(gd, 'Share with Plotly Cloud'); }, + icon: Icons.cloudupload, click: function(gd) { Plots.sendDataToCloud(gd); } }; -modeBarButtons.uploadToCloud = { - name: 'uploadToCloud', - title: function(gd) { return _(gd, 'Upload to Cloud'); }, - icon: Icons.cloudupload, - click: uploadToCloud, -}; - modeBarButtons.zoom2d = { name: 'zoom2d', _cat: 'zoom', diff --git a/src/components/modebar/cloud.js b/src/components/modebar/cloud.js deleted file mode 100644 index 915c26904ff..00000000000 --- a/src/components/modebar/cloud.js +++ /dev/null @@ -1,11 +0,0 @@ -var Plots = require('../../plots/plots'); - - -function uploadToCloud(gd) { - var fig = Plots.graphJson(gd, false, 'keepdata', 'object', true, true); - alert(JSON.stringify(fig, null, 2)); -} - -module.exports = { - uploadToCloud: uploadToCloud -}; \ No newline at end of file diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index d6b485be428..56713ca22db 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -144,9 +144,8 @@ function getButtonGroups(gd) { } // buttons common to all plot types - var commonGroup = ['toImage', 'uploadToCloud']; - if(context.showEditInChartStudio) commonGroup.push('editInChartStudio'); - else if(context.showSendToCloud) commonGroup.push('sendDataToCloud'); + var commonGroup = ['toImage']; + if(context.showSendToCloud) commonGroup.push('sendChartToCloud'); addGroup(commonGroup); var zoomGroup = []; diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index 09a22f99e55..4478a0ef695 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -35,12 +35,8 @@ var configAttributes = { valType: 'string', dflt: '', description: [ - 'When set it determines base URL for', - 'the \'Edit in Chart Studio\' `showEditInChartStudio`/`showSendToCloud` mode bar button', - 'and the showLink/sendData on-graph link.', - 'To enable sending your data to Chart Studio Cloud, you need to', - 'set both `plotlyServerURL` to \'https://chart-studio.plotly.com\' and', - 'also set `showSendToCloud` to true.' + 'Sets the URL for the `sendChartToCloud` modebar button.', + 'When clicked, the button will send the chart data to this URL.', ].join(' ') }, @@ -275,24 +271,12 @@ var configAttributes = { }, showSendToCloud: { valType: 'boolean', - dflt: false, - description: [ - 'Should we include a ModeBar button, labeled "Edit in Chart Studio",', - 'that sends this chart to chart-studio.plotly.com (formerly plot.ly) or another plotly server', - 'as specified by `plotlyServerURL` for editing, export, etc? Prior to version 1.43.0', - 'this button was included by default, now it is opt-in using this flag.', - 'Note that this button can (depending on `plotlyServerURL` being set) send your data', - 'to an external server. However that server does not persist your data', - 'until you arrive at the Chart Studio and explicitly click "Save".' - ].join(' ') - }, - showEditInChartStudio: { - valType: 'boolean', - dflt: false, + dflt: true, description: [ - 'Same as `showSendToCloud`, but use a pencil icon instead of a floppy-disk.', - 'Note that if both `showSendToCloud` and `showEditInChartStudio` are turned,', - 'only `showEditInChartStudio` will be honored.' + 'Should we include a modebar button that sends this chart to a URL', + 'specified by `plotlyServerURL`, for sharing the chart with others?', + 'Note that this button can (depending on `plotlyServerURL` being set)', + 'send your data to an external server.' ].join(' ') }, modeBarButtonsToRemove: { diff --git a/src/plots/plots.js b/src/plots/plots.js index b3ef101ef33..cf659cf18e3 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -201,8 +201,11 @@ function positionPlayWithData(gd, container) { } plots.sendDataToCloud = function(gd) { - var baseUrl = (window.PLOTLYENV || {}).BASE_URL || gd._context.plotlyServerURL; - if(!baseUrl) return; + var destUrl = (window.PLOTLYENV || {}).BASE_URL || gd._context.plotlyServerURL; + if(!destUrl) { + console.error('No destination URL provided (plotlyServerURL is not set)'); + return; + } gd.emit('plotly_beforeexport'); @@ -214,7 +217,7 @@ plots.sendDataToCloud = function(gd) { var hiddenform = hiddenformDiv .append('form') .attr({ - action: baseUrl + '/external', + action: destUrl, method: 'post', target: '_blank' }); @@ -227,6 +230,7 @@ plots.sendDataToCloud = function(gd) { }); hiddenformInput.node().value = plots.graphJson(gd, false, 'keepdata'); + console.log(`sending chart object to ${destUrl}`); hiddenform.node().submit(); hiddenformDiv.remove(); From 100da7ba21ed9f86e97f819840ed8acef713b627 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Thu, 14 May 2026 12:23:21 -0400 Subject: [PATCH 4/4] update plot-schema --- test/plot-schema.json | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/test/plot-schema.json b/test/plot-schema.json index e0b7c5f1371..18886d37287 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -279,7 +279,7 @@ "valType": "number" }, "plotlyServerURL": { - "description": "When set it determines base URL for the 'Edit in Chart Studio' `showEditInChartStudio`/`showSendToCloud` mode bar button and the showLink/sendData on-graph link. To enable sending your data to Chart Studio Cloud, you need to set both `plotlyServerURL` to 'https://chart-studio.plotly.com' and also set `showSendToCloud` to true.", + "description": "Sets the URL for the `sendChartToCloud` modebar button. When clicked, the button will send the chart data to this URL.", "dflt": "", "valType": "string" }, @@ -330,19 +330,14 @@ "dflt": true, "valType": "boolean" }, - "showEditInChartStudio": { - "description": "Same as `showSendToCloud`, but use a pencil icon instead of a floppy-disk. Note that if both `showSendToCloud` and `showEditInChartStudio` are turned, only `showEditInChartStudio` will be honored.", - "dflt": false, - "valType": "boolean" - }, "showLink": { "description": "Determines whether a link to Chart Studio Cloud is displayed at the bottom right corner of resulting graphs. Use with `sendData` and `linkText`.", "dflt": false, "valType": "boolean" }, "showSendToCloud": { - "description": "Should we include a ModeBar button, labeled \"Edit in Chart Studio\", that sends this chart to chart-studio.plotly.com (formerly plot.ly) or another plotly server as specified by `plotlyServerURL` for editing, export, etc? Prior to version 1.43.0 this button was included by default, now it is opt-in using this flag. Note that this button can (depending on `plotlyServerURL` being set) send your data to an external server. However that server does not persist your data until you arrive at the Chart Studio and explicitly click \"Save\".", - "dflt": false, + "description": "Should we include a modebar button that sends this chart to a URL specified by `plotlyServerURL`, for sharing the chart with others? Note that this button can (depending on `plotlyServerURL` being set) send your data to an external server.", + "dflt": true, "valType": "boolean" }, "showSources": { @@ -4628,7 +4623,7 @@ }, "remove": { "arrayOk": true, - "description": "Determines which predefined modebar buttons to remove. Similar to `config.modeBarButtonsToRemove` option. This may include *autoScale2d*, *autoscale*, *editInChartStudio*, *editinchartstudio*, *hoverCompareCartesian*, *hovercompare*, *lasso*, *lasso2d*, *orbitRotation*, *orbitrotation*, *pan*, *pan2d*, *pan3d*, *reset*, *resetCameraDefault3d*, *resetCameraLastSave3d*, *resetGeo*, *resetSankeyGroup*, *resetScale2d*, *resetViewMap*, *resetViewMapbox*, *resetViews*, *resetcameradefault*, *resetcameralastsave*, *resetsankeygroup*, *resetscale*, *resetview*, *resetviews*, *select*, *select2d*, *sendDataToCloud*, *senddatatocloud*, *tableRotation*, *tablerotation*, *toImage*, *toggleHover*, *toggleSpikelines*, *togglehover*, *togglespikelines*, *toimage*, *zoom*, *zoom2d*, *zoom3d*, *zoomIn2d*, *zoomInGeo*, *zoomInMap*, *zoomInMapbox*, *zoomOut2d*, *zoomOutGeo*, *zoomOutMap*, *zoomOutMapbox*, *zoomin*, *zoomout*.", + "description": "Determines which predefined modebar buttons to remove. Similar to `config.modeBarButtonsToRemove` option. This may include *autoScale2d*, *autoscale*, *hoverCompareCartesian*, *hovercompare*, *lasso*, *lasso2d*, *orbitRotation*, *orbitrotation*, *pan*, *pan2d*, *pan3d*, *reset*, *resetCameraDefault3d*, *resetCameraLastSave3d*, *resetGeo*, *resetSankeyGroup*, *resetScale2d*, *resetViewMap*, *resetViewMapbox*, *resetViews*, *resetcameradefault*, *resetcameralastsave*, *resetsankeygroup*, *resetscale*, *resetview*, *resetviews*, *select*, *select2d*, *sendChartToCloud*, *sendcharttocloud*, *tableRotation*, *tablerotation*, *toImage*, *toggleHover*, *toggleSpikelines*, *togglehover*, *togglespikelines*, *toimage*, *zoom*, *zoom2d*, *zoom3d*, *zoomIn2d*, *zoomInGeo*, *zoomInMap*, *zoomInMapbox*, *zoomOut2d*, *zoomOutGeo*, *zoomOutMap*, *zoomOutMapbox*, *zoomin*, *zoomout*.", "dflt": "", "editType": "modebar", "valType": "string"