Skip to content

Commit 26ea20c

Browse files
authored
Merge pull request #915 from plotly/boxpoints-no-range
Boxpoints no range
2 parents fd6ba1d + ae7bcab commit 26ea20c

File tree

3 files changed

+61
-16
lines changed

3 files changed

+61
-16
lines changed

Diff for: src/traces/box/plot.js

+29-16
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ module.exports = function plot(gd, plotinfo, cdbox) {
132132
.data(function(d) {
133133
var pts = (trace.boxpoints === 'all') ? d.val :
134134
d.val.filter(function(v) { return (v < d.lf || v > d.uf); }),
135-
spreadLimit = (d.q3 - d.q1) * JITTERSPREAD,
135+
// normally use IQR, but if this is 0 or too small, use max-min
136+
typicalSpread = Math.max((d.max - d.min) / 10, d.q3 - d.q1),
137+
minSpread = typicalSpread * 1e-9,
138+
spreadLimit = typicalSpread * JITTERSPREAD,
136139
jitterFactors = [],
137140
maxJitterFactor = 0,
138141
i,
@@ -144,22 +147,32 @@ module.exports = function plot(gd, plotinfo, cdbox) {
144147

145148
// dynamic jitter
146149
if(trace.jitter) {
147-
for(i = 0; i < pts.length; i++) {
148-
i0 = Math.max(0, i - JITTERCOUNT);
149-
pmin = pts[i0];
150-
i1 = Math.min(pts.length - 1, i + JITTERCOUNT);
151-
pmax = pts[i1];
152-
153-
if(trace.boxpoints !== 'all') {
154-
if(pts[i] < d.lf) pmax = Math.min(pmax, d.lf);
155-
else pmin = Math.max(pmin, d.uf);
150+
if(typicalSpread === 0) {
151+
// edge case of no spread at all: fall back to max jitter
152+
maxJitterFactor = 1;
153+
jitterFactors = new Array(pts.length);
154+
for(i = 0; i < pts.length; i++) {
155+
jitterFactors[i] = 1;
156+
}
157+
}
158+
else {
159+
for(i = 0; i < pts.length; i++) {
160+
i0 = Math.max(0, i - JITTERCOUNT);
161+
pmin = pts[i0];
162+
i1 = Math.min(pts.length - 1, i + JITTERCOUNT);
163+
pmax = pts[i1];
164+
165+
if(trace.boxpoints !== 'all') {
166+
if(pts[i] < d.lf) pmax = Math.min(pmax, d.lf);
167+
else pmin = Math.max(pmin, d.uf);
168+
}
169+
170+
jitterFactor = Math.sqrt(spreadLimit * (i1 - i0) / (pmax - pmin + minSpread)) || 0;
171+
jitterFactor = Lib.constrain(Math.abs(jitterFactor), 0, 1);
172+
173+
jitterFactors.push(jitterFactor);
174+
maxJitterFactor = Math.max(jitterFactor, maxJitterFactor);
156175
}
157-
158-
jitterFactor = Math.sqrt(spreadLimit * (i1 - i0) / (pmax - pmin)) || 0;
159-
jitterFactor = Lib.constrain(Math.abs(jitterFactor), 0, 1);
160-
161-
jitterFactors.push(jitterFactor);
162-
maxJitterFactor = Math.max(jitterFactor, maxJitterFactor);
163176
}
164177
newJitter = trace.jitter * 2 / maxJitterFactor;
165178
}

Diff for: test/image/baselines/box_plot_jitter_edge_cases.png

26.2 KB
Loading

Diff for: test/image/mocks/box_plot_jitter_edge_cases.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"data": [
3+
{
4+
"y": [0,0,2.4,0,0,2,0,0,0,0,0,0,62,0,0,0,13,0,0,0,0,38,0,0,0,0,0,0,0,0],
5+
"type": "box",
6+
"boxpoints": "all",
7+
"jitter": 0,
8+
"name": "No whiskers, no jitter"
9+
},
10+
{
11+
"y": [0,0,2.4,0,0,2,0,0,0,0,0,0,62,0,0,0,13,0,0,0,0,38,0,0,0,0,0,0,0,0],
12+
"type": "box",
13+
"boxpoints": "all",
14+
"jitter": 0.5,
15+
"name": "No whiskers, jitter 0.5"
16+
},
17+
{
18+
"y": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
19+
"type": "box",
20+
"boxpoints": "all",
21+
"jitter": 0,
22+
"name": "No range, no jitter"
23+
},
24+
{
25+
"y": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
26+
"type": "box",
27+
"boxpoints": "all",
28+
"jitter": 0.5,
29+
"name": "No range, jitter 0.5"
30+
}
31+
]
32+
}

0 commit comments

Comments
 (0)