Skip to content

Commit 60a42c1

Browse files
authored
Merge pull request #4242 from plotly/treemap-sunburst-colors-in-colorscale
use marker.colors with colorscale in treemap and sunburst plots
2 parents 713b42a + 1dff468 commit 60a42c1

37 files changed

+1600
-212
lines changed

Diff for: src/components/colorscale/helpers.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ var Color = require('../color');
1717

1818
var isValidScale = require('./scales').isValid;
1919

20-
function hasColorscale(trace, containerStr) {
20+
function hasColorscale(trace, containerStr, colorKey) {
2121
var container = containerStr ?
2222
Lib.nestedProperty(trace, containerStr).get() || {} :
2323
trace;
24-
var color = container.color;
24+
var color = container[colorKey || 'color'];
2525

2626
var isArrayWithOneNumber = false;
2727
if(Lib.isArrayOrTypedArray(color)) {

Diff for: src/traces/sunburst/calc.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@ var Lib = require('../../lib');
1515
var makeColorScaleFn = require('../../components/colorscale').makeColorScaleFuncFromTrace;
1616
var makePullColorFn = require('../pie/calc').makePullColorFn;
1717
var generateExtendedColors = require('../pie/calc').generateExtendedColors;
18-
19-
var Colorscale = require('../../components/colorscale');
20-
var hasColorscale = Colorscale.hasColorscale;
21-
var colorscaleCalc = Colorscale.calc;
18+
var colorscaleCalc = require('../../components/colorscale').calc;
2219

2320
var sunburstExtendedColorWays = {};
2421
var treemapExtendedColorWays = {};
@@ -198,9 +195,10 @@ exports.calc = function(gd, trace) {
198195
var pullColor;
199196
var scaleColor;
200197
var colors = trace.marker.colors || [];
201-
trace._hasColorscale = hasColorscale(trace, 'marker');
198+
var hasColors = !!colors.length;
199+
202200
if(trace._hasColorscale) {
203-
if(!colors.length) {
201+
if(!hasColors) {
204202
colors = hasValues ? trace.values : trace._values;
205203
}
206204

Diff for: src/traces/sunburst/defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
4444
if(lineWidth) coerce('marker.line.color', layout.paper_bgcolor);
4545

4646
coerce('marker.colors');
47-
var withColorscale = hasColorscale(traceIn, 'marker');
47+
var withColorscale = traceOut._hasColorscale = hasColorscale(traceIn, 'marker', 'colors');
4848
if(withColorscale) {
4949
colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: 'marker.', cLetter: 'c'});
5050
}

Diff for: src/traces/sunburst/plot.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ function plotOne(gd, cd, element, transitionOpts) {
151151
var transTextX = function(d) { return cx + d.pxmid[0] * d.transform.rCenter + (d.transform.x || 0); };
152152
var transTextY = function(d) { return cy + d.pxmid[1] * d.transform.rCenter + (d.transform.y || 0); };
153153

154-
slices = slices.data(sliceData, function(pt) { return helpers.getPtId(pt); });
154+
slices = slices.data(sliceData, helpers.getPtId);
155155

156156
slices.enter().append('g')
157157
.classed('slice', true);

Diff for: src/traces/treemap/attributes.js

+11-32
Original file line numberDiff line numberDiff line change
@@ -139,29 +139,20 @@ module.exports = {
139139

140140
colors: sunburstAttrs.marker.colors,
141141

142-
opacitybase: {
143-
valType: 'number',
142+
depthfade: {
143+
valType: 'enumerated',
144+
values: [true, false, 'reversed'],
144145
editType: 'style',
145146
role: 'style',
146-
min: 0,
147-
max: 1,
148-
dflt: 0.5,
149147
description: [
150-
'Sets the base opacity of the headers based on the depth from the entry.',
151-
'This options is not available when having a `colorscale`.'
152-
].join(' ')
153-
},
154-
155-
opacitystep: {
156-
valType: 'number',
157-
editType: 'style',
158-
role: 'style',
159-
min: 0,
160-
max: 1,
161-
dflt: 0.5,
162-
description: [
163-
'Sets the increment for opacity of the headers based on the depth from the entry.',
164-
'This options is not available when having a `colorscale`.'
148+
'Determines if the sector colors are faded towards',
149+
'the background from the leaves up to the headers.',
150+
'This option is unavailable when a `colorscale` is present,',
151+
'defaults to false when `marker.colors` is set,',
152+
'but otherwise defaults to true.',
153+
'When set to *reversed*, the fading direction is inverted,',
154+
'that is the top elements within hierarchy are drawn with fully saturated colors',
155+
'while the leaves are faded towards the background color.'
165156
].join(' ')
166157
},
167158

@@ -231,18 +222,6 @@ module.exports = {
231222
].join(' ')
232223
},
233224

234-
opacity: {
235-
valType: 'number',
236-
editType: 'style',
237-
role: 'style',
238-
min: 0,
239-
dflt: 0.5,
240-
description: [
241-
'Sets the opacity of the pathbar',
242-
'This options is not available when having a `colorscale`.'
243-
].join(' ')
244-
},
245-
246225
textfont: extendFlat({}, pieAttrs.textfont, {
247226
description: 'Sets the font used inside `pathbar`.'
248227
}),

Diff for: src/traces/treemap/defaults.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,13 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
7272
var lineWidth = coerce('marker.line.width');
7373
if(lineWidth) coerce('marker.line.color', layout.paper_bgcolor);
7474

75-
coerce('marker.colors');
76-
var withColorscale = hasColorscale(traceIn, 'marker');
75+
var colors = coerce('marker.colors');
76+
var withColorscale = traceOut._hasColorscale = hasColorscale(traceIn, 'marker', 'colors');
77+
if(withColorscale) {
78+
colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: 'marker.', cLetter: 'c'});
79+
} else {
80+
coerce('marker.depthfade', !(colors || []).length);
81+
}
7782

7883
var headerSize = traceOut.textfont.size * 2;
7984

@@ -84,15 +89,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
8489

8590
if(withColorscale) {
8691
colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: 'marker.', cLetter: 'c'});
87-
} else {
88-
coerce('marker.opacitybase');
89-
coerce('marker.opacitystep');
90-
coerce('pathbar.opacity');
9192
}
9293

9394
traceOut._hovered = {
9495
marker: {
95-
opacity: 1,
9696
line: {
9797
width: 2,
9898
color: Color.contrast(layout.paper_bgcolor)

Diff for: src/traces/treemap/draw_ancestors.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ module.exports = function drawAncestors(gd, cd, entry, slices, opts) {
7373

7474
sliceData.reverse();
7575

76-
slices = slices.data(sliceData, function(pt) { return helpers.getPtId(pt); });
76+
slices = slices.data(sliceData, helpers.getPtId);
7777

7878
slices.enter().append('g')
7979
.classed('pathbar', true);

Diff for: src/traces/treemap/draw_descendants.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,24 @@ module.exports = function drawDescendants(gd, cd, entry, slices, opts) {
6565

6666
var sliceData = allData.descendants();
6767

68-
slices = slices.data(sliceData, function(pt) {
69-
// hide slices that won't show up on graph
70-
if(pt.depth >= trace._maxDepth) {
68+
var minVisibleDepth = Infinity;
69+
var maxVisibleDepth = -Infinity;
70+
sliceData.forEach(function(pt) {
71+
var depth = pt.depth;
72+
if(depth >= trace._maxDepth) {
73+
// hide slices that won't show up on graph
7174
pt.x0 = pt.x1 = (pt.x0 + pt.x1) / 2;
7275
pt.y0 = pt.y1 = (pt.y0 + pt.y1) / 2;
76+
} else {
77+
minVisibleDepth = Math.min(minVisibleDepth, depth);
78+
maxVisibleDepth = Math.max(maxVisibleDepth, depth);
7379
}
74-
75-
return helpers.getPtId(pt);
7680
});
7781

82+
slices = slices.data(sliceData, helpers.getPtId);
83+
84+
trace._maxVisibleLayers = isFinite(maxVisibleDepth) ? maxVisibleDepth - minVisibleDepth + 1 : 0;
85+
7886
slices.enter().append('g')
7987
.classed('slice', true);
8088

@@ -185,14 +193,6 @@ module.exports = function drawDescendants(gd, cd, entry, slices, opts) {
185193
isHeader: isHeader
186194
});
187195

188-
if(helpers.isOutsideText(trace, pt)) {
189-
// consider in/out diff font sizes
190-
pt.transform.targetY -= (
191-
helpers.getOutsideTextFontKey('size', trace, pt, fullLayout.font) -
192-
helpers.getInsideTextFontKey('size', trace, pt, fullLayout.font)
193-
);
194-
}
195-
196196
if(hasTransition) {
197197
sliceText.transition().attrTween('transform', function(pt2) {
198198
var interp = makeUpdateTextInterpolator(pt2, onPathbar, getRefRect(), [width, height]);

Diff for: src/traces/treemap/plot.js

+6-7
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ function plotOne(gd, cd, element, transitionOpts) {
8484
var hierarchy = cd0.hierarchy;
8585
var hasTransition = helpers.hasTransition(transitionOpts);
8686
var entry = helpers.findEntryWithLevel(hierarchy, trace.level);
87+
var isRoot = helpers.isHierarchyRoot(entry);
88+
8789
var maxDepth = helpers.getMaxDepth(trace);
8890
var hasVisibleDepth = function(pt) {
8991
return pt.data.depth - entry.data.depth < maxDepth;
@@ -146,18 +148,15 @@ function plotOne(gd, cd, element, transitionOpts) {
146148
return {};
147149
};
148150

149-
var isRoot = helpers.isHierarchyRoot(entry);
150-
151-
trace._entryDepth = entry.data.depth;
152-
if(isRoot) {
153-
trace._entryDepth++;
154-
}
155-
156151
// N.B. handle multiple-root special case
157152
if(cd0.hasMultipleRoots && isRoot) {
158153
maxDepth++;
159154
}
155+
160156
trace._maxDepth = maxDepth;
157+
trace._backgroundColor = fullLayout.paper_bgcolor;
158+
trace._entryDepth = entry.data.depth;
159+
trace._atRootLevel = isRoot;
161160

162161
var cenX = -vpw / 2 + gs.l + gs.w * (domain.x[1] + domain.x[0]) / 2;
163162
var cenY = -vph / 2 + gs.t + gs.h * (1 - (domain.y[1] + domain.y[0]) / 2);

Diff for: src/traces/treemap/style.js

+37-17
Original file line numberDiff line numberDiff line change
@@ -35,37 +35,57 @@ function styleOne(s, pt, trace, opts) {
3535
var ptNumber = cdi.i;
3636
var lineColor;
3737
var lineWidth;
38-
var opacity;
39-
40-
var depthFade = function(n) {
41-
var base = trace.marker.opacitybase;
42-
var step = trace.marker.opacitystep;
43-
44-
return n === 0 ? base :
45-
Math.max(0, Math.min(1, n * step));
46-
};
38+
var fillColor = cdi.color;
39+
var isRoot = helpers.isHierarchyRoot(pt);
40+
var opacity = 1;
4741

4842
if(hovered) {
4943
lineColor = trace._hovered.marker.line.color;
5044
lineWidth = trace._hovered.marker.line.width;
51-
opacity = trace._hovered.marker.opacity;
5245
} else {
53-
if(helpers.isHierarchyRoot(pt)) {
46+
if(isRoot && fillColor === 'rgba(0,0,0,0)') {
47+
opacity = 0;
5448
lineColor = 'rgba(0,0,0,0)';
5549
lineWidth = 0;
5650
} else {
5751
lineColor = Lib.castOption(trace, ptNumber, 'marker.line.color') || Color.defaultLine;
5852
lineWidth = Lib.castOption(trace, ptNumber, 'marker.line.width') || 0;
59-
}
6053

61-
opacity =
62-
trace._hasColorscale || helpers.isLeaf(pt) ? 1 :
63-
pt.onPathbar ? trace.pathbar.opacity :
64-
depthFade(pt.data.depth - trace._entryDepth);
54+
if(!trace._hasColorscale && !pt.onPathbar) {
55+
var depthfade = trace.marker.depthfade;
56+
if(depthfade) {
57+
var fadedColor = Color.combine(Color.addOpacity(trace._backgroundColor, 0.75), fillColor);
58+
var n;
59+
60+
if(depthfade === true) {
61+
var maxDepth = helpers.getMaxDepth(trace);
62+
if(isFinite(maxDepth)) {
63+
if(helpers.isLeaf(pt)) {
64+
n = 0;
65+
} else {
66+
n = (trace._maxVisibleLayers) - (pt.data.depth - trace._entryDepth);
67+
}
68+
} else {
69+
n = pt.data.height + 1;
70+
}
71+
} else { // i.e. case of depthfade === 'reversed'
72+
n = pt.data.depth - trace._entryDepth;
73+
if(!trace._atRootLevel) n++;
74+
}
75+
76+
if(n > 0) {
77+
for(var i = 0; i < n; i++) {
78+
var ratio = 0.5 * i / n;
79+
fillColor = Color.combine(Color.addOpacity(fadedColor, ratio), fillColor);
80+
}
81+
}
82+
}
83+
}
84+
}
6585
}
6686

6787
s.style('stroke-width', lineWidth)
68-
.call(Color.fill, cdi.color)
88+
.call(Color.fill, fillColor)
6989
.call(Color.stroke, lineColor)
7090
.style('opacity', opacity);
7191
}

Diff for: test/image/baselines/treemap_coffee-maxdepth3.png

249 Bytes
Loading

Diff for: test/image/baselines/treemap_coffee.png

-301 Bytes
Loading

Diff for: test/image/baselines/treemap_first.png

28 Bytes
Loading

Diff for: test/image/baselines/treemap_flare.png

709 Bytes
Loading

Diff for: test/image/baselines/treemap_level-depth.png

-119 Bytes
Loading
193 Bytes
Loading
38 Bytes
Loading

Diff for: test/image/baselines/treemap_packings.png

-15 Bytes
Loading

Diff for: test/image/baselines/treemap_pad_mirror.png

224 Bytes
Loading

Diff for: test/image/baselines/treemap_pad_transpose.png

2.46 KB
Loading

Diff for: test/image/baselines/treemap_sunburst_basic.png

86.7 KB
Loading
275 KB
Loading

Diff for: test/image/baselines/treemap_textfit.png

1021 Bytes
Loading

Diff for: test/image/baselines/treemap_textposition.png

6.54 KB
Loading

Diff for: test/image/baselines/treemap_transpose_nopad.png

4.98 KB
Loading

Diff for: test/image/baselines/treemap_values.png

80 Bytes
Loading

Diff for: test/image/baselines/treemap_values_colorscale.png

43 Bytes
Loading

Diff for: test/image/baselines/treemap_with-without_values.png

221 Bytes
Loading
125 Bytes
Loading

Diff for: test/image/mocks/treemap_pad_mirror.json

+4-10
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
"pad": 0
1515
},
1616
"marker": {
17-
"opacitybase": 0.3,
18-
"opacitystep": 0.1,
17+
"depthfade": "reversed",
1918
"pad": {
2019
"t": 16,
2120
"l": 8,
@@ -105,8 +104,7 @@
105104
"pad": 0
106105
},
107106
"marker": {
108-
"opacitybase": 0.3,
109-
"opacitystep": 0.1,
107+
"depthfade": "reversed",
110108
"pad": {
111109
"t": 16,
112110
"l": 8,
@@ -196,8 +194,6 @@
196194
"pad": 0
197195
},
198196
"marker": {
199-
"opacitybase": 0.3,
200-
"opacitystep": 0.1,
201197
"pad": {
202198
"t": 16,
203199
"l": 8,
@@ -287,8 +283,6 @@
287283
"pad": 0
288284
},
289285
"marker": {
290-
"opacitybase": 0.3,
291-
"opacitystep": 0.1,
292286
"pad": {
293287
"t": 16,
294288
"l": 8,
@@ -412,7 +406,7 @@
412406
"annotations": [
413407
{
414408
"showarrow": false,
415-
"text": "base",
409+
"text": "base<br>depthfade: 'reversed'",
416410
"font": {
417411
"size": 16
418412
},
@@ -423,7 +417,7 @@
423417
},
424418
{
425419
"showarrow": false,
426-
"text": "flip y axis",
420+
"text": "flip y axis<br>depthfade: 'reversed'",
427421
"font": {
428422
"size": 16
429423
},

0 commit comments

Comments
 (0)