diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 78424eaab43..2a2bb78e64b 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -245,57 +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 = []; - 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); - } - 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')) { @@ -311,47 +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.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/axes.js b/src/plots/cartesian/axes.js index d6c9d98fe39..8663b061b01 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -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 : 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 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); + } +}; 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..257ce63ef3f 100644 --- a/src/plots/gl3d/layout/defaults.js +++ b/src/plots/gl3d/layout/defaults.js @@ -9,30 +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; - - // until they play better together - delete layoutOut.xaxis; - delete layoutOut.yaxis; + 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 @@ -45,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 = {}; @@ -82,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'; } /* diff --git a/test/image/baselines/plot_types.png b/test/image/baselines/plot_types.png new file mode 100644 index 00000000000..a89b8ea6770 Binary files /dev/null and b/test/image/baselines/plot_types.png differ 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 + } +}