diff --git a/src/lib/search.js b/src/lib/search.js index 738864f330d..c85ed5f975d 100644 --- a/src/lib/search.js +++ b/src/lib/search.js @@ -62,9 +62,7 @@ exports.sorterDes = function(a, b) { return b - a; }; * just be off by a rounding error * return the distinct values and the minimum difference between any two */ -exports.distinctVals = function(valsIn, opts) { - var unitMinDiff = (opts || {}).unitMinDiff; - +exports.distinctVals = function(valsIn) { var vals = valsIn.slice(); // otherwise we sort the original array... vals.sort(exports.sorterAsc); // undefined listed in the end - also works on IE11 @@ -73,9 +71,7 @@ exports.distinctVals = function(valsIn, opts) { if(vals[last] !== BADNUM) break; } - var minDiff = 1; - if(!unitMinDiff) minDiff = (vals[last] - vals[0]) || 1; - + var minDiff = (vals[last] - vals[0]) || 1; var errDiff = minDiff / (last || 1) / 10000; var newVals = []; var preV; diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 00e14812244..f1cad80924d 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -172,7 +172,7 @@ function setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts) { var calcTrace = calcTraces[i]; var sieve = new Sieve([calcTrace], { - unitMinDiff: opts.xCat || opts.yCat, + posAxis: pa, sepNegVal: false, overlapNoMerge: !opts.norm }); @@ -196,6 +196,7 @@ function setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts) { function setGroupPositionsInGroupMode(gd, pa, sa, calcTraces, opts) { var sieve = new Sieve(calcTraces, { + posAxis: pa, sepNegVal: false, overlapNoMerge: !opts.norm }); @@ -205,7 +206,7 @@ function setGroupPositionsInGroupMode(gd, pa, sa, calcTraces, opts) { // relative-stack bars within the same trace that would otherwise // be hidden - unhideBarsWithinTrace(sieve); + unhideBarsWithinTrace(sieve, pa); // set bar bases and sizes, and update size axis if(opts.norm) { @@ -218,6 +219,7 @@ function setGroupPositionsInGroupMode(gd, pa, sa, calcTraces, opts) { function setGroupPositionsInStackOrRelativeMode(gd, pa, sa, calcTraces, opts) { var sieve = new Sieve(calcTraces, { + posAxis: pa, sepNegVal: opts.mode === 'relative', overlapNoMerge: !(opts.norm || opts.mode === 'stack' || opts.mode === 'relative') }); @@ -610,7 +612,7 @@ function sieveBars(sieve) { } } -function unhideBarsWithinTrace(sieve) { +function unhideBarsWithinTrace(sieve, pa) { var calcTraces = sieve.traces; for(var i = 0; i < calcTraces.length; i++) { @@ -619,6 +621,7 @@ function unhideBarsWithinTrace(sieve) { if(fullTrace.base === undefined) { var inTraceSieve = new Sieve([calcTrace], { + posAxis: pa, sepNegVal: true, overlapNoMerge: true }); diff --git a/src/traces/bar/sieve.js b/src/traces/bar/sieve.js index 14e994f34a1..ad7eec482f8 100644 --- a/src/traces/bar/sieve.js +++ b/src/traces/bar/sieve.js @@ -40,14 +40,17 @@ function Sieve(traces, opts) { } this.positions = positions; - var dv = distinctVals(positions, { - unitMinDiff: opts.unitMinDiff - }); + var dv = distinctVals(positions); this.distinctPositions = dv.vals; if(dv.vals.length === 1 && width1 !== Infinity) this.minDiff = width1; else this.minDiff = Math.min(dv.minDiff, width1); + var type = (opts.posAxis || {}).type; + if(type === 'category' || type === 'multicategory') { + this.minDiff = 1; + } + this.binWidth = this.minDiff; this.bins = {}; diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js index f08e80f8713..2b810f07679 100644 --- a/src/traces/box/calc.js +++ b/src/traces/box/calc.js @@ -40,7 +40,7 @@ module.exports = function calc(gd, trace) { var allPosArrays = getPosArrays(trace, posLetter, posAxis, fullLayout[numKey]); var posArray = allPosArrays[0]; var origPos = allPosArrays[1]; - var dv = Lib.distinctVals(posArray); + var dv = Lib.distinctVals(posArray, posAxis); var posDistinct = dv.vals; var dPos = dv.minDiff / 2; diff --git a/src/traces/box/cross_trace_calc.js b/src/traces/box/cross_trace_calc.js index 34eb60528ac..00632d0dbb2 100644 --- a/src/traces/box/cross_trace_calc.js +++ b/src/traces/box/cross_trace_calc.js @@ -60,9 +60,10 @@ function setPositionOffset(traceType, gd, boxList, posAxis) { if(!pointList.length) return; // box plots - update dPos based on multiple traces - var boxdv = Lib.distinctVals(pointList, { - unitMinDiff: posAxis.type === 'category' || posAxis.type === 'multicategory' - }); + var boxdv = Lib.distinctVals(pointList); + if(posAxis.type === 'category' || posAxis.type === 'multicategory') { + boxdv.minDiff = 1; + } var dPos0 = boxdv.minDiff / 2; diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 62d74d99d71..3379549953c 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -981,12 +981,10 @@ describe('Bar.crossTraceCalc (formerly known as setPositions)', function() { it('should set unit width for categories in overlay mode', function() { var gd = mockBarPlot([{ - type: 'bar', x: ['a', 'b', 'c'], y: [2, 2, 2] }, { - type: 'bar', x: ['a', 'c'], y: [1, 1] }], { @@ -996,6 +994,20 @@ describe('Bar.crossTraceCalc (formerly known as setPositions)', function() { expect(gd.calcdata[1][0].t.bardelta).toBe(1); }); + it('should set unit width for categories case of missing data for defined category', function() { + var gd = mockBarPlot([{ + x: ['a', 'c'], + y: [1, 2] + }, { + x: ['a', 'c'], + y: [1, 2], + }], { + xaxis: { categoryarray: ['a', 'b', 'c'] } + }); + + expect(gd.calcdata[1][0].t.bardelta).toBe(1); + }); + describe('should relative-stack bar within the same trace that overlap under barmode=group', function() { it('- base case', function() { var gd = mockBarPlot([{