From b1700a74cd3f7922a780c0c6579533f399dd3fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 13:49:12 -0500 Subject: [PATCH 1/8] don't delete cartesian axes in 3d code --- src/plots/gl3d/index.js | 5 ----- src/plots/gl3d/layout/defaults.js | 4 ---- 2 files changed, 9 deletions(-) diff --git a/src/plots/gl3d/index.js b/src/plots/gl3d/index.js index beccb231bfc..5132c3cf995 100644 --- a/src/plots/gl3d/index.js +++ b/src/plots/gl3d/index.js @@ -80,11 +80,6 @@ exports.setConvert = require('./set_convert'); exports.initAxes = function(gd) { var fullLayout = gd._fullLayout; - - // until they play better together - delete fullLayout.xaxis; - delete fullLayout.yaxis; - var sceneIds = Plots.getSubplotIds(fullLayout, 'gl3d'); for(var i = 0; i < sceneIds.length; ++i) { diff --git a/src/plots/gl3d/layout/defaults.js b/src/plots/gl3d/layout/defaults.js index 495873f27be..e33aeec4d9e 100644 --- a/src/plots/gl3d/layout/defaults.js +++ b/src/plots/gl3d/layout/defaults.js @@ -20,10 +20,6 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { var scenes = Plotly.Plots.getSubplotIdsInData(fullData, 'gl3d'); var i; - // until they play better together - delete layoutOut.xaxis; - delete layoutOut.yaxis; - // Get number of scenes to compute default scene domain var scenesLength = scenes.length; var sceneLayoutIn, sceneLayoutOut; From 05d8b1c2eeba1559d96a9d6f534a40e9e57670d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 13:50:05 -0500 Subject: [PATCH 2/8] lint (mostly scoped variables) --- src/plot_api/plot_api.js | 14 +++++++++----- src/plots/gl3d/layout/defaults.js | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 78424eaab43..2ccfac9012d 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -256,12 +256,16 @@ Plotly.plot = function(gd, data, layout, config) { function getCdSubplot(calcdata, subplot) { var cdSubplot = []; - var i, cd, trace; - for (i = 0; i < calcdata.length; i++) { - cd = calcdata[i]; - trace = cd[0].trace; - if (trace.xaxis+trace.yaxis === subplot) cdSubplot.push(cd); + + for(var i = 0; i < calcdata.length; i++) { + var cd = calcdata[i]; + var trace = cd[0].trace; + + if(trace.xaxis + trace.yaxis === subplot) { + cdSubplot.push(cd); + } } + return cdSubplot; } diff --git a/src/plots/gl3d/layout/defaults.js b/src/plots/gl3d/layout/defaults.js index e33aeec4d9e..257ce63ef3f 100644 --- a/src/plots/gl3d/layout/defaults.js +++ b/src/plots/gl3d/layout/defaults.js @@ -9,26 +9,27 @@ 'use strict'; -var Plotly = require('../../../plotly'); +var Lib = require('../../../lib'); +var Plots = require('../../plots'); var layoutAttributes = require('./layout_attributes'); var supplyGl3dAxisLayoutDefaults = require('./axis_defaults'); module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { - if (!layoutOut._hasGL3D) return; + if(!layoutOut._hasGL3D) return; - var scenes = Plotly.Plots.getSubplotIdsInData(fullData, 'gl3d'); - var i; + var scenes = Plots.getSubplotIdsInData(fullData, 'gl3d'); // Get number of scenes to compute default scene domain var scenesLength = scenes.length; + var sceneLayoutIn, sceneLayoutOut; function coerce(attr, dflt) { - return Plotly.Lib.coerce(sceneLayoutIn, sceneLayoutOut, layoutAttributes, attr, dflt); + return Lib.coerce(sceneLayoutIn, sceneLayoutOut, layoutAttributes, attr, dflt); } - for (i = 0; i < scenesLength; ++i) { + for(var i = 0; i < scenesLength; i++) { var scene = scenes[i]; /* * Scene numbering proceeds as follows @@ -41,7 +42,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { * Also write back a blank scene object to user layout so that some * attributes like aspectratio can be written back dynamically. */ - sceneLayoutIn; + if(layoutIn[scene] !== undefined) sceneLayoutIn = layoutIn[scene]; else layoutIn[scene] = sceneLayoutIn = {}; @@ -78,10 +79,10 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { * for the mode. In this case we must force change it here as the default coerce * misses it above. */ - if (!hasAspect) { + if(!hasAspect) { sceneLayoutIn.aspectratio = sceneLayoutOut.aspectratio = {x: 1, y: 1, z: 1}; - if (aspectMode === 'manual') sceneLayoutOut.aspectmode = 'auto'; + if(aspectMode === 'manual') sceneLayoutOut.aspectmode = 'auto'; } /* From 0ba34c385655fb8ae3db6758c87f2f680d644da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 13:51:16 -0500 Subject: [PATCH 3/8] only used cartesian trace module in subplot loop --- src/plot_api/plot_api.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 2ccfac9012d..89ab016ef71 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -329,6 +329,8 @@ Plotly.plot = function(gd, data, layout, config) { for(j = 0; j < modules.length; j++) { _module = modules[j]; + if(_module.basePlotModule.name !== 'cartesian') continue; + if(!_module.plot && (_module.name === 'pie')) continue; // plot all traces of this type on this subplot at once From 3ad1021b6ac9f74eecf8cc87c82022f8a70c7220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 13:53:04 -0500 Subject: [PATCH 4/8] skip over anchor less axes: - in case some dummy axes were included in user layout. (e.g. someone layout = {xaxis: {}, scene: {xaxis: {}}} in a 3d-only graph. --- src/plots/cartesian/axes.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index d6c9d98fe39..7ebca7dd13d 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -1171,7 +1171,7 @@ axes.getSubplots = function(gd, ax) { if(subplots.indexOf(sp) === -1) subplots.push(sp); } - // look for subplots in the axes/anchors, so that we at least draw all axes + // look for subplots in the xes/anchors, so that we at least draw all axes var axesList = axes.list(gd, '', true); function hasAx2(sp, ax2) { @@ -1186,7 +1186,7 @@ axes.getSubplots = function(gd, ax) { ax2.anchor, ax3 = axes.getFromId(gd, ax3Id); - // if a free axis is already represented in the data, ignore it + // look if ax2 is already represented in the data var foundAx2 = false; for(j = 0; j < subplots.length; j++) { if(hasAx2(subplots[j], ax2)) { @@ -1194,15 +1194,12 @@ axes.getSubplots = function(gd, ax) { break; } } + + // ignore free axes that already represented in the data if(ax2.anchor === 'free' && foundAx2) continue; - if(!ax3) { - console.log([ - 'Warning: couldnt find anchor', ax3Id, - 'for axis', ax2._id - ].join(' ')); - return; - } + // ignore anchor-less axes + if(!ax3) continue; sp = (ax2Letter === 'x') ? ax2._id + ax3._id : From 0e186bc3b582132f67228da401437b1ca5d2dbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 13:53:48 -0500 Subject: [PATCH 5/8] init Fx when cartesian subplots are present --- src/plots/cartesian/graph_interact.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/cartesian/graph_interact.js b/src/plots/cartesian/graph_interact.js index 20531a93e86..6a8327ced22 100644 --- a/src/plots/cartesian/graph_interact.js +++ b/src/plots/cartesian/graph_interact.js @@ -79,7 +79,7 @@ fx.isHoriz = function(fullData) { fx.init = function(gd) { var fullLayout = gd._fullLayout; - if(fullLayout._hasGL3D || fullLayout._hasGeo || gd._context.staticPlot) return; + if(!fullLayout._hasCartesian || gd._context.staticPlot) return; var subplots = Object.keys(fullLayout._plots || {}).sort(function(a,b) { // sort overlays last, then by x axis number, then y axis number From e980e6a91de096ecc344e14611dddb68e0186b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 17:30:30 -0500 Subject: [PATCH 6/8] add multiple plot type image test --- test/image/baselines/plot_types.png | Bin 0 -> 49204 bytes test/image/mocks/plot_types.json | 135 ++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 test/image/baselines/plot_types.png create mode 100644 test/image/mocks/plot_types.json diff --git a/test/image/baselines/plot_types.png b/test/image/baselines/plot_types.png new file mode 100644 index 0000000000000000000000000000000000000000..a89b8ea6770bc3f4b1e240e64acc690d376e2815 GIT binary patch literal 49204 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�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 P@K5XdP4z<6hyMQuR*dOx literal 0 HcmV?d00001 diff --git a/test/image/mocks/plot_types.json b/test/image/mocks/plot_types.json new file mode 100644 index 00000000000..8d29b07d163 --- /dev/null +++ b/test/image/mocks/plot_types.json @@ -0,0 +1,135 @@ +{ + "data": [ + { + "x": [ + 1, + 2, + 3 + ], + "y": [ + 2, + 1, + 2 + ], + "legendgroup": "group", + "uid": "d036e4" + }, + { + "type": "scatter3d", + "x": [ + 1, + 2, + 3 + ], + "y": [ + 1, + 2, + 3 + ], + "z": [ + 2, + 1, + 2 + ], + "legendgroup": "group", + "uid": "a4b919" + }, + { + "type": "scattergeo", + "mode": "markers+lines", + "lon": [ + -100, + 0, + 100 + ], + "lat": [ + -45, + 0, + 45 + ], + "uid": "cdc474" + }, + { + "type": "pie", + "labels": [ + 1, + 2, + 3 + ], + "values": [ + 1, + 2, + 3 + ], + "domain": { + "x": [ + 0.5, + 1 + ], + "y": [ + 0.5, + 1 + ] + }, + "uid": "586104" + } + ], + "layout": { + "xaxis": { + "domain": [ + 0, + 0.5 + ], + "type": "linear", + "range": [ + 0.8603667136812412, + 3.139633286318759 + ], + "autorange": true + }, + "yaxis": { + "domain": [ + 0, + 0.5 + ], + "type": "linear", + "range": [ + 0.9078947368421053, + 2.0921052631578947 + ], + "autorange": true + }, + "scene": { + "domain": { + "x": [ + 0, + 0.5 + ], + "y": [ + 0.5, + 1 + ] + }, + "aspectratio": { + "x": 1.2599210498948732, + "y": 1.2599210498948732, + "z": 0.6299605249474366 + } + }, + "geo": { + "domain": { + "x": [ + 0.5, + 1 + ], + "y": [ + 0, + 0.5 + ] + } + }, + "height": 450, + "width": 1000, + "autosize": true + } +} From c537cc8f925ffbd8159a416d80bbcc160ff4fe7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 17:41:58 -0500 Subject: [PATCH 7/8] fix typo in comment --- src/plots/cartesian/axes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 7ebca7dd13d..8663b061b01 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -1171,7 +1171,7 @@ axes.getSubplots = function(gd, ax) { if(subplots.indexOf(sp) === -1) subplots.push(sp); } - // look for subplots in the xes/anchors, so that we at least draw all axes + // look for subplots in the axes/anchors, so that we at least draw all axes var axesList = axes.list(gd, '', true); function hasAx2(sp, ax2) { From c0652860700acc2b95abb3a9e48cd8e35a5d3e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 9 Feb 2016 18:25:04 -0500 Subject: [PATCH 8/8] introduce cartesian.plot method: - handles plot across cartesian subplots, in a similar way to how gl3d, geo and gl2d module operate. --- src/plot_api/plot_api.js | 104 +++++------------------------------ src/plots/cartesian/index.js | 87 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 91 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 89ab016ef71..2a2bb78e64b 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -245,61 +245,15 @@ Plotly.plot = function(gd, data, layout, config) { return Plotly.Axes.doTicks(gd, 'redraw'); } + // Now plot the data function drawData() { - // Now plot the data - var calcdata = gd.calcdata, - subplots = Plots.getSubplotIds(fullLayout, 'cartesian'), - modules = gd._modules; - - var i, j, trace, subplot, subplotInfo, - cdSubplot, cdError, cdModule, _module; - - function getCdSubplot(calcdata, subplot) { - var cdSubplot = []; - - for(var i = 0; i < calcdata.length; i++) { - var cd = calcdata[i]; - var trace = cd[0].trace; - - if(trace.xaxis + trace.yaxis === subplot) { - cdSubplot.push(cd); - } - } - - return cdSubplot; - } - - function getCdModule(cdSubplot, _module) { - var cdModule = []; - - for(var i = 0; i < cdSubplot.length; i++) { - var cd = cdSubplot[i]; - var trace = cd[0].trace; - - if((trace._module === _module) && (trace.visible === true)) { - cdModule.push(cd); - } - } - - return cdModule; - } - - // clean up old scenes that no longer have associated data - // will this be a performance hit? - - var plotRegistry = Plots.subplotsRegistry; - - // TODO incorporate cartesian and polar plots into this paradigm - if(fullLayout._hasGL3D) plotRegistry.gl3d.plot(gd); - if(fullLayout._hasGeo) plotRegistry.geo.plot(gd); - if(fullLayout._hasGL2D) plotRegistry.gl2d.plot(gd); + var calcdata = gd.calcdata; // in case of traces that were heatmaps or contour maps // previously, remove them and their colorbars explicitly - for (i = 0; i < calcdata.length; i++) { - trace = calcdata[i][0].trace; - - var isVisible = (trace.visible === true), + for(var i = 0; i < calcdata.length; i++) { + var trace = calcdata[i][0].trace, + isVisible = (trace.visible === true), uid = trace.uid; if(!isVisible || !Plots.traceIs(trace, '2dMap')) { @@ -315,49 +269,17 @@ Plotly.plot = function(gd, data, layout, config) { } } - for (i = 0; i < subplots.length; i++) { - subplot = subplots[i]; - subplotInfo = fullLayout._plots[subplot]; - cdSubplot = getCdSubplot(calcdata, subplot); - cdError = []; - - // remove old traces, then redraw everything - // TODO: use enter/exit appropriately in the plot functions - // so we don't need this - should sometimes be a big speedup - if(subplotInfo.plot) subplotInfo.plot.selectAll('g.trace').remove(); - - for(j = 0; j < modules.length; j++) { - _module = modules[j]; - - if(_module.basePlotModule.name !== 'cartesian') continue; - - if(!_module.plot && (_module.name === 'pie')) continue; - - // plot all traces of this type on this subplot at once - cdModule = getCdModule(cdSubplot, _module); - _module.plot(gd, subplotInfo, cdModule); - Lib.markTime('done ' + (cdModule[0] && cdModule[0][0].trace.type)); - - // collect the traces that may have error bars - if(cdModule[0] && cdModule[0][0].trace && Plots.traceIs(cdModule[0][0].trace, 'errorBarsOK')) { - cdError = cdError.concat(cdModule); - } - } + var plotRegistry = Plots.subplotsRegistry; - // finally do all error bars at once - if(fullLayout._hasCartesian) { - ErrorBars.plot(gd, subplotInfo, cdError); - Lib.markTime('done ErrorBars'); - } + if(fullLayout._hasGL3D) plotRegistry.gl3d.plot(gd); + if(fullLayout._hasGeo) plotRegistry.geo.plot(gd); + if(fullLayout._hasGL2D) plotRegistry.gl2d.plot(gd); + if(fullLayout._hasCartesian || fullLayout._hasPie) { + plotRegistry.cartesian.plot(gd); } - // now draw stuff not on subplots (ie, only pies at the moment) - if(fullLayout._hasPie) { - var Pie = Plots.getModule('pie'); - var cdPie = getCdModule(calcdata, Pie); - - if(cdPie.length) Pie.plot(gd, cdPie); - } + // clean up old scenes that no longer have associated data + // will this be a performance hit? // styling separate from drawing Plots.style(gd); diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js index e32de542552..a27eb63f22f 100644 --- a/src/plots/cartesian/index.js +++ b/src/plots/cartesian/index.js @@ -9,6 +9,10 @@ 'use strict'; +var Lib = require('../../lib'); +var Plots = require('../plots'); +var ErrorBars = require('../../components/errorbars'); + exports.name = 'cartesian'; @@ -27,3 +31,86 @@ exports.attrRegex = { x: /^xaxis([2-9]|[1-9][0-9]+)?$/, y: /^yaxis([2-9]|[1-9][0-9]+)?$/ }; + +exports.plot = function(gd) { + var fullLayout = gd._fullLayout, + subplots = Plots.getSubplotIds(fullLayout, 'cartesian'), + calcdata = gd.calcdata, + modules = gd._modules; + + function getCdSubplot(calcdata, subplot) { + var cdSubplot = []; + + for(var i = 0; i < calcdata.length; i++) { + var cd = calcdata[i]; + var trace = cd[0].trace; + + if(trace.xaxis + trace.yaxis === subplot) { + cdSubplot.push(cd); + } + } + + return cdSubplot; + } + + function getCdModule(cdSubplot, _module) { + var cdModule = []; + + for(var i = 0; i < cdSubplot.length; i++) { + var cd = cdSubplot[i]; + var trace = cd[0].trace; + + if((trace._module === _module) && (trace.visible === true)) { + cdModule.push(cd); + } + } + + return cdModule; + } + + for(var i = 0; i < subplots.length; i++) { + var subplot = subplots[i], + subplotInfo = fullLayout._plots[subplot], + cdSubplot = getCdSubplot(calcdata, subplot), + cdError = []; + + // remove old traces, then redraw everything + // TODO: use enter/exit appropriately in the plot functions + // so we don't need this - should sometimes be a big speedup + if(subplotInfo.plot) subplotInfo.plot.selectAll('g.trace').remove(); + + for(var j = 0; j < modules.length; j++) { + var _module = modules[j]; + + // skip over non-cartesian trace modules + if(_module.basePlotModule.name !== 'cartesian') continue; + + // skip over pies, there are drawn below + if(_module.name === 'pie') continue; + + // plot all traces of this type on this subplot at once + var cdModule = getCdModule(cdSubplot, _module); + _module.plot(gd, subplotInfo, cdModule); + Lib.markTime('done ' + (cdModule[0] && cdModule[0][0].trace.type)); + + // collect the traces that may have error bars + if(cdModule[0] && cdModule[0][0].trace && Plots.traceIs(cdModule[0][0].trace, 'errorBarsOK')) { + cdError = cdError.concat(cdModule); + } + } + + // finally do all error bars at once + if(fullLayout._hasCartesian) { + ErrorBars.plot(gd, subplotInfo, cdError); + Lib.markTime('done ErrorBars'); + } + } + + // now draw stuff not on subplots (ie, only pies at the moment) + if(fullLayout._hasPie) { + var Pie = Plots.getModule('pie'); + var cdPie = getCdModule(calcdata, Pie); + + if(cdPie.length) Pie.plot(gd, cdPie); + } +};