Skip to content

Commit 8be5c4b

Browse files
authored
Merge pull request #7580 from my-tien/pie-legend-visibility
Pie legend and showlegend per slice
2 parents f07f1c7 + cbe853b commit 8be5c4b

File tree

14 files changed

+273
-22
lines changed

14 files changed

+273
-22
lines changed

draftlogs/7580_add.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add support for arrays for the pie properties `showlegend` and `legend`, so that these can be configured per slice. [[#7580](https://github.com/plotly/plotly.js/pull/7580)], with thanks to @my-tien for the contribution!

src/components/legend/defaults.js

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,39 @@ function groupDefaults(legendId, layoutIn, layoutOut, fullData) {
4545

4646
var shapesWithLegend = (layoutOut.shapes || []).filter(function(d) { return d.showlegend; });
4747

48+
function isPieWithLegendArray(trace) {
49+
return Registry.traceIs(trace, 'pie-like')
50+
&& trace._length != null
51+
&& (Array.isArray(trace.legend) || Array.isArray(trace.showlegend));
52+
};
53+
fullData
54+
.filter(isPieWithLegendArray)
55+
.forEach(function (trace) {
56+
if (trace.visible) {
57+
legendTraceCount++;
58+
}
59+
for(var index = 0; index < trace._length; index++) {
60+
var legend = (Array.isArray(trace.legend) ? trace.legend[index] : trace.legend) || 'legend';
61+
if(legend === legendId) {
62+
// showlegend can be boolean or a boolean array.
63+
// will fall back to default if array index is out-of-range
64+
const showInLegend = Array.isArray(trace.showlegend) ? trace.showlegend[index] : trace.showlegend;
65+
if (showInLegend || trace._dfltShowLegend) {
66+
legendReallyHasATrace = true;
67+
legendTraceCount++;
68+
}
69+
}
70+
}
71+
if(legendId === 'legend' && trace._length > trace.legend.length) {
72+
for(var idx = trace.legend.length; idx < trace._length; idx++) {
73+
legendReallyHasATrace = true;
74+
legendTraceCount++;
75+
}
76+
}
77+
});
78+
4879
var allLegendItems = fullData.concat(shapesWithLegend).filter(function(d) {
49-
return legendId === (d.legend || 'legend');
80+
return !isPieWithLegendArray(trace) && legendId === (d.legend || 'legend');
5081
});
5182

5283
for(var i = 0; i < allLegendItems.length; i++) {
@@ -82,7 +113,6 @@ function groupDefaults(legendId, layoutIn, layoutOut, fullData) {
82113

83114
Lib.coerceFont(traceCoerce, 'legendgrouptitle.font', grouptitlefont);
84115
}
85-
86116
if((!isShape && Registry.traceIs(trace, 'bar') && layoutOut.barmode === 'stack') ||
87117
['tonextx', 'tonexty'].indexOf(trace.fill) !== -1) {
88118
defaultOrder = helpers.isGrouped({ traceorder: defaultOrder }) ?
@@ -95,9 +125,15 @@ function groupDefaults(legendId, layoutIn, layoutOut, fullData) {
95125
}
96126
}
97127

98-
var showLegend = Lib.coerce(layoutIn, layoutOut,
99-
basePlotLayoutAttributes, 'showlegend',
100-
legendReallyHasATrace && (legendTraceCount > (legendId === 'legend' ? 1 : 0)));
128+
var showLegend = Lib.coerce(
129+
layoutIn,
130+
layoutOut,
131+
basePlotLayoutAttributes,
132+
'showlegend',
133+
layoutOut.showlegend ||
134+
(legendReallyHasATrace &&
135+
legendTraceCount > (legendId === 'legend' ? 1 : 0))
136+
);
101137

102138
// delete legend
103139
if(showLegend === false) layoutOut[legendId] = undefined;
@@ -230,7 +266,11 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
230266

231267
var legends = ['legend'];
232268
for(i = 0; i < allLegendsData.length; i++) {
233-
Lib.pushUnique(legends, allLegendsData[i].legend);
269+
if (Array.isArray(allLegendsData[i].legend)) {
270+
legends = legends.concat(allLegendsData[i].legend);
271+
} else {
272+
Lib.pushUnique(legends, allLegendsData[i].legend);
273+
}
234274
}
235275

236276
layoutOut._legends = [];

src/components/legend/draw.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,11 @@ function textLayout(s, g, gd, legendObj, aTitle) {
633633

634634
function computeTextDimensions(g, gd, legendObj, aTitle) {
635635
var legendItem = g.data()[0][0];
636-
if(!legendObj._inHover && legendItem && !legendItem.trace.showlegend) {
636+
var showlegend = legendItem && legendItem.trace.showlegend;
637+
if (Array.isArray(showlegend)) {
638+
showlegend = showlegend[legendItem.i] !== false;
639+
}
640+
if(!legendObj._inHover && legendItem && !showlegend) {
637641
g.remove();
638642
return;
639643
}

src/components/legend/get_legend_data.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,17 @@ module.exports = function getLegendData(calcdata, opts, hasMultipleLegends) {
4747
if(!inHover && (!trace.visible || !trace.showlegend)) continue;
4848

4949
if(Registry.traceIs(trace, 'pie-like')) {
50+
var legendPerSlice = Array.isArray(trace.legend);
51+
var showlegendPerSlice = Array.isArray(trace.showlegend);
5052
if(!slicesShown[lgroup]) slicesShown[lgroup] = {};
5153

5254
for(j = 0; j < cd.length; j++) {
55+
if (showlegendPerSlice && trace.showlegend[cd[j].i] === false) {
56+
continue;
57+
}
58+
if (legendPerSlice) {
59+
lid = trace.legend[cd[j].i] || 'legend';
60+
}
5361
var labelj = cd[j].label;
5462

5563
if(!slicesShown[lgroup][labelj]) {

src/lib/coerce.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,14 @@ exports.valObjectMeta = {
8686
boolean: {
8787
description: 'A boolean (true/false) value.',
8888
requiredOpts: [],
89-
otherOpts: ['dflt'],
90-
coerceFunction: function(v, propOut, dflt) {
91-
if(v === true || v === false) propOut.set(v);
92-
else propOut.set(dflt);
89+
otherOpts: ['dflt', 'arrayOk'],
90+
coerceFunction: function(v, propOut, dflt, opts) {
91+
const isBoolean = value => value === true || value === false;
92+
if (isBoolean(v) || (opts.arrayOk && Array.isArray(v) && v.length > 0 && v.every(isBoolean))) {
93+
propOut.set(v);
94+
} else {
95+
propOut.set(dflt);
96+
}
9397
}
9498
},
9599
number: {
@@ -225,14 +229,15 @@ exports.valObjectMeta = {
225229
'\'geo\', \'geo2\', \'geo3\', ...'
226230
].join(' '),
227231
requiredOpts: ['dflt'],
228-
otherOpts: ['regex'],
232+
otherOpts: ['regex', 'arrayOk'],
229233
coerceFunction: function(v, propOut, dflt, opts) {
230234
var regex = opts.regex || counterRegex(dflt);
231-
if(typeof v === 'string' && regex.test(v)) {
235+
const isSubplotId = value => typeof value === 'string' && regex.test(value);
236+
if (isSubplotId(v) || (opts.arrayOk && isArrayOrTypedArray(v) && v.length > 0 && v.every(isSubplotId))) {
232237
propOut.set(v);
233-
return;
238+
} else {
239+
propOut.set(dflt);
234240
}
235-
propOut.set(dflt);
236241
},
237242
validateFunction: function(v, opts) {
238243
var dflt = opts.dflt;

src/plots/plots.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,8 +1254,10 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
12541254
_module.attributes.showlegend ? _module.attributes : plots.attributes,
12551255
'showlegend'
12561256
);
1257-
1258-
coerce('legend');
1257+
Lib.coerce(traceIn, traceOut,
1258+
_module.attributes.legend ? _module.attributes : plots.attributes,
1259+
'legend'
1260+
);
12591261
coerce('legendwidth');
12601262
coerce('legendgroup');
12611263
coerce('legendgrouptitle.text');

src/traces/pie/attributes.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,24 @@ module.exports = {
180180
editType: 'plot',
181181
description: ['Determines whether outside text labels can push the margins.'].join(' ')
182182
},
183-
183+
showlegend: extendFlat({}, baseAttrs.showlegend, {
184+
arrayOk: true,
185+
description: [
186+
'Determines whether or not items corresponding to the pie slices are shown in the',
187+
'legend. Can be an array if `values` is set. In that case, each entry specifies',
188+
'appearance in the legend for one slice.'
189+
].join(' ')
190+
}),
191+
legend: extendFlat({}, baseAttrs.legend, {
192+
arrayOk: true,
193+
description: [
194+
'Sets the reference to a legend to show the pie slices in. Can be an array if `values`',
195+
'is set. In that case, each entry specifies the legend reference for one slice.',
196+
'References to these legends are *legend*, *legend2*, *legend3*, etc.',
197+
'Settings for these legends are set in the layout, under',
198+
'`layout.legend`, `layout.legend2`, etc.'
199+
].join(' ')
200+
}),
184201
title: {
185202
text: {
186203
valType: 'string',
26.5 KB
Loading
27 KB
Loading
20.6 KB
Loading

0 commit comments

Comments
 (0)