Skip to content

Commit 235e967

Browse files
authored
Merge pull request #5591 from plotly/legendrank
Implement legendrank attribute in traces
2 parents fd1a26a + a1abb19 commit 235e967

File tree

9 files changed

+462
-41
lines changed

9 files changed

+462
-41
lines changed

src/components/legend/get_legend_data.js

+59-21
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ var Registry = require('../../registry');
44
var helpers = require('./helpers');
55

66
module.exports = function getLegendData(calcdata, opts) {
7+
var grouped = helpers.isGrouped(opts);
8+
var reversed = helpers.isReversed(opts);
9+
710
var lgroupToTraces = {};
811
var lgroups = [];
912
var hasOneNonBlankGroup = false;
@@ -18,14 +21,14 @@ module.exports = function getLegendData(calcdata, opts) {
1821
// TODO: check this against fullData legendgroups?
1922
var uniqueGroup = '~~i' + lgroupi;
2023
lgroups.push(uniqueGroup);
21-
lgroupToTraces[uniqueGroup] = [[legendItem]];
24+
lgroupToTraces[uniqueGroup] = [legendItem];
2225
lgroupi++;
2326
} else if(lgroups.indexOf(legendGroup) === -1) {
2427
lgroups.push(legendGroup);
2528
hasOneNonBlankGroup = true;
26-
lgroupToTraces[legendGroup] = [[legendItem]];
29+
lgroupToTraces[legendGroup] = [legendItem];
2730
} else {
28-
lgroupToTraces[legendGroup].push([legendItem]);
31+
lgroupToTraces[legendGroup].push(legendItem);
2932
}
3033
}
3134

@@ -66,31 +69,66 @@ module.exports = function getLegendData(calcdata, opts) {
6669
// won't draw a legend in this case
6770
if(!lgroups.length) return [];
6871

69-
// rearrange lgroupToTraces into a d3-friendly array of arrays
70-
var lgroupsLength = lgroups.length;
71-
var ltraces;
72-
var legendData;
73-
74-
if(hasOneNonBlankGroup && helpers.isGrouped(opts)) {
75-
legendData = new Array(lgroupsLength);
72+
// collapse all groups into one if all groups are blank
73+
var shouldCollapse = !hasOneNonBlankGroup || !grouped;
7674

77-
for(i = 0; i < lgroupsLength; i++) {
78-
ltraces = lgroupToTraces[lgroups[i]];
79-
legendData[i] = helpers.isReversed(opts) ? ltraces.reverse() : ltraces;
75+
var legendData = [];
76+
for(i = 0; i < lgroups.length; i++) {
77+
var t = lgroupToTraces[lgroups[i]];
78+
if(shouldCollapse) {
79+
legendData.push(t[0]);
80+
} else {
81+
legendData.push(t);
8082
}
81-
} else {
82-
// collapse all groups into one if all groups are blank
83-
legendData = [new Array(lgroupsLength)];
83+
}
84+
if(shouldCollapse) legendData = [legendData];
85+
86+
for(i = 0; i < legendData.length; i++) {
87+
// find minimum rank within group
88+
var groupMinRank = Infinity;
89+
for(j = 0; j < legendData[i].length; j++) {
90+
var rank = legendData[i][j].trace.legendrank;
91+
if(groupMinRank > rank) groupMinRank = rank;
92+
}
93+
94+
// record on first group element
95+
legendData[i][0]._groupMinRank = groupMinRank;
96+
legendData[i][0]._preGroupSort = i;
97+
}
8498

85-
for(i = 0; i < lgroupsLength; i++) {
86-
ltraces = lgroupToTraces[lgroups[i]][0];
87-
legendData[0][helpers.isReversed(opts) ? lgroupsLength - i - 1 : i] = ltraces;
99+
var orderFn1 = function(a, b) {
100+
return (
101+
(a[0]._groupMinRank - b[0]._groupMinRank) ||
102+
(a[0]._preGroupSort - b[0]._preGroupSort) // fallback for old Chrome < 70 https://bugs.chromium.org/p/v8/issues/detail?id=90
103+
);
104+
};
105+
106+
var orderFn2 = function(a, b) {
107+
return (
108+
(a.trace.legendrank - b.trace.legendrank) ||
109+
(a._preSort - b._preSort) // fallback for old Chrome < 70 https://bugs.chromium.org/p/v8/issues/detail?id=90
110+
);
111+
};
112+
113+
// sort considering minimum group legendrank
114+
legendData.forEach(function(a, k) { a[0]._preGroupSort = k; });
115+
legendData.sort(orderFn1);
116+
for(i = 0; i < legendData.length; i++) {
117+
// sort considering trace.legendrank and legend.traceorder
118+
legendData[i].forEach(function(a, k) { a._preSort = k; });
119+
legendData[i].sort(orderFn2);
120+
if(reversed) legendData[i].reverse();
121+
122+
// rearrange lgroupToTraces into a d3-friendly array of arrays
123+
for(j = 0; j < legendData[i].length; j++) {
124+
legendData[i][j] = [
125+
legendData[i][j]
126+
];
88127
}
89-
lgroupsLength = 1;
90128
}
91129

92130
// number of legend groups - needed in legend/draw.js
93-
opts._lgroupsLength = lgroupsLength;
131+
opts._lgroupsLength = legendData.length;
94132
// maximum name/label length - needed in legend/draw.js
95133
opts._maxNameLength = maxNameLength;
96134

src/plots/attributes.js

+13
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ module.exports = {
4141
'when toggling legend items.'
4242
].join(' ')
4343
},
44+
legendrank: {
45+
valType: 'number',
46+
dflt: 1000,
47+
editType: 'style',
48+
description: [
49+
'Sets the legend rank for this trace.',
50+
'Items and groups with smaller ranks are presented on top/left side while',
51+
'with `*reversed* `legend.traceorder` they are on bottom/right side.',
52+
'The default legendrank is 1000,',
53+
'so that you can use ranks less than 1000 to place certain items before all unranked items,',
54+
'and ranks greater than 1000 to go after all unranked items.'
55+
].join(' ')
56+
},
4457
opacity: {
4558
valType: 'number',
4659
min: 0,

src/plots/plots.js

+1
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOut, colorIndex, layout, trac
13091309
);
13101310

13111311
coerce('legendgroup');
1312+
coerce('legendrank');
13121313

13131314
traceOut._dfltShowLegend = true;
13141315
} else {

src/traces/parcats/attributes.js

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ module.exports = {
198198
hoverlabel: undefined,
199199
ids: undefined,
200200
legendgroup: undefined,
201+
legendrank: undefined,
201202
opacity: undefined,
202203
selectedpoints: undefined,
203204
showlegend: undefined

test/image/baselines/legendrank.png

14.7 KB
Loading

test/image/baselines/legendrank2.png

10.6 KB
Loading

test/image/mocks/legendrank.json

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"data": [
3+
{"type": "bar", "name": "1", "y": [1], "yaxis": "y2", "legendgroup": "two", "legendrank": 3},
4+
{
5+
"legendrank": 2,
6+
"legendgroup": "pie",
7+
"type": "pie",
8+
"labels": ["a","b","c","c","c","a"],
9+
"textinfo": "none",
10+
"domain": {
11+
"x": [0, 0.45],
12+
"y": [0.35, 0.65]
13+
}
14+
},
15+
{
16+
"legendrank": 1,
17+
"legendgroup": "pie",
18+
"type": "pie",
19+
"labels": ["z","x","x","x","y", "y"],
20+
"sort": false,
21+
"textinfo": "none",
22+
"domain": {
23+
"x": [0.55, 1],
24+
"y": [0.35, 0.65]
25+
}
26+
},
27+
{"type": "scatter", "name": "2", "y": [2], "yaxis": "y", "legendgroup": "one", "legendrank": 2},
28+
{"type": "scatter", "name": "1", "y": [1], "yaxis": "y", "legendgroup": "one", "legendrank": 1},
29+
{"type": "bar", "name": "2", "y": [2], "yaxis": "y2", "legendgroup": "two", "legendrank": 2},
30+
{"type": "scatter", "name": "3", "y": [3], "yaxis": "y", "legendgroup": "one", "legendrank": 3},
31+
{"type": "bar", "name": "3", "y": [3], "yaxis": "y2", "legendgroup": "two", "legendrank": 1}
32+
],
33+
"layout": {
34+
"title": {
35+
"text": "legendrank"
36+
},
37+
"hovermode": "x unified",
38+
"margin": {
39+
"t": 50
40+
},
41+
"width": 300,
42+
"height": 400,
43+
"yaxis2": {
44+
"domain": [0.7, 1]
45+
},
46+
"yaxis": {
47+
"autorange": "reversed",
48+
"domain": [0, 0.3]
49+
}
50+
}
51+
}

test/image/mocks/legendrank2.json

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"data": [
3+
{
4+
"name": "A",
5+
"legendrank": 2,
6+
"y": [-2]
7+
},
8+
{
9+
"name": "D",
10+
"legendrank": 4,
11+
"y": [-4],
12+
"legendgroup": "bottom"
13+
},
14+
{
15+
"name": "E",
16+
"legendrank": 4,
17+
"y": [-4],
18+
"legendgroup": "bottom"
19+
},
20+
{
21+
"name": "B",
22+
"legendrank": 1,
23+
"y": [-1],
24+
"legendgroup": "top"
25+
},
26+
{
27+
"name": "C",
28+
"legendrank": 3,
29+
"y": [-3],
30+
"legendgroup": "top"
31+
}
32+
],
33+
"layout": {
34+
"title": {
35+
"text": "rank groups using<br>minimum of the group"
36+
},
37+
"width": 300,
38+
"height": 300,
39+
"margin": {
40+
"b": 25
41+
},
42+
"hovermode": "x unified"
43+
}
44+
}

0 commit comments

Comments
 (0)