Skip to content

Commit 597a845

Browse files
committed
fix dynamic contour ordering and multi-heatmap-contour plots
1 parent 44aa70e commit 597a845

File tree

6 files changed

+87
-28
lines changed

6 files changed

+87
-28
lines changed

src/components/drawing/index.js

+7
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,13 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd) {
453453
if(gradientType) perPointGradient = true;
454454
else gradientType = markerGradient && markerGradient.type;
455455

456+
// for legend - arrays will propagate through here, but we don't need
457+
// to treat it as per-point.
458+
if(Array.isArray(gradientType)) {
459+
gradientType = gradientType[0];
460+
if(!gradientInfo[gradientType]) gradientType = 0;
461+
}
462+
456463
if(gradientType && gradientType !== 'none') {
457464
var gradientColor = d.mgc;
458465
if(gradientColor) perPointGradient = true;

src/components/legend/style.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ module.exports = function style(s, gd) {
7171
showGradientLine = true;
7272
}
7373
else {
74-
showLine = coloring === 'none' || contours.showlines;
74+
showLine = coloring === 'none' || coloring === 'heatmap' ||
75+
contours.showlines;
7576
}
7677

7778
if(contours.type === 'constraint') {

src/traces/contour/plot.js

+22-21
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ var Drawing = require('../../components/drawing');
1616
var svgTextUtils = require('../../lib/svg_text_utils');
1717
var Axes = require('../../plots/cartesian/axes');
1818
var setConvert = require('../../plots/cartesian/set_convert');
19-
var getUidsFromCalcData = require('../../plots/get_data').getUidsFromCalcData;
2019

2120
var heatmapPlot = require('../heatmap/plot');
2221
var makeCrossings = require('./make_crossings');
@@ -28,32 +27,35 @@ var constants = require('./constants');
2827
var costConstants = constants.LABELOPTIMIZER;
2928

3029
exports.plot = function plot(gd, plotinfo, cdcontours, contourLayer) {
31-
var uidLookup = getUidsFromCalcData(cdcontours);
30+
var contours = contourLayer.selectAll('g.contour')
31+
.data(
32+
cdcontours.map(function(d) { return d[0]; }),
33+
function(cd) { return cd.trace.uid; }
34+
);
3235

33-
contourLayer.selectAll('g.contour').each(function(d) {
34-
if(!uidLookup[d.trace.uid]) {
35-
d3.select(this).remove();
36-
}
37-
});
36+
contours.exit().remove();
3837

39-
for(var i = 0; i < cdcontours.length; i++) {
40-
plotOne(gd, plotinfo, cdcontours[i], contourLayer);
41-
}
38+
contours.enter().append('g')
39+
.classed('contour', true);
40+
41+
contours.each(function(cd) {
42+
plotOne(gd, plotinfo, cd, d3.select(this));
43+
})
44+
.order();
4245
};
4346

44-
function plotOne(gd, plotinfo, cd, contourLayer) {
45-
var trace = cd[0].trace;
46-
var x = cd[0].x;
47-
var y = cd[0].y;
47+
function plotOne(gd, plotinfo, cd, plotGroup) {
48+
var trace = cd.trace;
49+
var x = cd.x;
50+
var y = cd.y;
4851
var contours = trace.contours;
49-
var id = 'contour' + trace.uid;
5052
var xa = plotinfo.xaxis;
5153
var ya = plotinfo.yaxis;
5254
var fullLayout = gd._fullLayout;
53-
var pathinfo = emptyPathinfo(contours, plotinfo, cd[0]);
55+
var pathinfo = emptyPathinfo(contours, plotinfo, cd);
5456

5557
// use a heatmap to fill - draw it behind the lines
56-
var heatmapColoringLayer = Lib.ensureSingle(contourLayer, 'g', 'heatmapcoloring');
58+
var heatmapColoringLayer = Lib.ensureSingle(plotGroup, 'g', 'heatmapcoloring');
5759
var cdheatmaps = [];
5860
if(contours.coloring === 'heatmap') {
5961
if(trace.zauto && (trace.autocontour === false)) {
@@ -62,7 +64,7 @@ function plotOne(gd, plotinfo, cd, contourLayer) {
6264
trace._input.zmax = trace.zmax =
6365
trace.zmin + pathinfo.length * contours.size;
6466
}
65-
cdheatmaps = [cd];
67+
cdheatmaps = [[cd]];
6668
}
6769
heatmapPlot(gd, plotinfo, cdheatmaps, heatmapColoringLayer);
6870

@@ -87,11 +89,10 @@ function plotOne(gd, plotinfo, cd, contourLayer) {
8789
}
8890

8991
// draw everything
90-
var plotGroup = exports.makeContourGroup(contourLayer, cd, id);
9192
makeBackground(plotGroup, perimeter, contours);
9293
makeFills(plotGroup, fillPathinfo, perimeter, contours);
93-
makeLinesAndLabels(plotGroup, pathinfo, gd, cd[0], contours, perimeter);
94-
clipGaps(plotGroup, plotinfo, fullLayout._clips, cd[0], perimeter);
94+
makeLinesAndLabels(plotGroup, pathinfo, gd, cd, contours, perimeter);
95+
clipGaps(plotGroup, plotinfo, fullLayout._clips, cd, perimeter);
9596
}
9697

9798
exports.makeContourGroup = function(layer, cd, id) {
12.2 KB
Loading

test/image/mocks/contour_legend.json

+18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@
2727
"z": [[3, 2, 1], [6, 5, 4], [9, 8, 7]],
2828
"line": {"color": "#f88"},
2929
"name": "constraint"
30+
}, {
31+
"type": "contour",
32+
"contours": {"coloring": "heatmap"},
33+
"z": [[1, 2], [3, 4]],
34+
"showscale": false,
35+
"showlegend": true,
36+
"y": [2, 3],
37+
"name": "heatmap 1"
38+
}, {
39+
"type": "contour",
40+
"contours": {"coloring": "heatmap"},
41+
"z": [[1, 2], [3, 4]],
42+
"showscale": false,
43+
"showlegend": true,
44+
"colorscale": "Viridis",
45+
"x": [1, 2],
46+
"y": [2, 3],
47+
"name": "heatmap 2"
3048
}],
3149
"layout":{
3250
"autosize":false,

test/jasmine/tests/contour_test.js

+38-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
var d3 = require('d3');
2+
13
var Plotly = require('@lib/index');
24
var Plots = require('@src/plots/plots');
35
var Lib = require('@src/lib');
@@ -414,12 +416,12 @@ describe('contour plotting and editing', function() {
414416

415417
function _assert(exp) {
416418
var msg = ' index in <g.contourlayer> (call #' + cnt + ')';
417-
var contourLayer = gd.querySelector('.xy > .plot > .contourlayer');
419+
var contourPlot = gd.querySelector('.xy > .plot > .contourlayer > .contour');
418420
var hmIndex = -1;
419421
var contoursIndex = -1;
420422

421-
for(var i in contourLayer.children) {
422-
var child = contourLayer.children[i];
423+
for(var i in contourPlot.children) {
424+
var child = contourPlot.children[i];
423425
if(child.querySelector) {
424426
if(child.querySelector('.hm')) hmIndex = +i;
425427
else if(child.querySelector('.contourlevel')) contoursIndex = +i;
@@ -439,21 +441,21 @@ describe('contour plotting and editing', function() {
439441
.then(function() {
440442
_assert({
441443
hmIndex: 0,
442-
contoursIndex: 1
444+
contoursIndex: 3
443445
});
444446
return Plotly.restyle(gd, 'contours.coloring', 'lines');
445447
})
446448
.then(function() {
447449
_assert({
448450
hmIndex: -1,
449-
contoursIndex: 1
451+
contoursIndex: 3
450452
});
451453
return Plotly.restyle(gd, 'contours.coloring', 'heatmap');
452454
})
453455
.then(function() {
454456
_assert({
455457
hmIndex: 0,
456-
contoursIndex: 1
458+
contoursIndex: 3
457459
});
458460
})
459461
.catch(fail)
@@ -501,4 +503,34 @@ describe('contour plotting and editing', function() {
501503
.catch(fail)
502504
.then(done);
503505
});
506+
507+
it('keeps the correct ordering after hide and show', function(done) {
508+
function getIndices() {
509+
var out = [];
510+
d3.selectAll('.contour').each(function(d) { out.push(d.trace.index); });
511+
return out;
512+
}
513+
514+
Plotly.newPlot(gd, [{
515+
type: 'contour',
516+
z: [[1, 2], [3, 4]]
517+
}, {
518+
type: 'contour',
519+
z: [[2, 1], [4, 3]],
520+
contours: {coloring: 'lines'}
521+
}])
522+
.then(function() {
523+
expect(getIndices()).toEqual([0, 1]);
524+
return Plotly.restyle(gd, 'visible', false, [0]);
525+
})
526+
.then(function() {
527+
expect(getIndices()).toEqual([1]);
528+
return Plotly.restyle(gd, 'visible', true, [0]);
529+
})
530+
.then(function() {
531+
expect(getIndices()).toEqual([0, 1]);
532+
})
533+
.catch(fail)
534+
.then(done);
535+
});
504536
});

0 commit comments

Comments
 (0)