Skip to content

Commit 78c5964

Browse files
committed
contour constraints outside carpet
1 parent de15ad1 commit 78c5964

31 files changed

+605
-372
lines changed

src/components/legend/helpers.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99

1010
'use strict';
1111

12-
var Registry = require('../../registry');
13-
14-
1512
exports.legendGetsTrace = function legendGetsTrace(trace) {
16-
return trace.visible && Registry.traceIs(trace, 'showLegend');
13+
// traceIs(trace, 'showLegend') is not sufficient anymore, due to contour(carpet)?
14+
// which are legend-eligible only if type: constraint. Otherwise, showlegend gets deleted.
15+
16+
// Note that we explicitly include showlegend: false, so a trace that *could* be
17+
// in the legend but is not shown still counts toward the two traces you need to
18+
// ensure the legend is shown by default, because this can still help disambiguate.
19+
return trace.visible && (trace.showlegend !== undefined);
1720
};
1821

1922
exports.isGrouped = function isGrouped(legendLayout) {

src/components/legend/style.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,14 @@ module.exports = function style(s, gd) {
6060
.each(stylePoints);
6161

6262
function styleLines(d) {
63-
var trace = d[0].trace,
64-
showFill = trace.visible && trace.fill && trace.fill !== 'none',
65-
showLine = subTypes.hasLines(trace);
66-
67-
if(trace && trace._module && trace._module.name === 'contourcarpet') {
68-
showLine = trace.contours.showlines;
69-
showFill = trace.contours.coloring === 'fill' || trace.contours.type === 'constraint';
63+
var trace = d[0].trace;
64+
var showFill = trace.visible && trace.fill && trace.fill !== 'none';
65+
var showLine = subTypes.hasLines(trace);
66+
var contours = trace.contours;
67+
68+
if(contours && contours.type === 'constraint') {
69+
showLine = contours.showlines;
70+
showFill = contours.operation !== '=';
7071
}
7172

7273
var fill = d3.select(this).select('.legendfill').selectAll('path')

src/traces/contour/attributes.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ module.exports = extendFlat({
3939

4040
connectgaps: heatmapAttrs.connectgaps,
4141

42+
fillcolor: {
43+
valType: 'color',
44+
role: 'style',
45+
editType: 'calc',
46+
description: [
47+
'Sets the fill color if `contours.type` is *constraint*.',
48+
'Defaults to a half-transparent variant of the line color,',
49+
'marker color, or marker line color, whichever is available.'
50+
].join(' ')
51+
},
52+
4253
autocontour: {
4354
valType: 'boolean',
4455
dflt: true,

src/traces/contour/calc.js

Lines changed: 3 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -9,94 +9,14 @@
99

1010
'use strict';
1111

12-
var Axes = require('../../plots/cartesian/axes');
13-
var extendFlat = require('../../lib').extendFlat;
1412
var heatmapCalc = require('../heatmap/calc');
15-
13+
var setContours = require('./set_contours');
1614

1715
// most is the same as heatmap calc, then adjust it
1816
// though a few things inside heatmap calc still look for
1917
// contour maps, because the makeBoundArray calls are too entangled
2018
module.exports = function calc(gd, trace) {
21-
var cd = heatmapCalc(gd, trace),
22-
contours = trace.contours;
23-
24-
// check if we need to auto-choose contour levels
25-
if(trace.autocontour !== false) {
26-
var dummyAx = autoContours(trace.zmin, trace.zmax, trace.ncontours);
27-
28-
contours.size = dummyAx.dtick;
29-
30-
contours.start = Axes.tickFirst(dummyAx);
31-
dummyAx.range.reverse();
32-
contours.end = Axes.tickFirst(dummyAx);
33-
34-
if(contours.start === trace.zmin) contours.start += contours.size;
35-
if(contours.end === trace.zmax) contours.end -= contours.size;
36-
37-
// if you set a small ncontours, *and* the ends are exactly on zmin/zmax
38-
// there's an edge case where start > end now. Make sure there's at least
39-
// one meaningful contour, put it midway between the crossed values
40-
if(contours.start > contours.end) {
41-
contours.start = contours.end = (contours.start + contours.end) / 2;
42-
}
43-
44-
// copy auto-contour info back to the source data.
45-
// previously we copied the whole contours object back, but that had
46-
// other info (coloring, showlines) that should be left to supplyDefaults
47-
if(!trace._input.contours) trace._input.contours = {};
48-
extendFlat(trace._input.contours, {
49-
start: contours.start,
50-
end: contours.end,
51-
size: contours.size
52-
});
53-
trace._input.autocontour = true;
54-
}
55-
else {
56-
// sanity checks on manually-supplied start/end/size
57-
var start = contours.start,
58-
end = contours.end,
59-
inputContours = trace._input.contours;
60-
61-
if(start > end) {
62-
contours.start = inputContours.start = end;
63-
end = contours.end = inputContours.end = start;
64-
start = contours.start;
65-
}
66-
67-
if(!(contours.size > 0)) {
68-
var sizeOut;
69-
if(start === end) sizeOut = 1;
70-
else sizeOut = autoContours(start, end, trace.ncontours).dtick;
71-
72-
inputContours.size = contours.size = sizeOut;
73-
}
74-
}
75-
19+
var cd = heatmapCalc(gd, trace);
20+
setContours(trace);
7621
return cd;
7722
};
78-
79-
/*
80-
* autoContours: make a dummy axis object with dtick we can use
81-
* as contours.size, and if needed we can use Axes.tickFirst
82-
* with this axis object to calculate the start and end too
83-
*
84-
* start: the value to start the contours at
85-
* end: the value to end at (must be > start)
86-
* ncontours: max number of contours to make, like roughDTick
87-
*
88-
* returns: an axis object
89-
*/
90-
function autoContours(start, end, ncontours) {
91-
var dummyAx = {
92-
type: 'linear',
93-
range: [start, end]
94-
};
95-
96-
Axes.autoTicks(
97-
dummyAx,
98-
(end - start) / (ncontours || 15)
99-
);
100-
101-
return dummyAx;
102-
}

src/traces/contourcarpet/close_boundaries.js renamed to src/traces/contour/close_boundaries.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
module.exports = function(pathinfo, operation, perimeter, trace) {
1212
// Abandon all hope, ye who enter here.
1313
var i, v1, v2;
14-
var na = trace.a.length;
15-
var nb = trace.b.length;
16-
var z = trace.z;
14+
var pi0 = pathinfo[0];
15+
var na = pi0.x.length;
16+
var nb = pi0.y.length;
17+
var z = pi0.z;
18+
var contours = trace.contours;
1719

1820
var boundaryMax = -Infinity;
1921
var boundaryMin = Infinity;
@@ -32,36 +34,35 @@ module.exports = function(pathinfo, operation, perimeter, trace) {
3234
boundaryMax = Math.max(boundaryMax, z[nb - 1][i]);
3335
}
3436

37+
pi0.prefixBoundary = false;
38+
3539
switch(operation) {
3640
case '>':
3741
case '>=':
38-
if(trace.contours.value > boundaryMax) {
39-
pathinfo[0].prefixBoundary = true;
42+
if(contours.value > boundaryMax) {
43+
pi0.prefixBoundary = true;
4044
}
4145
break;
4246
case '<':
4347
case '<=':
44-
if(trace.contours.value < boundaryMin) {
45-
pathinfo[0].prefixBoundary = true;
48+
if(contours.value < boundaryMin) {
49+
pi0.prefixBoundary = true;
4650
}
4751
break;
4852
case '[]':
4953
case '()':
50-
v1 = Math.min.apply(null, trace.contours.value);
51-
v2 = Math.max.apply(null, trace.contours.value);
52-
if(v2 < boundaryMin) {
53-
pathinfo[0].prefixBoundary = true;
54-
}
55-
if(v1 > boundaryMax) {
56-
pathinfo[0].prefixBoundary = true;
54+
v1 = Math.min.apply(null, contours.value);
55+
v2 = Math.max.apply(null, contours.value);
56+
if(v2 < boundaryMin || v1 > boundaryMax) {
57+
pi0.prefixBoundary = true;
5758
}
5859
break;
5960
case '][':
6061
case ')(':
61-
v1 = Math.min.apply(null, trace.contours.value);
62-
v2 = Math.max.apply(null, trace.contours.value);
62+
v1 = Math.min.apply(null, contours.value);
63+
v2 = Math.max.apply(null, contours.value);
6364
if(v1 < boundaryMin && v2 > boundaryMax) {
64-
pathinfo[0].prefixBoundary = true;
65+
pi0.prefixBoundary = true;
6566
}
6667
break;
6768
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Copyright 2012-2018, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var handleConstraintValueDefaults = require('./constraint_value_defaults');
13+
var handleLabelDefaults = require('./label_defaults');
14+
var Color = require('../../components/color');
15+
var addOpacity = Color.addOpacity;
16+
var opacity = Color.opacity;
17+
18+
module.exports = function handleConstraintDefaults(traceIn, traceOut, coerce, layout, defaultColor, opts) {
19+
var contours = traceOut.contours;
20+
var showLines, lineColor, fillColor;
21+
22+
var operation = coerce('contours.operation');
23+
24+
handleConstraintValueDefaults(coerce, contours);
25+
26+
if(operation === '=') {
27+
showLines = contours.showlines = true;
28+
}
29+
else {
30+
showLines = coerce('contours.showlines');
31+
fillColor = coerce('fillcolor', addOpacity(
32+
(traceIn.line || {}).color || defaultColor, 0.5
33+
));
34+
}
35+
36+
if(showLines) {
37+
var lineDfltColor = fillColor && opacity(fillColor) ?
38+
addOpacity(traceOut.fillcolor, 1) :
39+
defaultColor;
40+
lineColor = coerce('line.color', lineDfltColor);
41+
coerce('line.width', 2);
42+
coerce('line.dash');
43+
}
44+
45+
coerce('line.smoothing');
46+
47+
handleLabelDefaults(coerce, layout, lineColor, opts);
48+
};

src/traces/contourcarpet/constraint_value_defaults.js renamed to src/traces/contour/constraint_value_defaults.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
var constraintMapping = require('./constraint_mapping');
12+
// var constraintMapping = require('./constraint_mapping');
1313
var isNumeric = require('fast-isnumeric');
1414

1515
module.exports = function(coerce, contours) {
@@ -50,10 +50,4 @@ module.exports = function(coerce, contours) {
5050
}
5151
}
5252
}
53-
54-
var map = constraintMapping[contours.operation](contours.value);
55-
56-
contours.start = map.start;
57-
contours.end = map.end;
58-
contours.size = map.size;
5953
};

src/traces/contourcarpet/convert_to_constraints.js renamed to src/traces/contour/convert_to_constraints.js

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,29 @@ module.exports = function(pathinfo, operation) {
2121
var op1 = function(arr) { return arr; };
2222

2323
switch(operation) {
24+
case '=':
25+
case '<':
26+
case '<=':
27+
return pathinfo;
28+
case '>=':
29+
case '>':
30+
if(pathinfo.length !== 1) {
31+
Lib.warn('Contour data invalid for the specified inequality operation.');
32+
}
33+
34+
// In this case there should be exactly two contour levels in pathinfo. We
35+
// simply concatenate the info into one pathinfo and flip all of the data
36+
// in one. This will draw the contour as closed.
37+
pi0 = pathinfo[0];
38+
39+
for(i = 0; i < pi0.edgepaths.length; i++) {
40+
pi0.edgepaths[i] = op0(pi0.edgepaths[i]);
41+
}
42+
43+
for(i = 0; i < pi0.paths.length; i++) {
44+
pi0.paths[i] = op0(pi0.paths[i]);
45+
}
46+
return pathinfo;
2447
case '][':
2548
case ')[':
2649
case '](':
@@ -37,14 +60,13 @@ module.exports = function(pathinfo, operation) {
3760
/* eslint-enable: no-fallthrough */
3861
if(pathinfo.length !== 2) {
3962
Lib.warn('Contour data invalid for the specified inequality range operation.');
40-
return;
4163
}
4264

4365
// In this case there should be exactly two contour levels in pathinfo. We
4466
// simply concatenate the info into one pathinfo and flip all of the data
4567
// in one. This will draw the contour as closed.
46-
pi0 = pathinfo[0];
47-
pi1 = pathinfo[1];
68+
pi0 = copyPathinfo(pathinfo[0]);
69+
pi1 = copyPathinfo(pathinfo[1]);
4870

4971
for(i = 0; i < pi0.edgepaths.length; i++) {
5072
pi0.edgepaths[i] = op0(pi0.edgepaths[i]);
@@ -60,28 +82,13 @@ module.exports = function(pathinfo, operation) {
6082
while(pi1.paths.length) {
6183
pi0.paths.push(op1(pi1.paths.shift()));
6284
}
63-
pathinfo.pop();
64-
65-
break;
66-
case '>=':
67-
case '>':
68-
if(pathinfo.length !== 1) {
69-
Lib.warn('Contour data invalid for the specified inequality operation.');
70-
return;
71-
}
72-
73-
// In this case there should be exactly two contour levels in pathinfo. We
74-
// simply concatenate the info into one pathinfo and flip all of the data
75-
// in one. This will draw the contour as closed.
76-
pi0 = pathinfo[0];
77-
78-
for(i = 0; i < pi0.edgepaths.length; i++) {
79-
pi0.edgepaths[i] = op0(pi0.edgepaths[i]);
80-
}
81-
82-
for(i = 0; i < pi0.paths.length; i++) {
83-
pi0.paths[i] = op0(pi0.paths[i]);
84-
}
85-
break;
85+
return [pi0];
8686
}
8787
};
88+
89+
function copyPathinfo(pi) {
90+
return Lib.extendFlat({}, pi, {
91+
edgepaths: Lib.extendDeep([], pi.edgepaths),
92+
paths: Lib.extendDeep([], pi.paths)
93+
});
94+
}

0 commit comments

Comments
 (0)