Skip to content

Commit 7769f20

Browse files
committed
implement violinmode, violingroup and violingroupgap
- totally indenpendent from their box* counterpart
1 parent 1eb453b commit 7769f20

File tree

8 files changed

+135
-80
lines changed

8 files changed

+135
-80
lines changed

src/traces/box/calc.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ module.exports = function calc(gd, trace) {
1818
var fullLayout = gd._fullLayout;
1919
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
2020
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
21-
var orientation = trace.orientation;
2221
var cd = [];
2322

24-
var numKey = '_numBoxes';
23+
// N.B. violin reuses same Box.calc
24+
var numKey = trace.type === 'violin' ? '_numViolins' : '_numBoxes';
2525

2626
var i;
2727
var valAxis, valLetter;
2828
var posAxis, posLetter;
2929

30-
if(orientation === 'h') {
30+
if(trace.orientation === 'h') {
3131
valAxis = xa;
3232
valLetter = 'x';
3333
posAxis = ya;
@@ -119,7 +119,9 @@ module.exports = function calc(gd, trace) {
119119
if(cd.length > 0) {
120120
cd[0].t = {
121121
num: fullLayout[numKey],
122-
dPos: dPos
122+
dPos: dPos,
123+
posLetter: posLetter,
124+
valLetter: valLetter
123125
};
124126

125127
fullLayout[numKey]++;

src/traces/box/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Box.layoutAttributes = require('./layout_attributes');
1515
Box.supplyDefaults = require('./defaults').supplyDefaults;
1616
Box.supplyLayoutDefaults = require('./layout_defaults').supplyLayoutDefaults;
1717
Box.calc = require('./calc');
18-
Box.setPositions = require('./set_positions');
18+
Box.setPositions = require('./set_positions').setPositions;
1919
Box.plot = require('./plot').plot;
2020
Box.style = require('./style');
2121
Box.hoverPoints = require('./hover').hoverPoints;

src/traces/box/layout_defaults.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,22 @@
88

99
'use strict';
1010

11-
var Registry = require('../../registry');
1211
var Lib = require('../../lib');
1312
var layoutAttributes = require('./layout_attributes');
1413

15-
function _supply(layoutIn, layoutOut, fullData, coerce, prefix) {
16-
var hasBoxes;
14+
function _supply(layoutIn, layoutOut, fullData, coerce, traceType) {
15+
var hasTraceType;
1716
for(var i = 0; i < fullData.length; i++) {
18-
if(Registry.traceIs(fullData[i], 'box')) {
19-
hasBoxes = true;
17+
if(fullData[i].type === traceType) {
18+
hasTraceType = true;
2019
break;
2120
}
2221
}
23-
if(!hasBoxes) return;
22+
if(!hasTraceType) return;
2423

25-
coerce(prefix + 'mode');
26-
coerce(prefix + 'gap');
27-
coerce(prefix + 'groupgap');
24+
coerce(traceType + 'mode');
25+
coerce(traceType + 'gap');
26+
coerce(traceType + 'groupgap');
2827
}
2928

3029
function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {

src/traces/box/set_positions.js

+70-63
Original file line numberDiff line numberDiff line change
@@ -8,95 +8,102 @@
88

99
'use strict';
1010

11-
var Registry = require('../../registry');
1211
var Axes = require('../../plots/cartesian/axes');
1312
var Lib = require('../../lib');
1413

15-
module.exports = function setPositions(gd, plotinfo) {
16-
var fullLayout = gd._fullLayout;
14+
var orientations = ['v', 'h'];
15+
16+
function setPositions(gd, plotinfo) {
17+
var calcdata = gd.calcdata;
1718
var xa = plotinfo.xaxis;
1819
var ya = plotinfo.yaxis;
19-
var orientations = ['v', 'h'];
20-
21-
// TODO figure this out
22-
// should violins and boxes share 'num' fields?
23-
var numKey = '_numBoxes';
24-
25-
var posAxis, i, j, k;
2620

27-
for(i = 0; i < orientations.length; ++i) {
28-
var orientation = orientations[i],
29-
boxlist = [],
30-
boxpointlist = [],
31-
minPad = 0,
32-
maxPad = 0,
33-
cd,
34-
t,
35-
trace;
36-
37-
// set axis via orientation
38-
if(orientation === 'h') posAxis = ya;
39-
else posAxis = xa;
21+
for(var i = 0; i < orientations.length; i++) {
22+
var orientation = orientations[i];
23+
var posAxis = orientation === 'h' ? ya : xa;
24+
var boxList = [];
25+
var minPad = 0;
26+
var maxPad = 0;
4027

4128
// make list of boxes
42-
for(j = 0; j < gd.calcdata.length; ++j) {
43-
cd = gd.calcdata[j];
44-
t = cd[0].t;
45-
trace = cd[0].trace;
29+
for(var j = 0; j < calcdata.length; j++) {
30+
var cd = calcdata[j];
31+
var t = cd[0].t;
32+
var trace = cd[0].trace;
4633

4734
if(trace.visible === true && trace.type === 'box' &&
4835
!t.empty &&
4936
trace.orientation === orientation &&
5037
trace.xaxis === xa._id &&
51-
trace.yaxis === ya._id) {
52-
boxlist.push(j);
38+
trace.yaxis === ya._id
39+
) {
40+
boxList.push(j);
41+
5342
if(trace.boxpoints !== false) {
5443
minPad = Math.max(minPad, trace.jitter - trace.pointpos - 1);
5544
maxPad = Math.max(maxPad, trace.jitter + trace.pointpos - 1);
5645
}
5746
}
5847
}
5948

60-
// make list of box points
61-
for(j = 0; j < boxlist.length; j++) {
62-
cd = gd.calcdata[boxlist[j]];
63-
for(k = 0; k < cd.length; k++) boxpointlist.push(cd[k].pos);
64-
}
65-
if(!boxpointlist.length) continue;
49+
setPositionOffset('box', gd, boxList, posAxis, [minPad, maxPad]);
50+
}
51+
}
6652

67-
// box plots - update dPos based on multiple traces
68-
// and then use for posAxis autorange
53+
function setPositionOffset(traceType, gd, boxList, posAxis, pad) {
54+
var calcdata = gd.calcdata;
55+
var fullLayout = gd._fullLayout;
56+
var pointList = [];
57+
58+
// N.B. reused in violin
59+
var numKey = traceType === 'violin' ? '_numViolins' : '_numBoxes';
6960

70-
var boxdv = Lib.distinctVals(boxpointlist);
71-
var dPos = boxdv.minDiff / 2;
61+
var i, j, calcTrace;
7262

73-
// if there's no duplication of x points,
74-
// disable 'group' mode by setting counter to 1
75-
if(boxpointlist.length === boxdv.vals.length) {
76-
fullLayout[numKey] = 1;
63+
// make list of box points
64+
for(i = 0; i < boxList.length; i++) {
65+
calcTrace = calcdata[boxList[i]];
66+
for(j = 0; j < calcTrace.length; j++) {
67+
pointList.push(calcTrace[j].pos);
7768
}
69+
}
7870

79-
// check for forced minimum dtick
80-
Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true);
71+
if(!pointList.length) return;
8172

82-
// set the width of all boxes
83-
for(i = 0; i < boxlist.length; i++) {
84-
var boxListIndex = boxlist[i];
85-
gd.calcdata[boxListIndex][0].t.dPos = dPos;
86-
}
73+
// box plots - update dPos based on multiple traces
74+
// and then use for posAxis autorange
75+
var boxdv = Lib.distinctVals(pointList);
76+
var dPos = boxdv.minDiff / 2;
8777

88-
// TODO this won't work when both boxes and violins are present
89-
// on same graph
90-
var gap = fullLayout.boxgap || fullLayout.violingap;
91-
var groupgap = fullLayout.boxgroupgap || fullLayout.violingroupgap;
92-
93-
// autoscale the x axis - including space for points if they're off the side
94-
// TODO: this will overdo it if the outermost boxes don't have
95-
// their points as far out as the other boxes
96-
var padfactor = (1 - gap) * (1 - groupgap) * dPos / fullLayout[numKey];
97-
Axes.expand(posAxis, boxdv.vals, {
98-
vpadminus: dPos + minPad * padfactor,
99-
vpadplus: dPos + maxPad * padfactor
100-
});
78+
// if there's no duplication of x points,
79+
// disable 'group' mode by setting counter to 1
80+
if(pointList.length === boxdv.vals.length) {
81+
fullLayout[numKey] = 1;
10182
}
83+
84+
// check for forced minimum dtick
85+
Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true);
86+
87+
// set the width of all boxes
88+
for(i = 0; i < boxList.length; i++) {
89+
calcTrace = calcdata[boxList[i]];
90+
calcTrace[0].t.dPos = dPos;
91+
}
92+
93+
var gap = fullLayout[traceType + 'gap'];
94+
var groupgap = fullLayout[traceType + 'groupgap'];
95+
var padfactor = (1 - gap) * (1 - groupgap) * dPos / fullLayout[numKey];
96+
97+
// autoscale the x axis - including space for points if they're off the side
98+
// TODO: this will overdo it if the outermost boxes don't have
99+
// their points as far out as the other boxes
100+
Axes.expand(posAxis, boxdv.vals, {
101+
vpadminus: dPos + pad[0] * padfactor,
102+
vpadplus: dPos + pad[1] * padfactor
103+
});
104+
}
105+
106+
module.exports = {
107+
setPositions: setPositions,
108+
setPositionOffset: setPositionOffset
102109
};

src/traces/violin/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module.exports = {
1414
supplyDefaults: require('./defaults'),
1515
supplyLayoutDefaults: require('./layout_defaults'),
1616
calc: require('./calc'),
17-
setPositions: require('../box/set_positions'),
17+
setPositions: require('./set_positions'),
1818
plot: require('./plot'),
1919
style: require('./style'),
2020
hoverPoints: require('../box/hover'),

src/traces/violin/layout_attributes.js

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
var boxLayoutAttrs = require('../box/layout_attributes');
1212

1313
// TODO update descriptions
14-
// ... or maybe just reuse box* attributes?
1514
module.exports = {
1615
violinmode: boxLayoutAttrs.boxmode,
1716
violingap: boxLayoutAttrs.boxgap,

src/traces/violin/plot.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module.exports = function plot(gd, plotinfo, cd) {
3030
var t = cd0.t;
3131
var trace = cd0.trace;
3232
var sel = cd0.node3 = d3.select(this);
33-
var numViolins = fullLayout._numBoxes;
33+
var numViolins = fullLayout._numViolins;
3434
var group = (fullLayout.violinmode === 'group' && numViolins > 1);
3535
// violin max half width
3636
var bdPos = t.bdPos = t.dPos * (1 - fullLayout.violingap) * (1 - fullLayout.violingroupgap) / (group ? numViolins : 1);

src/traces/violin/set_positions.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Copyright 2012-2017, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var setPositionOffset = require('../box/set_positions').setPositionOffset;
12+
var orientations = ['v', 'h'];
13+
14+
module.exports = function setPositions(gd, plotinfo) {
15+
var calcdata = gd.calcdata;
16+
var xa = plotinfo.xaxis;
17+
var ya = plotinfo.yaxis;
18+
19+
for(var i = 0; i < orientations.length; i++) {
20+
var orientation = orientations[i];
21+
var posAxis = orientation === 'h' ? ya : xa;
22+
var violinList = [];
23+
var minPad = 0;
24+
var maxPad = 0;
25+
26+
for(var j = 0; j < calcdata.length; j++) {
27+
var cd = calcdata[j];
28+
var t = cd[0].t;
29+
var trace = cd[0].trace;
30+
31+
if(trace.visible === true && trace.type === 'violin' &&
32+
!t.empty &&
33+
trace.orientation === orientation &&
34+
trace.xaxis === xa._id &&
35+
trace.yaxis === ya._id
36+
) {
37+
violinList.push(j);
38+
39+
if(trace.points !== false) {
40+
minPad = Math.max(minPad, trace.jitter - trace.pointpos - 1);
41+
maxPad = Math.max(maxPad, trace.jitter + trace.pointpos - 1);
42+
}
43+
}
44+
}
45+
46+
setPositionOffset('violin', gd, violinList, posAxis, [minPad, maxPad]);
47+
}
48+
};

0 commit comments

Comments
 (0)