diff --git a/src/traces/bar/set_positions.js b/src/traces/bar/set_positions.js index dbc68616224..2a670a63536 100644 --- a/src/traces/bar/set_positions.js +++ b/src/traces/bar/set_positions.js @@ -148,8 +148,11 @@ module.exports = function setPositions(gd, plotinfo) { if(!isNumeric(ti[j].s)) continue; sv = Math.round(ti[j].p / sumround); - // store the negative sum value for p at the same key, with sign flipped - if(relative && ti[j].s < 0) sv = -sv; + + // store the negative sum value for p at the same key, + // with sign flipped using string to ensure -0 !== 0. + if(relative && ti[j].s < 0) sv = '-' + sv; + var previousSum = sums[sv] || 0; if(stack || relative) ti[j].b = previousSum; barEnd = ti[j].b + ti[j].s; @@ -167,20 +170,29 @@ module.exports = function setPositions(gd, plotinfo) { } if(norm) { - padded = false; var top = norm === 'fraction' ? 1 : 100, relAndNegative = false, tiny = top / 1e9; // in case of rounding error in sum + + padded = false; sMin = 0; sMax = stack ? top : 0; + for(i = 0; i < bl.length; i++) { // trace index ti = gd.calcdata[bl[i]]; + for(j = 0; j < ti.length; j++) { - relAndNegative = relative && ti[j].s < 0; + relAndNegative = (relative && ti[j].s < 0); + sv = Math.round(ti[j].p / sumround); - if(relAndNegative) sv = -sv; // locate negative sum amount for this p val + + // locate negative sum amount for this p val + if(relAndNegative) sv = '-' + sv; + scale = top / sums[sv]; - if(relAndNegative) scale *= -1; // preserve sign if negative + + // preserve sign if negative + if(relAndNegative) scale *= -1; ti[j].b *= scale; ti[j].s *= scale; barEnd = ti[j].b + ti[j].s; diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 365891170d9..be35de30694 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -183,4 +183,44 @@ describe('heatmap calc / setPositions', function() { assertTraceField(out, 't.dbar', [1, 1]); }); + it('should fill in calc pt fields (relative case)', function() { + var out = _calc([{ + y: [20, 14, -23] + }, { + y: [-12, -18, -29] + }], { + barmode: 'relative' + }); + + assertPtField(out, 'x', [[0, 1, 2], [0, 1, 2]]); + assertPtField(out, 'y', [[20, 14, -23], [-12, -18, -52]]); + assertPtField(out, 'b', [[0, 0, 0], [0, 0, -23]]); + assertPtField(out, 's', [[20, 14, -23], [-12, -18, -29]]); + assertPtField(out, 'p', [[0, 1, 2], [0, 1, 2]]); + assertTraceField(out, 't.barwidth', [0.8, 0.8]); + assertTraceField(out, 't.poffset', [-0.4, -0.4]); + assertTraceField(out, 't.dbar', [1, 1]); + }); + + it('should fill in calc pt fields (relative / percent case)', function() { + var out = _calc([{ + x: ['A', 'B', 'C', 'D'], + y: [20, 14, 40, -60] + }, { + x: ['A', 'B', 'C', 'D'], + y: [-12, -18, 60, -40] + }], { + barmode: 'relative', + barnorm: 'percent' + }); + + assertPtField(out, 'x', [[0, 1, 2, 3], [0, 1, 2, 3]]); + assertPtField(out, 'y', [[100, 100, 40, -60], [-100, -100, 100, -100]]); + assertPtField(out, 'b', [[0, 0, 0, 0], [0, 0, 40, -60]]); + assertPtField(out, 's', [[100, 100, 40, -60], [-100, -100, 60, -40]]); + assertPtField(out, 'p', [[0, 1, 2, 3], [0, 1, 2, 3]]); + assertTraceField(out, 't.barwidth', [0.8, 0.8]); + assertTraceField(out, 't.poffset', [-0.4, -0.4]); + assertTraceField(out, 't.dbar', [1, 1]); + }); });