Skip to content
Open
1 change: 1 addition & 0 deletions draftlogs/7580_add.md
Original file line number Diff line number Diff line change
@@ -0,0 +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)]
57 changes: 51 additions & 6 deletions src/components/legend/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,44 @@ function groupDefaults(legendId, layoutIn, layoutOut, fullData) {

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

function isPieWithLegendArray(trace) {
return Registry.traceIs(trace, 'pie-like')
&& trace._length != null
&& (Array.isArray(trace.legend) || Array.isArray(trace.showlegend));
};
fullData
.filter(isPieWithLegendArray)
.map(function (trace, idx) {
if (trace.visible) {
legendTraceCount++;
}
for(var index = 0; index < trace._length; index++) {
var legend = (Array.isArray(trace.legend) ? trace.legend[index] : trace.legend) || 'legend';
if(legend === legendId) {
// showlegend can be undefined, boolean or a boolean array.
// will fall back to default if undefined or if array index is out-of-range
if(
!Array.isArray(trace.showlegend)
? trace.showlegend || trace._dfltShowLegend
: trace.showlegend[index] == null
? trace._dfltShowLegend
: trace.showlegend[index]
) {
legendReallyHasATrace = true;
legendTraceCount++;
}
}
}
if(legendId === 'legend' && trace._length > trace.legend.length) {
for(var idx = trace.legend.length; idx < trace._length; idx++) {
legendReallyHasATrace = true;
legendTraceCount++;
}
}
});

var allLegendItems = fullData.concat(shapesWithLegend).filter(function(d) {
return legendId === (d.legend || 'legend');
return !isPieWithLegendArray(trace) && legendId === (d.legend || 'legend');
});

for(var i = 0; i < allLegendItems.length; i++) {
Expand Down Expand Up @@ -82,7 +118,6 @@ function groupDefaults(legendId, layoutIn, layoutOut, fullData) {

Lib.coerceFont(traceCoerce, 'legendgrouptitle.font', grouptitlefont);
}

if((!isShape && Registry.traceIs(trace, 'bar') && layoutOut.barmode === 'stack') ||
['tonextx', 'tonexty'].indexOf(trace.fill) !== -1) {
defaultOrder = helpers.isGrouped({ traceorder: defaultOrder }) ?
Expand All @@ -95,9 +130,15 @@ function groupDefaults(legendId, layoutIn, layoutOut, fullData) {
}
}

var showLegend = Lib.coerce(layoutIn, layoutOut,
basePlotLayoutAttributes, 'showlegend',
legendReallyHasATrace && (legendTraceCount > (legendId === 'legend' ? 1 : 0)));
var showLegend = Lib.coerce(
layoutIn,
layoutOut,
basePlotLayoutAttributes,
'showlegend',
layoutOut.showlegend ||
(legendReallyHasATrace &&
legendTraceCount > (legendId === 'legend' ? 1 : 0))
);

// delete legend
if(showLegend === false) layoutOut[legendId] = undefined;
Expand Down Expand Up @@ -230,7 +271,11 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {

var legends = ['legend'];
for(i = 0; i < allLegendsData.length; i++) {
Lib.pushUnique(legends, allLegendsData[i].legend);
if (Array.isArray(allLegendsData[i].legend)) {
Lib.extendFlat(legends, allLegendsData[i].legend);
} else {
Lib.pushUnique(legends, allLegendsData[i].legend);
}
}

layoutOut._legends = [];
Expand Down
6 changes: 5 additions & 1 deletion src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,11 @@ function textLayout(s, g, gd, legendObj, aTitle) {

function computeTextDimensions(g, gd, legendObj, aTitle) {
var legendItem = g.data()[0][0];
if(!legendObj._inHover && legendItem && !legendItem.trace.showlegend) {
var showlegend = legendItem && legendItem.trace.showlegend;
if (Array.isArray(showlegend)) {
showlegend = showlegend[legendItem.i] !== false;
}
if(!legendObj._inHover && legendItem && !showlegend) {
g.remove();
return;
}
Expand Down
8 changes: 8 additions & 0 deletions src/components/legend/get_legend_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,17 @@ module.exports = function getLegendData(calcdata, opts, hasMultipleLegends) {
if(!inHover && (!trace.visible || !trace.showlegend)) continue;

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

for(j = 0; j < cd.length; j++) {
if (showlegendPerSlice && trace.showlegend[cd[j].i] === false) {
continue;
}
if (legendPerSlice) {
lid = trace.legend[cd[j].i] || 'legend';
}
var labelj = cd[j].label;

if(!slicesShown[lgroup][labelj]) {
Expand Down
8 changes: 6 additions & 2 deletions src/lib/coerce.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ exports.valObjectMeta = {
boolean: {
description: 'A boolean (true/false) value.',
requiredOpts: [],
otherOpts: ['dflt'],
otherOpts: ['dflt', 'arrayOk'],
coerceFunction: function(v, propOut, dflt) {
if(v === true || v === false) propOut.set(v);
else propOut.set(dflt);
Expand Down Expand Up @@ -225,8 +225,12 @@ exports.valObjectMeta = {
'\'geo\', \'geo2\', \'geo3\', ...'
].join(' '),
requiredOpts: ['dflt'],
otherOpts: ['regex'],
otherOpts: ['regex', 'arrayOk'],
coerceFunction: function(v, propOut, dflt, opts) {
if(opts.arrayOk && isArrayOrTypedArray(v)) {
propOut.set(v);
return;
}
var regex = opts.regex || counterRegex(dflt);
if(typeof v === 'string' && regex.test(v)) {
propOut.set(v);
Expand Down
6 changes: 4 additions & 2 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -1254,8 +1254,10 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
_module.attributes.showlegend ? _module.attributes : plots.attributes,
'showlegend'
);

coerce('legend');
Lib.coerce(traceIn, traceOut,
_module.attributes.legend ? _module.attributes : plots.attributes,
'legend'
);
coerce('legendwidth');
coerce('legendgroup');
coerce('legendgrouptitle.text');
Expand Down
7 changes: 6 additions & 1 deletion src/traces/pie/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,12 @@ module.exports = {
'Determines whether outside text labels can push the margins.'
].join(' ')
},

showlegend: extendFlat({}, baseAttrs.showlegend, {
arrayOk: true
}),
legend: extendFlat({}, baseAttrs.legend, {
arrayOk: true
}),
title: {
text: {
valType: 'string',
Expand Down
Binary file added test/image/baselines/zz-pie-slice-legend.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/zz-pie-slice-legend2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions test/image/mocks/zz-pie-slice-legend.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"data": [
{
"labels": [
"with",
"pie",
"multiple",
"hidden",
"legends",
"A",
"hidden too"
],
"values": [3, 4, 2, 7, 1, 5, 8],
"type": "pie",
"showlegend": [true, true, true, false, true, true, false],
"legend": ["legend2", "legend", "legend2", "legend4", "legend3", "legend", "legend4"]
}
],
"layout": {
"title": {
"text": "Test array version of 'showlegend' and 'legend'"
},
"width": 400,
"height": 400,
"legend": {
"title": {
"text": "L1"
},
"y": 1
},
"legend2": {
"title": {
"text": "L2"
},
"y": 0.7
},
"legend3": {
"title": {
"text": "L3"
},
"y": 0.2
},
"legend4": {
"title": {
"text": "L4"
},
"y": 0
}
}
}
50 changes: 50 additions & 0 deletions test/image/mocks/zz-pie-slice-legend2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"data": [
{
"labels": [
"with",
"multiple",
"hidden",
"legends",
"A",
"hidden too",
"pie"
],
"values": [3, 2, 7, 1, 5, 8, 4],
"type": "pie",
"showlegend": [true, true, false, true, true, false],
"legend": ["legend2", "legend2", "legend4", "legend3", "legend", "legend4"]
}
],
"layout": {
"title": {
"text": "Test short array version of 'showlegend' and 'legend'"
},
"width": 450,
"height": 400,
"legend": {
"title": {
"text": "L1"
},
"y": 1
},
"legend2": {
"title": {
"text": "L2"
},
"y": 0.7
},
"legend3": {
"title": {
"text": "L3"
},
"y": 0.2
},
"legend4": {
"title": {
"text": "L4"
},
"y": 0
}
}
}
18 changes: 16 additions & 2 deletions test/plot-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,8 @@
"boolean": {
"description": "A boolean (true/false) value.",
"otherOpts": [
"dflt"
"dflt",
"arrayOk"
],
"requiredOpts": []
},
Expand Down Expand Up @@ -549,7 +550,8 @@
"subplotid": {
"description": "An id string of a subplot type (given by dflt), optionally followed by an integer >1. e.g. if dflt='geo', we can have 'geo', 'geo2', 'geo3', ...",
"otherOpts": [
"regex"
"regex",
"arrayOk"
],
"requiredOpts": [
"dflt"
Expand Down Expand Up @@ -56338,6 +56340,7 @@
"valType": "string"
},
"legend": {
"arrayOk": true,
"description": "Sets the reference to a legend to show this trace in. References to these legends are *legend*, *legend2*, *legend3*, etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.",
"dflt": "legend",
"editType": "style",
Expand Down Expand Up @@ -56454,6 +56457,11 @@
"editType": "style",
"valType": "number"
},
"legendsrc": {
"description": "Sets the source reference on Chart Studio Cloud for `legend`.",
"editType": "none",
"valType": "string"
},
"legendwidth": {
"description": "Sets the width (in px or fraction) of the legend for this trace.",
"editType": "style",
Expand Down Expand Up @@ -56801,11 +56809,17 @@
"valType": "string"
},
"showlegend": {
"arrayOk": true,
"description": "Determines whether or not an item corresponding to this trace is shown in the legend.",
"dflt": true,
"editType": "style",
"valType": "boolean"
},
"showlegendsrc": {
"description": "Sets the source reference on Chart Studio Cloud for `showlegend`.",
"editType": "none",
"valType": "string"
},
"sort": {
"description": "Determines whether or not the sectors are reordered from largest to smallest.",
"dflt": true,
Expand Down