Skip to content

Commit 1c85de6

Browse files
committed
add 'layer' axis attribute
- has 2 possible values: 'above traces' and 'below traces' for now, but opens the door for other values down the road.
1 parent 02b9fbc commit 1c85de6

File tree

7 files changed

+162
-20
lines changed

7 files changed

+162
-20
lines changed

src/plots/cartesian/constants.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,10 @@ module.exports = {
6565
'carpetlayer',
6666
'boxlayer',
6767
'scatterlayer'
68-
]
68+
],
69+
70+
layerValue2layerClass: {
71+
'above traces': 'above',
72+
'below traces': 'below'
73+
}
6974
};

src/plots/cartesian/index.js

+41-10
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ function makeSubplotData(gd) {
296296
function makeSubplotLayer(plotinfo) {
297297
var plotgroup = plotinfo.plotgroup;
298298
var id = plotinfo.id;
299+
var xLayer = constants.layerValue2layerClass[plotinfo.xaxis.layer];
300+
var yLayer = constants.layerValue2layerClass[plotinfo.yaxis.layer];
299301

300302
if(!plotinfo.mainplot) {
301303
var backLayer = joinLayer(plotgroup, 'g', 'layer-subplot');
@@ -308,19 +310,36 @@ function makeSubplotLayer(plotinfo) {
308310
plotinfo.zerolinelayer = joinLayer(plotgroup, 'g', 'zerolinelayer');
309311
plotinfo.overzero = joinLayer(plotgroup, 'g', 'overzero');
310312

313+
joinLayer(plotgroup, 'path', 'xlines-below');
314+
joinLayer(plotgroup, 'path', 'ylines-below');
315+
plotinfo.overlinesBelow = joinLayer(plotgroup, 'g', 'overlines-below');
316+
317+
joinLayer(plotgroup, 'g', 'xaxislayer-below');
318+
joinLayer(plotgroup, 'g', 'yaxislayer-below');
319+
plotinfo.overaxesBelow = joinLayer(plotgroup, 'g', 'overaxes-below');
320+
311321
plotinfo.plot = joinLayer(plotgroup, 'g', 'plot');
312322
plotinfo.overplot = joinLayer(plotgroup, 'g', 'overplot');
313323

314-
plotinfo.xlines = joinLayer(plotgroup, 'path', 'xlines');
315-
plotinfo.ylines = joinLayer(plotgroup, 'path', 'ylines');
316-
plotinfo.overlines = joinLayer(plotgroup, 'g', 'overlines');
324+
joinLayer(plotgroup, 'path', 'xlines-above');
325+
joinLayer(plotgroup, 'path', 'ylines-above');
326+
plotinfo.overlinesAbove = joinLayer(plotgroup, 'g', 'overlines-above');
327+
328+
joinLayer(plotgroup, 'g', 'xaxislayer-above');
329+
joinLayer(plotgroup, 'g', 'yaxislayer-above');
330+
plotinfo.overaxesAbove = joinLayer(plotgroup, 'g', 'overaxes-above');
317331

318-
plotinfo.xaxislayer = joinLayer(plotgroup, 'g', 'xaxislayer');
319-
plotinfo.yaxislayer = joinLayer(plotgroup, 'g', 'yaxislayer');
320-
plotinfo.overaxes = joinLayer(plotgroup, 'g', 'overaxes');
332+
// set refs to correct layers as determined by 'axis.layer'
333+
plotinfo.xlines = plotgroup.select('.xlines-' + xLayer);
334+
plotinfo.ylines = plotgroup.select('.ylines-' + yLayer);
335+
plotinfo.xaxislayer = plotgroup.select('.xaxislayer-' + xLayer);
336+
plotinfo.yaxislayer = plotgroup.select('.yaxislayer-' + yLayer);
321337
}
322338
else {
323339
var mainplotinfo = plotinfo.mainplotinfo;
340+
var mainplotgroup = mainplotinfo.plotgroup;
341+
var xId = id + '-x';
342+
var yId = id + '-y';
324343

325344
// now make the components of overlaid subplots
326345
// overlays don't have backgrounds, and append all
@@ -330,11 +349,23 @@ function makeSubplotLayer(plotinfo) {
330349
plotinfo.gridlayer = joinLayer(mainplotinfo.overgrid, 'g', id);
331350
plotinfo.zerolinelayer = joinLayer(mainplotinfo.overzero, 'g', id);
332351

352+
joinLayer(mainplotinfo.overlinesBelow, 'path', xId);
353+
joinLayer(mainplotinfo.overlinesBelow, 'path', yId);
354+
joinLayer(mainplotinfo.overaxesBelow, 'g', xId);
355+
joinLayer(mainplotinfo.overaxesBelow, 'g', yId);
356+
333357
plotinfo.plot = joinLayer(mainplotinfo.overplot, 'g', id);
334-
plotinfo.xlines = joinLayer(mainplotinfo.overlines, 'path', id + '-x');
335-
plotinfo.ylines = joinLayer(mainplotinfo.overlines, 'path', id + '-y');
336-
plotinfo.xaxislayer = joinLayer(mainplotinfo.overaxes, 'g', id + '-x');
337-
plotinfo.yaxislayer = joinLayer(mainplotinfo.overaxes, 'g', id + '-y');
358+
359+
joinLayer(mainplotinfo.overlinesAbove, 'path', xId);
360+
joinLayer(mainplotinfo.overlinesAbove, 'path', yId);
361+
joinLayer(mainplotinfo.overaxesAbove, 'g', xId);
362+
joinLayer(mainplotinfo.overaxesAbove, 'g', yId);
363+
364+
// set refs to correct layers as determined by 'abovetraces'
365+
plotinfo.xlines = mainplotgroup.select('.overlines-' + xLayer).select('.' + xId);
366+
plotinfo.ylines = mainplotgroup.select('.overlines-' + yLayer).select('.' + yId);
367+
plotinfo.xaxislayer = mainplotgroup.select('.overaxes-' + xLayer).select('.' + xId);
368+
plotinfo.yaxislayer = mainplotgroup.select('.overaxes-' + yLayer).select('.' + yId);
338369
}
339370

340371
// common attributes for all subplots, overlays or not

src/plots/cartesian/layout_attributes.js

+12
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,18 @@ module.exports = {
573573
'If *false*, this axis does not overlay any same-letter axes.'
574574
].join(' ')
575575
},
576+
layer: {
577+
valType: 'enumerated',
578+
values: ['above traces', 'below traces'],
579+
dflt: 'above traces',
580+
role: 'info',
581+
description: [
582+
'Sets the layer on which this axis is displayed.',
583+
'If *above traces*, this axis is displayed above all the subplot\'s traces',
584+
'If *below traces*, this axis is displayed below all the subplot\'s traces,',
585+
'but above the grid lines.'
586+
].join(' ')
587+
},
576588
domain: {
577589
valType: 'info_array',
578590
role: 'info',

src/plots/cartesian/position_defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,7 @@ module.exports = function handlePositionDefaults(containerIn, containerOut, coer
5959
Lib.noneOrAll(containerIn.domain, containerOut.domain, [0, 1]);
6060
}
6161

62+
coerce('layer');
63+
6264
return containerOut;
6365
};

src/plots/plots.js

+18-7
Original file line numberDiff line numberDiff line change
@@ -638,24 +638,35 @@ plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLa
638638
var ids = Plotly.Axes.getSubplots(mockGd);
639639

640640
for(var i = 0; i < ids.length; i++) {
641-
var id = ids[i],
642-
oldSubplot = oldSubplots[id],
643-
plotinfo;
641+
var id = ids[i];
642+
var oldSubplot = oldSubplots[id];
643+
var xaxis = Plotly.Axes.getFromId(mockGd, id, 'x');
644+
var yaxis = Plotly.Axes.getFromId(mockGd, id, 'y');
645+
var plotinfo;
644646

645647
if(oldSubplot) {
646648
plotinfo = newSubplots[id] = oldSubplot;
647649

648650
if(plotinfo._scene2d) {
649651
plotinfo._scene2d.updateRefs(newFullLayout);
650652
}
651-
}
652-
else {
653+
654+
if(plotinfo.xaxis.layer !== xaxis.layer) {
655+
plotinfo.xlines.attr('d', null);
656+
plotinfo.xaxislayer.selectAll('*').remove();
657+
}
658+
659+
if(plotinfo.yaxis.layer !== yaxis.layer) {
660+
plotinfo.ylines.attr('d', null);
661+
plotinfo.yaxislayer.selectAll('*').remove();
662+
}
663+
} else {
653664
plotinfo = newSubplots[id] = {};
654665
plotinfo.id = id;
655666
}
656667

657-
plotinfo.xaxis = Plotly.Axes.getFromId(mockGd, id, 'x');
658-
plotinfo.yaxis = Plotly.Axes.getFromId(mockGd, id, 'y');
668+
plotinfo.xaxis = xaxis;
669+
plotinfo.yaxis = yaxis;
659670

660671
// By default, we clip at the subplot level,
661672
// but if one trace on a given subplot has *cliponaxis* set to false,

test/jasmine/tests/cartesian_test.js

+75
Original file line numberDiff line numberDiff line change
@@ -403,4 +403,79 @@ describe('subplot creation / deletion:', function() {
403403
.catch(failTest)
404404
.then(done);
405405
});
406+
407+
it('should clear obsolete content out of axis layers when relayout\'ing *layer*', function(done) {
408+
var fig = Lib.extendDeep({}, require('@mocks/overlaying-axis-lines.json'));
409+
410+
function assertPathDatum(sel, expected, msg) {
411+
expect(sel.attr('d') === null ? false : true).toBe(expected, msg);
412+
}
413+
414+
function assertChildrenCnt(sel, expected, msg) {
415+
expect(sel.selectAll('*').size()).toBe(expected, msg);
416+
}
417+
418+
function _assert(xBelow, yBelow, xAbove, yAbove) {
419+
var g = d3.select('.subplot.xy');
420+
421+
assertPathDatum(g.select('.xlines-below'), xBelow[0], 'xlines below');
422+
assertChildrenCnt(g.select('.xaxislayer-below'), xBelow[1], 'xaxislayer below');
423+
424+
assertPathDatum(g.select('.ylines-below'), yBelow[0], 'ylines below');
425+
assertChildrenCnt(g.select('.yaxislayer-below'), yBelow[1], 'yaxislayer below');
426+
427+
assertPathDatum(g.select('.xlines-above'), xAbove[0], 'xlines above');
428+
assertChildrenCnt(g.select('.xaxislayer-above'), xAbove[1], 'xaxislayer above');
429+
430+
assertPathDatum(g.select('.ylines-above'), yAbove[0], 'ylines above');
431+
assertChildrenCnt(g.select('.yaxislayer-above'), yAbove[1], 'yaxislayer above');
432+
}
433+
434+
Plotly.plot(gd, fig).then(function() {
435+
_assert(
436+
[false, 0],
437+
[false, 0],
438+
[true, 10],
439+
[true, 10]
440+
);
441+
return Plotly.relayout(gd, 'xaxis.layer', 'below traces');
442+
})
443+
.then(function() {
444+
_assert(
445+
[true, 10],
446+
[false, 0],
447+
[false, 0],
448+
[true, 10]
449+
);
450+
return Plotly.relayout(gd, 'yaxis.layer', 'below traces');
451+
})
452+
.then(function() {
453+
_assert(
454+
[true, 10],
455+
[true, 10],
456+
[false, 0],
457+
[false, 0]
458+
);
459+
return Plotly.relayout(gd, { 'xaxis.layer': null, 'yaxis.layer': null });
460+
})
461+
.then(function() {
462+
_assert(
463+
[false, 0],
464+
[false, 0],
465+
[true, 10],
466+
[true, 10]
467+
);
468+
return Plotly.relayout(gd, { 'xaxis.layer': 'below traces', 'yaxis.layer': 'below traces' });
469+
})
470+
.then(function() {
471+
_assert(
472+
[true, 10],
473+
[true, 10],
474+
[false, 0],
475+
[false, 0]
476+
);
477+
})
478+
.catch(failTest)
479+
.then(done);
480+
});
406481
});

test/jasmine/tests/plots_test.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var Plotly = require('@lib/index');
22
var Plots = require('@src/plots/plots');
3+
var Lib = require('@src/lib');
34

45
var d3 = require('d3');
56
var createGraphDiv = require('../assets/create_graph_div');
@@ -38,13 +39,18 @@ describe('Test Plots', function() {
3839

3940
var oldFullLayout = {
4041
_plots: { xy: { plot: {} } },
41-
xaxis: { c2p: function() {} },
42-
yaxis: { _m: 20 },
42+
xaxis: { c2p: function() {}, layer: 'above traces' },
43+
yaxis: { _m: 20, layer: 'above traces' },
4344
scene: { _scene: {} },
4445
annotations: [{ _min: 10, }, { _max: 20 }],
4546
someFunc: function() {}
4647
};
4748

49+
Lib.extendFlat(oldFullLayout._plots.xy, {
50+
xaxis: oldFullLayout.xaxis,
51+
yaxis: oldFullLayout.yaxis
52+
});
53+
4854
var newData = [{
4955
type: 'scatter3d',
5056
z: [1, 2, 3, 4]

0 commit comments

Comments
 (0)