Skip to content

Commit 8a5c655

Browse files
committed
relative-stack bars within the same trace that would otherwise be hidden
... under barmode:'group'
1 parent 9b7cd8d commit 8a5c655

File tree

4 files changed

+122
-0
lines changed

4 files changed

+122
-0
lines changed

src/traces/bar/cross_trace_calc.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ function setGroupPositionsInGroupMode(gd, pa, sa, calcTraces) {
198198
// set bar offsets and widths, and update position axis
199199
setOffsetAndWidthInGroupMode(gd, pa, sieve);
200200

201+
// relative-stack bars within the same trace that would otherwise
202+
// be hidden
203+
unhideBarsWithinTrace(gd, sa, sieve);
204+
201205
// set bar bases and sizes, and update size axis
202206
if(barnorm) {
203207
sieveBars(gd, sa, sieve);
@@ -578,6 +582,36 @@ function sieveBars(gd, sa, sieve) {
578582
}
579583
}
580584

585+
function unhideBarsWithinTrace(gd, sa, sieve) {
586+
var calcTraces = sieve.traces;
587+
588+
for(var i = 0; i < calcTraces.length; i++) {
589+
var calcTrace = calcTraces[i];
590+
var fullTrace = calcTrace[0].trace;
591+
592+
if(fullTrace.base === undefined) {
593+
var inTraceSieve = new Sieve([calcTrace], {
594+
separateNegativeValues: true,
595+
dontMergeOverlappingData: true
596+
});
597+
598+
for(var j = 0; j < calcTrace.length; j++) {
599+
var bar = calcTrace[j];
600+
601+
if(bar.p !== BADNUM) {
602+
// stack current bar and get previous sum
603+
var barBase = inTraceSieve.put(bar.p, bar.b + bar.s);
604+
605+
// if previous sum if non-zero, this means:
606+
// multiple bars have same starting point are potentially hidden,
607+
// shift them vertically so that all bars are visible by default
608+
if(barBase) bar.b = barBase;
609+
}
610+
}
611+
}
612+
}
613+
}
614+
581615
// Note:
582616
//
583617
// normalizeBars requires that either sieveBars or stackBars has been

test/image/baselines/bar_unhidden.png

8.42 KB
Loading

test/image/mocks/bar_unhidden.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"data": [
3+
{
4+
"type": "bar",
5+
"x": [ 0, 0, 0 ],
6+
"y": [ 1, 1, -1 ],
7+
"marker": {
8+
"color": [ "red", "green", "blue" ]
9+
}
10+
},
11+
{
12+
"type": "bar",
13+
"x": [ 0, 0, 0 ],
14+
"y": [ 1, 1, -1 ],
15+
"marker": {
16+
"color": [ "cyan", "magenta", "yellow" ]
17+
}
18+
}
19+
],
20+
"layout": {
21+
"margin": { "t": 30, "b": 30, "l": 30, "r": 30 },
22+
"width": 400,
23+
"height": 400,
24+
"showlegend": false,
25+
"hovermode": "closest"
26+
}
27+
}

test/jasmine/tests/bar_test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,67 @@ describe('Bar.crossTraceCalc (formerly known as setPositions)', function() {
926926
expect(gd._fullLayout.xaxis.type).toBe('multicategory');
927927
assertPointField(gd.calcdata, 'b', [[0, 0, 0, 0]]);
928928
});
929+
930+
describe('should relative-stack bar within the same trace that overlap under barmode=group', function() {
931+
it('- base case', function() {
932+
var gd = mockBarPlot([{
933+
x: [0, 0, 0],
934+
y: [1, -2, -1]
935+
}]);
936+
937+
assertPointField(gd.calcdata, 'b', [[0, 0, -2]]);
938+
assertPointField(gd.calcdata, 'y', [[1, -2, -3]]);
939+
});
940+
941+
it('- with blank positions', function() {
942+
var gd = mockBarPlot([{
943+
x: [0, null, 0, null, 0],
944+
y: [1, null, -2, null, -1]
945+
}]);
946+
947+
assertPointField(gd.calcdata, 'b', [[0, 0, 0, 0, -2]]);
948+
assertPointField(gd.calcdata, 'y', [[1, NaN, -2, NaN, -3]]);
949+
});
950+
951+
it('- with barnorm set', function() {
952+
var gd = mockBarPlot([{
953+
x: [0, 0, 0],
954+
y: [1, -2, -1],
955+
}], {
956+
barnorm: 'fraction'
957+
});
958+
959+
assertPointField(gd.calcdata, 'b', [[0, 0, -0.5]]);
960+
assertPointField(gd.calcdata, 'y', [[0.25, -0.5, -0.75]]);
961+
});
962+
963+
it('- skipped when base is set', function() {
964+
var gd = mockBarPlot([{
965+
x: [0, 0, 0],
966+
y: [1, -2, -1],
967+
base: 10
968+
}, {
969+
x: [0, 0, 0],
970+
y: [1, -2, -1],
971+
base: [1, 2, 1]
972+
}]);
973+
974+
assertPointField(gd.calcdata, 'b', [[10, 10, 10], [1, 2, 1]]);
975+
assertPointField(gd.calcdata, 'y', [[11, 8, 9], [2, 0, 0]]);
976+
});
977+
978+
it('- skipped when barmode=overlay', function() {
979+
var gd = mockBarPlot([{
980+
x: [0, 0, 0],
981+
y: [1, -2, -1]
982+
}], {
983+
barmode: 'overlay'
984+
});
985+
986+
assertPointField(gd.calcdata, 'b', [[0, 0, 0]]);
987+
assertPointField(gd.calcdata, 'y', [[1, -2, -1]]);
988+
});
989+
});
929990
});
930991

931992
describe('A bar plot', function() {

0 commit comments

Comments
 (0)