Skip to content

Commit ecb476d

Browse files
committed
Merge pull request #159 from plotly/pie-trace-cleaning
Pie trace cleaning
2 parents 7236922 + c47255f commit ecb476d

10 files changed

+1032
-932
lines changed

src/traces/pie/attributes.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9+
'use strict';
910

1011
var colorAttrs = require('../../components/color/attributes');
1112
var fontAttrs = require('../../plots/font_attributes');

src/traces/pie/calc.js

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* Copyright 2012-2016, 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+
'use strict';
10+
11+
var isNumeric = require('fast-isnumeric');
12+
var tinycolor = require('tinycolor2');
13+
14+
var Color = require('../../components/color');
15+
var helpers = require('./helpers');
16+
17+
module.exports = function calc(gd, trace) {
18+
var vals = trace.values,
19+
labels = trace.labels,
20+
cd = [],
21+
fullLayout = gd._fullLayout,
22+
colorMap = fullLayout._piecolormap,
23+
allThisTraceLabels = {},
24+
needDefaults = false,
25+
vTotal = 0,
26+
hiddenLabels = fullLayout.hiddenlabels || [],
27+
i,
28+
v,
29+
label,
30+
color,
31+
hidden,
32+
pt;
33+
34+
if(trace.dlabel) {
35+
labels = new Array(vals.length);
36+
for(i = 0; i < vals.length; i++) {
37+
labels[i] = String(trace.label0 + i * trace.dlabel);
38+
}
39+
}
40+
41+
for(i = 0; i < vals.length; i++) {
42+
v = vals[i];
43+
if(!isNumeric(v)) continue;
44+
v = +v;
45+
if(v < 0) continue;
46+
47+
label = labels[i];
48+
if(label === undefined || label === '') label = i;
49+
label = String(label);
50+
// only take the first occurrence of any given label.
51+
// TODO: perhaps (optionally?) sum values for a repeated label?
52+
if(allThisTraceLabels[label] === undefined) allThisTraceLabels[label] = true;
53+
else continue;
54+
55+
color = tinycolor(trace.marker.colors[i]);
56+
if(color.isValid()) {
57+
color = Color.addOpacity(color, color.getAlpha());
58+
if(!colorMap[label]) {
59+
colorMap[label] = color;
60+
}
61+
}
62+
// have we seen this label and assigned a color to it in a previous trace?
63+
else if(colorMap[label]) color = colorMap[label];
64+
// color needs a default - mark it false, come back after sorting
65+
else {
66+
color = false;
67+
needDefaults = true;
68+
}
69+
70+
hidden = hiddenLabels.indexOf(label) !== -1;
71+
72+
if(!hidden) vTotal += v;
73+
74+
cd.push({
75+
v: v,
76+
label: label,
77+
color: color,
78+
i: i,
79+
hidden: hidden
80+
});
81+
}
82+
83+
if(trace.sort) cd.sort(function(a, b) { return b.v - a.v; });
84+
85+
/**
86+
* now go back and fill in colors we're still missing
87+
* this is done after sorting, so we pick defaults
88+
* in the order slices will be displayed
89+
*/
90+
91+
if(needDefaults) {
92+
for(i = 0; i < cd.length; i++) {
93+
pt = cd[i];
94+
if(pt.color === false) {
95+
colorMap[pt.label] = pt.color = nextDefaultColor(fullLayout._piedefaultcolorcount);
96+
fullLayout._piedefaultcolorcount++;
97+
}
98+
}
99+
}
100+
101+
// include the sum of all values in the first point
102+
if(cd[0]) cd[0].vTotal = vTotal;
103+
104+
// now insert text
105+
if(trace.textinfo && trace.textinfo !== 'none') {
106+
var hasLabel = trace.textinfo.indexOf('label') !== -1,
107+
hasText = trace.textinfo.indexOf('text') !== -1,
108+
hasValue = trace.textinfo.indexOf('value') !== -1,
109+
hasPercent = trace.textinfo.indexOf('percent') !== -1,
110+
thisText;
111+
112+
for(i = 0; i < cd.length; i++) {
113+
pt = cd[i];
114+
thisText = hasLabel ? [pt.label] : [];
115+
if(hasText && trace.text[pt.i]) thisText.push(trace.text[pt.i]);
116+
if(hasValue) thisText.push(helpers.formatPieValue(pt.v));
117+
if(hasPercent) thisText.push(helpers.formatPiePercent(pt.v / vTotal));
118+
pt.text = thisText.join('<br>');
119+
}
120+
}
121+
122+
return cd;
123+
};
124+
125+
/**
126+
* pick a default color from the main default set, augmented by
127+
* itself lighter then darker before repeating
128+
*/
129+
var pieDefaultColors;
130+
131+
function nextDefaultColor(index) {
132+
if(!pieDefaultColors) {
133+
// generate this default set on demand (but then it gets saved in the module)
134+
var mainDefaults = Color.defaults;
135+
pieDefaultColors = mainDefaults.slice();
136+
for(var i = 0; i < mainDefaults.length; i++) {
137+
pieDefaultColors.push(tinycolor(mainDefaults[i]).lighten(20).toHexString());
138+
}
139+
for(i = 0; i < Color.defaults.length; i++) {
140+
pieDefaultColors.push(tinycolor(mainDefaults[i]).darken(20).toHexString());
141+
}
142+
}
143+
144+
return pieDefaultColors[index % pieDefaultColors.length];
145+
}

src/traces/pie/defaults.js

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Copyright 2012-2016, 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+
'use strict';
10+
11+
var Lib = require('../../lib');
12+
var attributes = require('./attributes');
13+
14+
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
15+
function coerce(attr, dflt) {
16+
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
17+
}
18+
19+
var coerceFont = Lib.coerceFont;
20+
21+
var vals = coerce('values');
22+
if(!Array.isArray(vals) || !vals.length) {
23+
traceOut.visible = false;
24+
return;
25+
}
26+
27+
var labels = coerce('labels');
28+
if(!Array.isArray(labels)) {
29+
coerce('label0');
30+
coerce('dlabel');
31+
}
32+
33+
var lineWidth = coerce('marker.line.width');
34+
if(lineWidth) coerce('marker.line.color');
35+
36+
var colors = coerce('marker.colors');
37+
if(!Array.isArray(colors)) traceOut.marker.colors = []; // later this will get padded with default colors
38+
39+
coerce('scalegroup');
40+
// TODO: tilt, depth, and hole all need to be coerced to the same values within a scaleegroup
41+
// (ideally actually, depth would get set the same *after* scaling, ie the same absolute depth)
42+
// and if colors aren't specified we should match these up - potentially even if separate pies
43+
// are NOT in the same sharegroup
44+
45+
46+
var textData = coerce('text');
47+
var textInfo = coerce('textinfo', Array.isArray(textData) ? 'text+percent' : 'percent');
48+
49+
coerce('hoverinfo', (layout._dataLength === 1) ? 'label+text+value+percent' : undefined);
50+
51+
if(textInfo && textInfo !== 'none') {
52+
var textPosition = coerce('textposition'),
53+
hasBoth = Array.isArray(textPosition) || textPosition === 'auto',
54+
hasInside = hasBoth || textPosition === 'inside',
55+
hasOutside = hasBoth || textPosition === 'outside';
56+
57+
if(hasInside || hasOutside) {
58+
var dfltFont = coerceFont(coerce, 'textfont', layout.font);
59+
if(hasInside) coerceFont(coerce, 'insidetextfont', dfltFont);
60+
if(hasOutside) coerceFont(coerce, 'outsidetextfont', dfltFont);
61+
}
62+
}
63+
64+
coerce('domain.x');
65+
coerce('domain.y');
66+
67+
// 3D attributes commented out until I finish them in a later PR
68+
// var tilt = coerce('tilt');
69+
// if(tilt) {
70+
// coerce('tiltaxis');
71+
// coerce('depth');
72+
// coerce('shading');
73+
// }
74+
75+
coerce('hole');
76+
77+
coerce('sort');
78+
coerce('direction');
79+
coerce('rotation');
80+
81+
coerce('pull');
82+
};

src/traces/pie/helpers.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright 2012-2016, 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+
'use strict';
10+
11+
exports.formatPiePercent = function formatPiePercent(v) {
12+
var vRounded = (v * 100).toPrecision(3);
13+
if(vRounded.indexOf('.') !== -1) return vRounded.replace(/[.]?0+$/,'') + '%';
14+
return vRounded + '%';
15+
};
16+
17+
exports.formatPieValue = function formatPieValue(v) {
18+
var vRounded = v.toPrecision(10);
19+
if(vRounded.indexOf('.') !== -1) return vRounded.replace(/[.]?0+$/,'');
20+
return vRounded;
21+
};

0 commit comments

Comments
 (0)