Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement notched box plots, closes #2286 #1

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@
"gl-pointcloud2d": "^1.0.0",
"gl-scatter3d": "^1.0.4",
"gl-select-box": "^1.0.1",
"gl-shader": "^4.2.1",
"gl-spikes2d": "^1.0.1",
"gl-surface3d": "^1.3.1",
"gl-surface3d": "^1.3.3",
"has-hover": "^1.0.1",
"kdgrass": "^1.0.1",
"mapbox-gl": "^0.22.0",
Expand Down
21 changes: 21 additions & 0 deletions src/traces/box/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ module.exports = {
'For example, with 1, the whiskers are as wide as the box(es).'
].join(' ')
},
notched: {
valType: 'boolean',
role: 'style',
editType: 'calcIfAutorange',
description: [
'Determines whether or not notches should be drawn.'
].join(' ')
},
notchwidth: {
valType: 'number',
min: 0,
max: 0.5,
dflt: 0.25,
role: 'style',
editType: 'calcIfAutorange',
description: [
'Sets the width of the notches relative to',
'the box\' width.',
'For example, with 0, the notches are as wide as the box(es).'
].join(' ')
},
boxpoints: {
valType: 'enumerated',
values: ['all', 'outliers', 'suspectedoutliers', false],
Expand Down
7 changes: 7 additions & 0 deletions src/traces/box/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ module.exports = function calc(gd, trace) {
cdi.lo = 4 * cdi.q1 - 3 * cdi.q3;
cdi.uo = 4 * cdi.q3 - 3 * cdi.q1;


// lower and upper notches ~95% Confidence Intervals for median
var iqr = cdi.q3 - cdi.q1;
var mci = 1.57 * iqr / Math.sqrt(bvLen);
cdi.ln = cdi.med - mci;
cdi.un = cdi.med + mci;

cd.push(cdi);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/traces/box/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
coerce('whiskerwidth');
coerce('boxmean');

var notched = coerce('notched', traceIn.notchwidth !== undefined);
if(notched) coerce('notchwidth');

handlePointsDefaults(traceIn, traceOut, coerce, {prefix: 'box'});
}

Expand Down
24 changes: 20 additions & 4 deletions src/traces/box/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ function plotBoxAndWhiskers(sel, axes, trace, t) {
var wdPos = t.wdPos || 0;
var bPosPxOffset = t.bPosPxOffset || 0;
var whiskerWidth = trace.whiskerwidth || 0;
var notched = trace.notched || false;
var nw = notched ? 1 - 2 * trace.notchwidth : 1;

// to support for one-sided box
var bdPos0;
Expand All @@ -125,6 +127,8 @@ function plotBoxAndWhiskers(sel, axes, trace, t) {
var pos1 = posAxis.c2p(pos + bPos + bdPos1, true) + bPosPxOffset;
var posw0 = posAxis.c2p(pos + bPos - wdPos, true) + bPosPxOffset;
var posw1 = posAxis.c2p(pos + bPos + wdPos, true) + bPosPxOffset;
var posm0 = posAxis.c2p(pos + bPos - bdPos0 * nw, true) + bPosPxOffset;
var posm1 = posAxis.c2p(pos + bPos + bdPos1 * nw, true) + bPosPxOffset;
var q1 = valAxis.c2p(d.q1, true);
var q3 = valAxis.c2p(d.q3, true);
// make sure median isn't identical to either of the
Expand All @@ -135,18 +139,30 @@ function plotBoxAndWhiskers(sel, axes, trace, t) {
);
var lf = valAxis.c2p(trace.boxpoints === false ? d.min : d.lf, true);
var uf = valAxis.c2p(trace.boxpoints === false ? d.max : d.uf, true);
var ln = valAxis.c2p(d.ln, true);
var un = valAxis.c2p(d.un, true);

if(trace.orientation === 'h') {
d3.select(this).attr('d',
'M' + m + ',' + pos0 + 'V' + pos1 + // median line
'M' + q1 + ',' + pos0 + 'V' + pos1 + 'H' + q3 + 'V' + pos0 + 'Z' + // box
'M' + m + ',' + posm0 + 'V' + posm1 + // median line
'M' + q1 + ',' + pos0 + 'V' + pos1 + // left edge
(notched ? 'H' + ln + 'L' + m + ',' + posm1 + 'L' + un + ',' + pos1 : '') + // top notched edge
'H' + q3 + // end of the top edge
'V' + pos0 + // right edge
(notched ? 'H' + un + 'L' + m + ',' + posm0 + 'L' + ln + ',' + pos0 : '') + // bottom notched edge
'Z' + // end of the box
'M' + q1 + ',' + posc + 'H' + lf + 'M' + q3 + ',' + posc + 'H' + uf + // whiskers
((whiskerWidth === 0) ? '' : // whisker caps
'M' + lf + ',' + posw0 + 'V' + posw1 + 'M' + uf + ',' + posw0 + 'V' + posw1));
} else {
d3.select(this).attr('d',
'M' + pos0 + ',' + m + 'H' + pos1 + // median line
'M' + pos0 + ',' + q1 + 'H' + pos1 + 'V' + q3 + 'H' + pos0 + 'Z' + // box
'M' + posm0 + ',' + m + 'H' + posm1 + // median line
'M' + pos0 + ',' + q1 + 'H' + pos1 + // top of the box
(notched ? 'V' + ln + 'L' + posm1 + ',' + m + 'L' + pos1 + ',' + un : '') + // notched right edge
'V' + q3 + // end of the right edge
'H' + pos0 + // bottom of the box
(notched ? 'V' + un + 'L' + posm0 + ',' + m + 'L' + pos0 + ',' + ln : '') + // notched left edge
'Z' + // end of the box
'M' + posc + ',' + q1 + 'V' + lf + 'M' + posc + ',' + q3 + 'V' + uf + // whiskers
((whiskerWidth === 0) ? '' : // whisker caps
'M' + posw0 + ',' + lf + 'H' + posw1 + 'M' + posw0 + ',' + uf + 'H' + posw1));
Expand Down
Binary file added test/image/baselines/box_horz_notched.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/image/baselines/box_notched.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/gl3d_cufflinks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/gl3d_ibm-plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/gl3d_surface-circular-colorscale.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading