Skip to content

Commit 3781f48

Browse files
authored
Merge pull request #5072 from plotly/fix5058-overlay-missing-category
Set width of categorical bars & boxes to category unit i.e. 1
2 parents eae3bda + 081cb77 commit 3781f48

File tree

6 files changed

+83
-4
lines changed

6 files changed

+83
-4
lines changed

src/lib/search.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ exports.sorterDes = function(a, b) { return b - a; };
7171
* just be off by a rounding error
7272
* return the distinct values and the minimum difference between any two
7373
*/
74-
exports.distinctVals = function(valsIn) {
74+
exports.distinctVals = function(valsIn, opts) {
75+
var unitMinDiff = (opts || {}).unitMinDiff;
76+
7577
var vals = valsIn.slice(); // otherwise we sort the original array...
7678
vals.sort(exports.sorterAsc); // undefined listed in the end - also works on IE11
7779

@@ -80,7 +82,9 @@ exports.distinctVals = function(valsIn) {
8082
if(vals[last] !== BADNUM) break;
8183
}
8284

83-
var minDiff = (vals[last] - vals[0]) || 1;
85+
var minDiff = 1;
86+
if(!unitMinDiff) minDiff = (vals[last] - vals[0]) || 1;
87+
8488
var errDiff = minDiff / (last || 1) / 10000;
8589
var newVals = [];
8690
var preV;

src/traces/bar/cross_trace_calc.js

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ function crossTraceCalc(gd, plotinfo) {
5959
}
6060

6161
var opts = {
62+
xCat: xa.type === 'category' || xa.type === 'multicategory',
63+
yCat: ya.type === 'category' || ya.type === 'multicategory',
64+
6265
mode: fullLayout.barmode,
6366
norm: fullLayout.barnorm,
6467
gap: fullLayout.bargap,
@@ -177,6 +180,7 @@ function setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts) {
177180
var calcTrace = calcTraces[i];
178181

179182
var sieve = new Sieve([calcTrace], {
183+
unitMinDiff: opts.xCat || opts.yCat,
180184
sepNegVal: false,
181185
overlapNoMerge: !opts.norm
182186
});

src/traces/bar/sieve.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ function Sieve(traces, opts) {
4848
}
4949
this.positions = positions;
5050

51-
var dv = distinctVals(positions);
51+
var dv = distinctVals(positions, {
52+
unitMinDiff: opts.unitMinDiff
53+
});
54+
5255
this.distinctPositions = dv.vals;
5356
if(dv.vals.length === 1 && width1 !== Infinity) this.minDiff = width1;
5457
else this.minDiff = Math.min(dv.minDiff, width1);

src/traces/box/cross_trace_calc.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ function setPositionOffset(traceType, gd, boxList, posAxis) {
6868
if(!pointList.length) return;
6969

7070
// box plots - update dPos based on multiple traces
71-
var boxdv = Lib.distinctVals(pointList);
71+
var boxdv = Lib.distinctVals(pointList, {
72+
unitMinDiff: posAxis.type === 'category' || posAxis.type === 'multicategory'
73+
});
74+
7275
var dPos0 = boxdv.minDiff / 2;
7376

7477
// check for forced minimum dtick

test/jasmine/tests/bar_test.js

+17
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,23 @@ describe('Bar.crossTraceCalc (formerly known as setPositions)', function() {
969969
assertPointField(gd.calcdata, 'b', [[0, 0, 0, 0]]);
970970
});
971971

972+
it('should set unit width for categories in overlay mode', function() {
973+
var gd = mockBarPlot([{
974+
type: 'bar',
975+
x: ['a', 'b', 'c'],
976+
y: [2, 2, 2]
977+
},
978+
{
979+
type: 'bar',
980+
x: ['a', 'c'],
981+
y: [1, 1]
982+
}], {
983+
barmode: 'overlay'
984+
});
985+
986+
expect(gd.calcdata[1][0].t.bardelta).toBe(1);
987+
});
988+
972989
describe('should relative-stack bar within the same trace that overlap under barmode=group', function() {
973990
it('- base case', function() {
974991
var gd = mockBarPlot([{

test/jasmine/tests/box_test.js

+48
Original file line numberDiff line numberDiff line change
@@ -1534,3 +1534,51 @@ describe('Test box calc', function() {
15341534
});
15351535
});
15361536
});
1537+
1538+
1539+
describe('Box crossTraceCalc', function() {
1540+
'use strict';
1541+
1542+
function mockBoxPlot(dataWithoutTraceType, layout) {
1543+
var traceTemplate = { type: 'box' };
1544+
1545+
var dataWithTraceType = dataWithoutTraceType.map(function(trace) {
1546+
return Lib.extendFlat({}, traceTemplate, trace);
1547+
});
1548+
1549+
var gd = {
1550+
data: dataWithTraceType,
1551+
layout: layout || {},
1552+
calcdata: [],
1553+
_context: {locale: 'en', locales: {}}
1554+
};
1555+
1556+
supplyAllDefaults(gd);
1557+
Plots.doCalcdata(gd);
1558+
1559+
return gd;
1560+
}
1561+
1562+
it('should set unit width for categories in overlay mode', function() {
1563+
var gd = mockBoxPlot([{
1564+
y: [1, 2, 3]
1565+
},
1566+
{
1567+
y: [null, null, null]
1568+
},
1569+
{
1570+
y: [null, null, null]
1571+
},
1572+
{
1573+
y: [4, 5, 6]
1574+
}], {
1575+
boxgap: 0,
1576+
xaxis: {
1577+
range: [-0.5, 3.5],
1578+
type: 'category'
1579+
}
1580+
});
1581+
1582+
expect(gd.calcdata[0][0].t.dPos).toBe(0.5);
1583+
});
1584+
});

0 commit comments

Comments
 (0)