Skip to content

Commit 7a1c0e5

Browse files
committed
Correct percentages at root
- simplify sunburst and treemap percentage references - add hovertemplate tests to treemap - fixup sunburst jasmine texttemplate tests
1 parent 24ac0ec commit 7a1c0e5

File tree

5 files changed

+215
-49
lines changed

5 files changed

+215
-49
lines changed

src/traces/sunburst/fx.js

+11-18
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
2424
var cd0 = cd[0];
2525
var trace = cd0.trace;
2626
var hierarchy = cd0.hierarchy;
27-
var rootLabel = hierarchy.data.data.pid;
28-
var readLabel = function(refPt) {
29-
var l = helpers.getPtLabel(refPt);
30-
return l === undefined ? rootLabel : l;
31-
};
3227

3328
var isSunburst = trace.type === 'sunburst';
3429
var isTreemap = trace.type === 'treemap';
@@ -53,7 +48,7 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
5348
var isRoot = helpers.isHierarchyRoot(pt);
5449
var parent = helpers.getParent(hierarchy, pt);
5550

56-
var val = helpers.getVal(pt);
51+
var val = helpers.getValue(pt);
5752

5853
var _cast = function(astr) {
5954
return Lib.castOption(traceNow, ptNumber, astr);
@@ -109,24 +104,22 @@ module.exports = function attachFxHandlers(sliceTop, entry, gd, cd, opts) {
109104
}
110105
};
111106

112-
if(parent) {
113-
hoverPt.percentParent = pt.percentParent = val / helpers.getVal(parent);
114-
hoverPt.parent = pt.parentString = readLabel(parent);
115-
if(hasFlag('percent parent')) {
116-
tx = helpers.formatPercent(hoverPt.percentParent, separators) + ' of ' + hoverPt.parent;
117-
insertPercent();
118-
}
107+
hoverPt.percentParent = pt.percentParent = val / helpers.getValue(parent);
108+
hoverPt.parent = pt.parentString = helpers.getPtLabel(parent);
109+
if(hasFlag('percent parent')) {
110+
tx = helpers.formatPercent(hoverPt.percentParent, separators) + ' of ' + hoverPt.parent;
111+
insertPercent();
119112
}
120113

121-
hoverPt.percentEntry = pt.percentEntry = val / helpers.getVal(entry);
122-
hoverPt.entry = pt.entry = readLabel(entry);
114+
hoverPt.percentEntry = pt.percentEntry = val / helpers.getValue(entry);
115+
hoverPt.entry = pt.entry = helpers.getPtLabel(entry);
123116
if(hasFlag('percent entry') && !isRoot && !pt.onPathbar) {
124117
tx = helpers.formatPercent(hoverPt.percentEntry, separators) + ' of ' + hoverPt.entry;
125118
insertPercent();
126119
}
127120

128-
hoverPt.percentRoot = pt.percentRoot = val / helpers.getVal(hierarchy);
129-
hoverPt.root = pt.root = readLabel(hierarchy);
121+
hoverPt.percentRoot = pt.percentRoot = val / helpers.getValue(hierarchy);
122+
hoverPt.root = pt.root = helpers.getPtLabel(hierarchy);
130123
if(hasFlag('percent root') && !isRoot) {
131124
tx = helpers.formatPercent(hoverPt.percentRoot, separators) + ' of ' + hoverPt.root;
132125
insertPercent();
@@ -307,7 +300,7 @@ function makeEventData(pt, trace, keys) {
307300
if(key in pt) out[key] = pt[key];
308301
}
309302
// handle special case of parent
310-
if('parentString' in pt) out.parent = pt.parentString;
303+
if('parentString' in pt && !helpers.isHierarchyRoot(pt)) out.parent = pt.parentString;
311304

312305
appendArrayPointValue(out, trace, cdi.i);
313306

src/traces/sunburst/helpers.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ exports.getPtId = function(pt) {
5252
};
5353

5454
exports.getPtLabel = function(pt) {
55-
return pt.data.data.label;
55+
var label = pt.data.data.label;
56+
return label === undefined ? pt.data.data.pid : label;
5657
};
5758

58-
exports.getVal = function(d) {
59+
exports.getValue = function(d) {
5960
return d.value;
6061
};
6162

@@ -152,10 +153,7 @@ function getParentId(pt) {
152153
}
153154

154155
exports.getParent = function(hierarchy, pt) {
155-
var parentId = getParentId(pt);
156-
return parentId === '' ?
157-
undefined :
158-
exports.findEntryWithLevel(hierarchy, parentId);
156+
return exports.findEntryWithLevel(hierarchy, getParentId(pt));
159157
};
160158

161159
exports.listPath = function(d, keyStr) {

src/traces/sunburst/plot.js

+14-22
Original file line numberDiff line numberDiff line change
@@ -488,15 +488,9 @@ exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) {
488488
var cd0 = cd[0];
489489
var cdi = pt.data.data;
490490
var hierarchy = cd0.hierarchy;
491-
var rootLabel = hierarchy.data.data.pid;
492-
var readLabel = function(refPt) {
493-
var l = helpers.getPtLabel(refPt);
494-
return l === undefined ? rootLabel : l;
495-
};
496-
497491
var isRoot = helpers.isHierarchyRoot(pt);
498492
var parent = helpers.getParent(hierarchy, pt);
499-
var val = helpers.getVal(pt);
493+
var val = helpers.getValue(pt);
500494

501495
if(!texttemplate) {
502496
var parts = textinfo.split('+');
@@ -532,16 +526,16 @@ exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) {
532526
thisText.push(tx);
533527
};
534528

535-
if(hasFlag('percent parent') && parent) {
536-
percent = val / helpers.getVal(parent);
529+
if(hasFlag('percent parent')) {
530+
percent = val / helpers.getValue(parent);
537531
addPercent('parent');
538532
}
539533
if(hasFlag('percent entry')) {
540-
percent = val / helpers.getVal(entry);
534+
percent = val / helpers.getValue(entry);
541535
addPercent('entry');
542536
}
543537
if(hasFlag('percent root')) {
544-
percent = val / helpers.getVal(hierarchy);
538+
percent = val / helpers.getValue(hierarchy);
545539
addPercent('root');
546540
}
547541
}
@@ -566,25 +560,23 @@ exports.formatSliceLabel = function(pt, entry, trace, cd, fullLayout) {
566560

567561
obj.currentPath = helpers.getPath(pt.data);
568562

569-
if(parent) {
570-
obj.percentParent = val / helpers.getVal(parent);
571-
obj.percentParentLabel = helpers.formatPercent(
572-
obj.percentParent, separators
573-
);
574-
obj.parent = readLabel(parent);
575-
}
563+
obj.percentParent = val / helpers.getValue(parent);
564+
obj.percentParentLabel = helpers.formatPercent(
565+
obj.percentParent, separators
566+
);
567+
obj.parent = helpers.getPtLabel(parent);
576568

577-
obj.percentEntry = val / helpers.getVal(entry);
569+
obj.percentEntry = val / helpers.getValue(entry);
578570
obj.percentEntryLabel = helpers.formatPercent(
579571
obj.percentEntry, separators
580572
);
581-
obj.entry = readLabel(entry);
573+
obj.entry = helpers.getPtLabel(entry);
582574

583-
obj.percentRoot = val / helpers.getVal(hierarchy);
575+
obj.percentRoot = val / helpers.getValue(hierarchy);
584576
obj.percentRootLabel = helpers.formatPercent(
585577
obj.percentRoot, separators
586578
);
587-
obj.root = readLabel(hierarchy);
579+
obj.root = helpers.getPtLabel(hierarchy);
588580

589581
if(cdi.hasOwnProperty('color')) {
590582
obj.color = cdi.color;

test/jasmine/tests/sunburst_test.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,7 @@ describe('Test sunburst texttemplate without `values` should work at root level:
13451345
['path: %{currentPath}', ['path: /', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve', 'path: Eve/Seth', 'path: Eve/Seth/', 'path: Eve/Awan/']],
13461346
['%{percentRoot} of %{root}', ['100% of Eve', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve']],
13471347
['%{percentEntry} of %{entry}', ['100% of Eve', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve']],
1348-
['%{percentParent} of %{parent}', ['%{percentParent} of %{parent}', '100% of Seth', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '50% of Seth', '100% of Awan']],
1348+
['%{percentParent} of %{parent}', ['100% of Eve', '100% of Seth', '33% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '17% of Eve', '50% of Seth', '100% of Awan']],
13491349
[
13501350
[
13511351
'label: %{label}',
@@ -1389,7 +1389,7 @@ describe('Test sunburst texttemplate with *total* `values` should work at root l
13891389
['path: %{currentPath}', ['path: /', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve', 'path: Eve/Seth', 'path: Eve/Seth/', 'path: Eve/Awan/']],
13901390
['%{percentRoot} of %{root}', ['100% of Eve', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '15% of Eve', '3% of Eve', '2% of Eve']],
13911391
['%{percentEntry} of %{entry}', ['100% of Eve', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '15% of Eve', '3% of Eve', '2% of Eve']],
1392-
['%{percentParent} of %{parent}', ['%{percentParent} of %{parent}', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '83% of Seth', '17% of Seth', '17% of Awan']],
1392+
['%{percentParent} of %{parent}', ['100% of Eve', '22% of Eve', '18% of Eve', '9% of Eve', '9% of Eve', '6% of Eve', '83% of Seth', '17% of Seth', '17% of Awan']],
13931393
[
13941394
[
13951395
'label: %{label}',
@@ -1433,7 +1433,7 @@ describe('Test sunburst texttemplate with *remainder* `values` should work at ro
14331433
['path: %{currentPath}', ['path: /', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve/', 'path: Eve', 'path: Eve/Seth', 'path: Eve/Seth/', 'path: Eve/Awan/']],
14341434
['%{percentRoot} of %{root}', ['100% of Eve', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '8% of Eve', '2% of Eve', '1% of Eve']],
14351435
['%{percentEntry} of %{entry}', ['100% of Eve', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '8% of Eve', '2% of Eve', '1% of Eve']],
1436-
['%{percentParent} of %{parent}', ['%{percentParent} of %{parent}', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '42% of Seth', '8% of Seth', '14% of Awan']],
1436+
['%{percentParent} of %{parent}', ['100% of Eve', '20% of Eve', '12% of Eve', '6% of Eve', '5% of Eve', '3% of Eve', '42% of Seth', '8% of Seth', '14% of Awan']],
14371437
[
14381438
[
14391439
'label: %{label}',

test/jasmine/tests/treemap_test.js

+183
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,189 @@ describe('Test treemap hover:', function() {
629629
});
630630
});
631631

632+
describe('Test treemap hover with levels', function() {
633+
var gd;
634+
635+
var labels0 = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform', 'Victor', 'Whiskey', 'X ray', 'Yankee', 'Zulu'];
636+
var parents0 = ['', 'Alpha', 'Alpha', 'Charlie', 'Charlie', 'Charlie', 'Foxtrot', 'Foxtrot', 'Foxtrot', 'Foxtrot', 'Juliet', 'Juliet', 'Juliet', 'Juliet', 'Juliet', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Uniform', 'Uniform', 'Uniform', 'Uniform', 'Uniform', 'Uniform'];
637+
var values0 = [40, 2, 38, 1.5, 2.5, 34, 1, 2, 3, 28, 1.25, 1.75, 2.25, 2.75, 20, 1, 1.5, 2, 2.5, 3, 10, 1, 1.5, 2, 2.5, 3];
638+
var text0 = ['forty', 'two', 'thirty-eight', 'one and a half', 'two and a half', 'thirty-four', 'one', 'two', 'three', 'twenty-eight', 'one and twenty-five hundredths', 'one and seventy-five hundredths', 'two and twenty-five hundredths', 'two and seventy-five hundredths', 'twenty', 'one', 'one and a half', 'two', 'two and a half', 'three', 'ten', 'one', 'one and a half', 'two', 'two and a half', 'three'];
639+
640+
afterEach(destroyGraphDiv);
641+
642+
function run(spec) {
643+
gd = createGraphDiv();
644+
645+
var data = (spec.traces || [{}]).map(function(t) {
646+
t.type = 'treemap';
647+
t.text = text0;
648+
t.values = values0;
649+
t.level = 'Oscar';
650+
t.branchvalues = 'total';
651+
t.hovertemplate = 'path = %{currentPath}<br>label = %{label}<br>text = %{text}<br>value = %{value}<br>ratio to %{parent} = %{percentParent}<br>ratio to %{entry} = %{percentEntry}<br>ratio to %{root} = %{percentRoot}';
652+
653+
if(!t.labels) t.labels = labels0.slice();
654+
if(!t.parents) t.parents = parents0.slice();
655+
return t;
656+
});
657+
658+
var layout = Lib.extendFlat({
659+
width: 500,
660+
height: 500,
661+
margin: {t: 0, b: 0, l: 0, r: 0, pad: 0}
662+
}, spec.layout || {});
663+
664+
var exp = spec.exp || {};
665+
var ptData = null;
666+
667+
return Plotly.plot(gd, data, layout)
668+
.then(function() {
669+
gd.once('plotly_hover', function(d) { ptData = d.points[0]; });
670+
})
671+
.then(hover(gd, spec.pos))
672+
.then(function() {
673+
assertHoverLabelContent(exp.label);
674+
675+
for(var k in exp.ptData) {
676+
expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k);
677+
}
678+
679+
if(exp.style) {
680+
var gd3 = d3.select(gd);
681+
assertHoverLabelStyle(gd3.select('.hovertext'), exp.style);
682+
}
683+
});
684+
}
685+
686+
[{
687+
desc: 'entry',
688+
pos: 0,
689+
exp: {
690+
label: {
691+
name: 'trace 0',
692+
nums: 'path = Alpha/Charlie/Foxtrot/Juliet/\nlabel = Oscar\ntext = twenty\nvalue = 20\nratio to Juliet = 0.7142857142857143\nratio to Oscar = 1\nratio to Alpha = 0.5',
693+
},
694+
ptData: {
695+
curveNumber: 0,
696+
pointNumber: 14,
697+
label: 'Oscar',
698+
parent: 'Juliet'
699+
}
700+
}
701+
}, {
702+
desc: 'leaf',
703+
pos: 10,
704+
exp: {
705+
label: {
706+
name: 'trace 0',
707+
nums: 'path = Alpha/Charlie/Foxtrot/Juliet/Oscar/Uniform/\nlabel = X ray\ntext = two\nvalue = 2\nratio to Uniform = 0.2\nratio to Oscar = 0.1\nratio to Alpha = 0.05',
708+
},
709+
ptData: {
710+
curveNumber: 0,
711+
pointNumber: 23,
712+
label: 'X ray',
713+
parent: 'Uniform'
714+
}
715+
}
716+
}]
717+
.forEach(function(spec) {
718+
it('should generate correct hover labels and event data - ' + spec.desc, function(done) {
719+
run(spec).catch(failTest).then(done);
720+
});
721+
});
722+
});
723+
724+
describe('Test treemap hover at root level', function() {
725+
var gd;
726+
727+
var labels0 = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliet', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Tango', 'Uniform', 'Victor', 'Whiskey', 'X ray', 'Yankee', 'Zulu'];
728+
var parents0 = ['', 'Alpha', 'Alpha', 'Charlie', 'Charlie', 'Charlie', 'Foxtrot', 'Foxtrot', 'Foxtrot', 'Foxtrot', 'Juliet', 'Juliet', 'Juliet', 'Juliet', 'Juliet', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Oscar', 'Uniform', 'Uniform', 'Uniform', 'Uniform', 'Uniform', 'Uniform'];
729+
var values0 = [40, 2, 38, 1.5, 2.5, 34, 1, 2, 3, 28, 1.25, 1.75, 2.25, 2.75, 20, 1, 1.5, 2, 2.5, 3, 10, 1, 1.5, 2, 2.5, 3];
730+
var text0 = ['forty', 'two', 'thirty-eight', 'one and a half', 'two and a half', 'thirty-four', 'one', 'two', 'three', 'twenty-eight', 'one and twenty-five hundredths', 'one and seventy-five hundredths', 'two and twenty-five hundredths', 'two and seventy-five hundredths', 'twenty', 'one', 'one and a half', 'two', 'two and a half', 'three', 'ten', 'one', 'one and a half', 'two', 'two and a half', 'three'];
731+
732+
afterEach(destroyGraphDiv);
733+
734+
function run(spec) {
735+
gd = createGraphDiv();
736+
737+
var data = (spec.traces || [{}]).map(function(t) {
738+
t.type = 'treemap';
739+
t.text = text0;
740+
t.values = values0;
741+
t.branchvalues = 'total';
742+
t.hovertemplate = 'path = %{currentPath}<br>label = %{label}<br>text = %{text}<br>value = %{value}<br>ratio to %{parent} = %{percentParent}<br>ratio to %{entry} = %{percentEntry}<br>ratio to %{root} = %{percentRoot}';
743+
744+
if(!t.labels) t.labels = labels0.slice();
745+
if(!t.parents) t.parents = parents0.slice();
746+
return t;
747+
});
748+
749+
var layout = Lib.extendFlat({
750+
width: 500,
751+
height: 500,
752+
margin: {t: 0, b: 0, l: 0, r: 0, pad: 0}
753+
}, spec.layout || {});
754+
755+
var exp = spec.exp || {};
756+
var ptData = null;
757+
758+
return Plotly.plot(gd, data, layout)
759+
.then(function() {
760+
gd.once('plotly_hover', function(d) { ptData = d.points[0]; });
761+
})
762+
.then(hover(gd, spec.pos))
763+
.then(function() {
764+
assertHoverLabelContent(exp.label);
765+
766+
for(var k in exp.ptData) {
767+
expect(ptData[k]).toBe(exp.ptData[k], 'pt event data key ' + k);
768+
}
769+
770+
if(exp.style) {
771+
var gd3 = d3.select(gd);
772+
assertHoverLabelStyle(gd3.select('.hovertext'), exp.style);
773+
}
774+
});
775+
}
776+
777+
[{
778+
desc: 'entry',
779+
pos: 0,
780+
exp: {
781+
label: {
782+
name: 'trace 0',
783+
nums: 'path = /\nlabel = Alpha\ntext = forty\nvalue = 40\nratio to = 1\nratio to Alpha = 1\nratio to Alpha = 1',
784+
},
785+
ptData: {
786+
curveNumber: 0,
787+
pointNumber: 0,
788+
label: 'Alpha',
789+
parent: ''
790+
}
791+
}
792+
}, {
793+
desc: 'leaf',
794+
pos: 10,
795+
exp: {
796+
label: {
797+
name: 'trace 0',
798+
nums: 'path = Alpha/Charlie/Foxtrot/\nlabel = Golf\ntext = one\nvalue = 1\nratio to Foxtrot = 0.029411764705882353\nratio to Alpha = 0.025\nratio to Alpha = 0.025',
799+
},
800+
ptData: {
801+
curveNumber: 0,
802+
pointNumber: 6,
803+
label: 'Golf',
804+
parent: 'Foxtrot'
805+
}
806+
}
807+
}]
808+
.forEach(function(spec) {
809+
it('should generate correct hover labels and event data - ' + spec.desc, function(done) {
810+
run(spec).catch(failTest).then(done);
811+
});
812+
});
813+
});
814+
632815
describe('Test treemap hover lifecycle:', function() {
633816
var gd;
634817
var hoverData;

0 commit comments

Comments
 (0)