Skip to content

Commit 7f785d5

Browse files
committed
Merge pull request #246 from plotly/subplots
Multi-plot-type graphs
2 parents c9bdddb + c065286 commit 7f785d5

File tree

8 files changed

+251
-112
lines changed

8 files changed

+251
-112
lines changed

src/plot_api/plot_api.js

+13-85
Original file line numberDiff line numberDiff line change
@@ -245,57 +245,15 @@ Plotly.plot = function(gd, data, layout, config) {
245245
return Plotly.Axes.doTicks(gd, 'redraw');
246246
}
247247

248+
// Now plot the data
248249
function drawData() {
249-
// Now plot the data
250-
var calcdata = gd.calcdata,
251-
subplots = Plots.getSubplotIds(fullLayout, 'cartesian'),
252-
modules = gd._modules;
253-
254-
var i, j, trace, subplot, subplotInfo,
255-
cdSubplot, cdError, cdModule, _module;
256-
257-
function getCdSubplot(calcdata, subplot) {
258-
var cdSubplot = [];
259-
var i, cd, trace;
260-
for (i = 0; i < calcdata.length; i++) {
261-
cd = calcdata[i];
262-
trace = cd[0].trace;
263-
if (trace.xaxis+trace.yaxis === subplot) cdSubplot.push(cd);
264-
}
265-
return cdSubplot;
266-
}
267-
268-
function getCdModule(cdSubplot, _module) {
269-
var cdModule = [];
270-
271-
for(var i = 0; i < cdSubplot.length; i++) {
272-
var cd = cdSubplot[i];
273-
var trace = cd[0].trace;
274-
275-
if((trace._module === _module) && (trace.visible === true)) {
276-
cdModule.push(cd);
277-
}
278-
}
279-
280-
return cdModule;
281-
}
282-
283-
// clean up old scenes that no longer have associated data
284-
// will this be a performance hit?
285-
286-
var plotRegistry = Plots.subplotsRegistry;
287-
288-
// TODO incorporate cartesian and polar plots into this paradigm
289-
if(fullLayout._hasGL3D) plotRegistry.gl3d.plot(gd);
290-
if(fullLayout._hasGeo) plotRegistry.geo.plot(gd);
291-
if(fullLayout._hasGL2D) plotRegistry.gl2d.plot(gd);
250+
var calcdata = gd.calcdata;
292251

293252
// in case of traces that were heatmaps or contour maps
294253
// previously, remove them and their colorbars explicitly
295-
for (i = 0; i < calcdata.length; i++) {
296-
trace = calcdata[i][0].trace;
297-
298-
var isVisible = (trace.visible === true),
254+
for(var i = 0; i < calcdata.length; i++) {
255+
var trace = calcdata[i][0].trace,
256+
isVisible = (trace.visible === true),
299257
uid = trace.uid;
300258

301259
if(!isVisible || !Plots.traceIs(trace, '2dMap')) {
@@ -311,47 +269,17 @@ Plotly.plot = function(gd, data, layout, config) {
311269
}
312270
}
313271

314-
for (i = 0; i < subplots.length; i++) {
315-
subplot = subplots[i];
316-
subplotInfo = fullLayout._plots[subplot];
317-
cdSubplot = getCdSubplot(calcdata, subplot);
318-
cdError = [];
319-
320-
// remove old traces, then redraw everything
321-
// TODO: use enter/exit appropriately in the plot functions
322-
// so we don't need this - should sometimes be a big speedup
323-
if(subplotInfo.plot) subplotInfo.plot.selectAll('g.trace').remove();
324-
325-
for(j = 0; j < modules.length; j++) {
326-
_module = modules[j];
327-
328-
if(!_module.plot && (_module.name === 'pie')) continue;
329-
330-
// plot all traces of this type on this subplot at once
331-
cdModule = getCdModule(cdSubplot, _module);
332-
_module.plot(gd, subplotInfo, cdModule);
333-
Lib.markTime('done ' + (cdModule[0] && cdModule[0][0].trace.type));
334-
335-
// collect the traces that may have error bars
336-
if(cdModule[0] && cdModule[0][0].trace && Plots.traceIs(cdModule[0][0].trace, 'errorBarsOK')) {
337-
cdError = cdError.concat(cdModule);
338-
}
339-
}
272+
var plotRegistry = Plots.subplotsRegistry;
340273

341-
// finally do all error bars at once
342-
if(fullLayout._hasCartesian) {
343-
ErrorBars.plot(gd, subplotInfo, cdError);
344-
Lib.markTime('done ErrorBars');
345-
}
274+
if(fullLayout._hasGL3D) plotRegistry.gl3d.plot(gd);
275+
if(fullLayout._hasGeo) plotRegistry.geo.plot(gd);
276+
if(fullLayout._hasGL2D) plotRegistry.gl2d.plot(gd);
277+
if(fullLayout._hasCartesian || fullLayout._hasPie) {
278+
plotRegistry.cartesian.plot(gd);
346279
}
347280

348-
// now draw stuff not on subplots (ie, only pies at the moment)
349-
if(fullLayout._hasPie) {
350-
var Pie = Plots.getModule('pie');
351-
var cdPie = getCdModule(calcdata, Pie);
352-
353-
if(cdPie.length) Pie.plot(gd, cdPie);
354-
}
281+
// clean up old scenes that no longer have associated data
282+
// will this be a performance hit?
355283

356284
// styling separate from drawing
357285
Plots.style(gd);

src/plots/cartesian/axes.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -1186,23 +1186,20 @@ axes.getSubplots = function(gd, ax) {
11861186
ax2.anchor,
11871187
ax3 = axes.getFromId(gd, ax3Id);
11881188

1189-
// if a free axis is already represented in the data, ignore it
1189+
// look if ax2 is already represented in the data
11901190
var foundAx2 = false;
11911191
for(j = 0; j < subplots.length; j++) {
11921192
if(hasAx2(subplots[j], ax2)) {
11931193
foundAx2 = true;
11941194
break;
11951195
}
11961196
}
1197+
1198+
// ignore free axes that already represented in the data
11971199
if(ax2.anchor === 'free' && foundAx2) continue;
11981200

1199-
if(!ax3) {
1200-
console.log([
1201-
'Warning: couldnt find anchor', ax3Id,
1202-
'for axis', ax2._id
1203-
].join(' '));
1204-
return;
1205-
}
1201+
// ignore anchor-less axes
1202+
if(!ax3) continue;
12061203

12071204
sp = (ax2Letter === 'x') ?
12081205
ax2._id + ax3._id :

src/plots/cartesian/graph_interact.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ fx.isHoriz = function(fullData) {
7979
fx.init = function(gd) {
8080
var fullLayout = gd._fullLayout;
8181

82-
if(fullLayout._hasGL3D || fullLayout._hasGeo || gd._context.staticPlot) return;
82+
if(!fullLayout._hasCartesian || gd._context.staticPlot) return;
8383

8484
var subplots = Object.keys(fullLayout._plots || {}).sort(function(a,b) {
8585
// sort overlays last, then by x axis number, then y axis number

src/plots/cartesian/index.js

+87
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
'use strict';
1111

12+
var Lib = require('../../lib');
13+
var Plots = require('../plots');
14+
var ErrorBars = require('../../components/errorbars');
15+
1216

1317
exports.name = 'cartesian';
1418

@@ -27,3 +31,86 @@ exports.attrRegex = {
2731
x: /^xaxis([2-9]|[1-9][0-9]+)?$/,
2832
y: /^yaxis([2-9]|[1-9][0-9]+)?$/
2933
};
34+
35+
exports.plot = function(gd) {
36+
var fullLayout = gd._fullLayout,
37+
subplots = Plots.getSubplotIds(fullLayout, 'cartesian'),
38+
calcdata = gd.calcdata,
39+
modules = gd._modules;
40+
41+
function getCdSubplot(calcdata, subplot) {
42+
var cdSubplot = [];
43+
44+
for(var i = 0; i < calcdata.length; i++) {
45+
var cd = calcdata[i];
46+
var trace = cd[0].trace;
47+
48+
if(trace.xaxis + trace.yaxis === subplot) {
49+
cdSubplot.push(cd);
50+
}
51+
}
52+
53+
return cdSubplot;
54+
}
55+
56+
function getCdModule(cdSubplot, _module) {
57+
var cdModule = [];
58+
59+
for(var i = 0; i < cdSubplot.length; i++) {
60+
var cd = cdSubplot[i];
61+
var trace = cd[0].trace;
62+
63+
if((trace._module === _module) && (trace.visible === true)) {
64+
cdModule.push(cd);
65+
}
66+
}
67+
68+
return cdModule;
69+
}
70+
71+
for(var i = 0; i < subplots.length; i++) {
72+
var subplot = subplots[i],
73+
subplotInfo = fullLayout._plots[subplot],
74+
cdSubplot = getCdSubplot(calcdata, subplot),
75+
cdError = [];
76+
77+
// remove old traces, then redraw everything
78+
// TODO: use enter/exit appropriately in the plot functions
79+
// so we don't need this - should sometimes be a big speedup
80+
if(subplotInfo.plot) subplotInfo.plot.selectAll('g.trace').remove();
81+
82+
for(var j = 0; j < modules.length; j++) {
83+
var _module = modules[j];
84+
85+
// skip over non-cartesian trace modules
86+
if(_module.basePlotModule.name !== 'cartesian') continue;
87+
88+
// skip over pies, there are drawn below
89+
if(_module.name === 'pie') continue;
90+
91+
// plot all traces of this type on this subplot at once
92+
var cdModule = getCdModule(cdSubplot, _module);
93+
_module.plot(gd, subplotInfo, cdModule);
94+
Lib.markTime('done ' + (cdModule[0] && cdModule[0][0].trace.type));
95+
96+
// collect the traces that may have error bars
97+
if(cdModule[0] && cdModule[0][0].trace && Plots.traceIs(cdModule[0][0].trace, 'errorBarsOK')) {
98+
cdError = cdError.concat(cdModule);
99+
}
100+
}
101+
102+
// finally do all error bars at once
103+
if(fullLayout._hasCartesian) {
104+
ErrorBars.plot(gd, subplotInfo, cdError);
105+
Lib.markTime('done ErrorBars');
106+
}
107+
}
108+
109+
// now draw stuff not on subplots (ie, only pies at the moment)
110+
if(fullLayout._hasPie) {
111+
var Pie = Plots.getModule('pie');
112+
var cdPie = getCdModule(calcdata, Pie);
113+
114+
if(cdPie.length) Pie.plot(gd, cdPie);
115+
}
116+
};

src/plots/gl3d/index.js

-5
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,6 @@ exports.setConvert = require('./set_convert');
8080

8181
exports.initAxes = function(gd) {
8282
var fullLayout = gd._fullLayout;
83-
84-
// until they play better together
85-
delete fullLayout.xaxis;
86-
delete fullLayout.yaxis;
87-
8883
var sceneIds = Plots.getSubplotIds(fullLayout, 'gl3d');
8984

9085
for(var i = 0; i < sceneIds.length; ++i) {

src/plots/gl3d/layout/defaults.js

+10-13
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,27 @@
99

1010
'use strict';
1111

12-
var Plotly = require('../../../plotly');
12+
var Lib = require('../../../lib');
13+
var Plots = require('../../plots');
1314
var layoutAttributes = require('./layout_attributes');
1415
var supplyGl3dAxisLayoutDefaults = require('./axis_defaults');
1516

1617

1718
module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
18-
if (!layoutOut._hasGL3D) return;
19+
if(!layoutOut._hasGL3D) return;
1920

20-
var scenes = Plotly.Plots.getSubplotIdsInData(fullData, 'gl3d');
21-
var i;
22-
23-
// until they play better together
24-
delete layoutOut.xaxis;
25-
delete layoutOut.yaxis;
21+
var scenes = Plots.getSubplotIdsInData(fullData, 'gl3d');
2622

2723
// Get number of scenes to compute default scene domain
2824
var scenesLength = scenes.length;
25+
2926
var sceneLayoutIn, sceneLayoutOut;
3027

3128
function coerce(attr, dflt) {
32-
return Plotly.Lib.coerce(sceneLayoutIn, sceneLayoutOut, layoutAttributes, attr, dflt);
29+
return Lib.coerce(sceneLayoutIn, sceneLayoutOut, layoutAttributes, attr, dflt);
3330
}
3431

35-
for (i = 0; i < scenesLength; ++i) {
32+
for(var i = 0; i < scenesLength; i++) {
3633
var scene = scenes[i];
3734
/*
3835
* Scene numbering proceeds as follows
@@ -45,7 +42,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
4542
* Also write back a blank scene object to user layout so that some
4643
* attributes like aspectratio can be written back dynamically.
4744
*/
48-
sceneLayoutIn;
45+
4946
if(layoutIn[scene] !== undefined) sceneLayoutIn = layoutIn[scene];
5047
else layoutIn[scene] = sceneLayoutIn = {};
5148

@@ -82,10 +79,10 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
8279
* for the mode. In this case we must force change it here as the default coerce
8380
* misses it above.
8481
*/
85-
if (!hasAspect) {
82+
if(!hasAspect) {
8683
sceneLayoutIn.aspectratio = sceneLayoutOut.aspectratio = {x: 1, y: 1, z: 1};
8784

88-
if (aspectMode === 'manual') sceneLayoutOut.aspectmode = 'auto';
85+
if(aspectMode === 'manual') sceneLayoutOut.aspectmode = 'auto';
8986
}
9087

9188
/*

test/image/baselines/plot_types.png

48.1 KB
Loading

0 commit comments

Comments
 (0)