From db3540f267b85abd153a727f297e0d11e5f766e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Tusz?= Date: Tue, 5 Jan 2016 12:09:18 -0500 Subject: [PATCH 1/5] Box trace directory split into multiple files --- src/traces/box/calc.js | 138 +++++++ src/traces/box/defaults.js | 59 +++ src/traces/box/hover.js | 97 +++++ src/traces/box/index.js | 622 +----------------------------- src/traces/box/layout_defaults.js | 23 ++ src/traces/box/plot.js | 219 +++++++++++ src/traces/box/set_positions.js | 82 ++++ src/traces/box/style.js | 28 ++ 8 files changed, 658 insertions(+), 610 deletions(-) create mode 100644 src/traces/box/calc.js create mode 100644 src/traces/box/defaults.js create mode 100644 src/traces/box/hover.js create mode 100644 src/traces/box/layout_defaults.js create mode 100644 src/traces/box/plot.js create mode 100644 src/traces/box/set_positions.js create mode 100644 src/traces/box/style.js diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js new file mode 100644 index 00000000000..697fe70051b --- /dev/null +++ b/src/traces/box/calc.js @@ -0,0 +1,138 @@ +'use strict'; + +var isNumeric = require('fast-isnumeric'); + +var Plotly = require('../../plotly'); +var Lib = require('../../lib'); + +module.exports = function calc(gd, trace) { + // outlier definition based on http://www.physics.csbsju.edu/stats/box2.html + var xa = Plotly.Axes.getFromId(gd, trace.xaxis||'x'), + ya = Plotly.Axes.getFromId(gd, trace.yaxis||'y'), + orientation = trace.orientation, + cd = [], + valAxis, valLetter, val, valBinned, + posAxis, posLetter, pos, posDistinct, dPos; + + // Set value (val) and position (pos) keys via orientation + if (orientation==='h') { + valAxis = xa; + valLetter = 'x'; + posAxis = ya; + posLetter = 'y'; + } else { + valAxis = ya; + valLetter = 'y'; + posAxis = xa; + posLetter = 'x'; + } + + val = valAxis.makeCalcdata(trace, valLetter); // get val + + // size autorange based on all source points + // position happens afterward when we know all the pos + Plotly.Axes.expand(valAxis, val, {padded: true}); + + // In vertical (horizontal) box plots: + // if no x (y) data, use x0 (y0), or name + // so if you want one box + // per trace, set x0 (y0) to the x (y) value or category for this trace + // (or set x (y) to a constant array matching y (x)) + function getPos (gd, trace, posLetter, posAxis, val) { + var pos0; + if (posLetter in trace) pos = posAxis.makeCalcdata(trace, posLetter); + else { + if (posLetter+'0' in trace) pos0 = trace[posLetter+'0']; + else if ('name' in trace && ( + posAxis.type==='category' || + (isNumeric(trace.name) && + ['linear','log'].indexOf(posAxis.type)!==-1) || + (Lib.isDateTime(trace.name) && + posAxis.type==='date') + )) { + pos0 = trace.name; + } + else pos0 = gd.numboxes; + pos0 = posAxis.d2c(pos0); + pos = val.map(function(){ return pos0; }); + } + return pos; + } + + pos = getPos(gd, trace, posLetter, posAxis, val); + + // get distinct positions and min difference + var dv = Lib.distinctVals(pos); + posDistinct = dv.vals; + dPos = dv.minDiff/2; + + function binVal (cd, val, pos, posDistinct, dPos) { + var posDistinctLength = posDistinct.length, + valLength = val.length, + valBinned = [], + bins = [], + i, p, n, v; + + // store distinct pos in cd, find bins, init. valBinned + for (i = 0; i < posDistinctLength; ++i) { + p = posDistinct[i]; + cd[i] = {pos: p}; + bins[i] = p - dPos; + valBinned[i] = []; + } + bins.push(posDistinct[posDistinctLength-1] + dPos); + + // bin the values + for (i = 0; i < valLength; ++i) { + v = val[i]; + if(!isNumeric(v)) continue; + n = Lib.findBin(pos[i], bins); + if(n>=0 && n=0 && n1), - // box half width - bdPos = t.dPos*(1-fullLayout.boxgap)*(1-fullLayout.boxgroupgap)/(group ? gd.numboxes : 1), - // box center offset - bPos = group ? 2*t.dPos*(-0.5+(t.boxnum+0.5)/gd.numboxes)*(1-fullLayout.boxgap) : 0, - // whisker width - wdPos = bdPos*trace.whiskerwidth; - if(trace.visible !== true || t.emptybox) { - d3.select(this).remove(); - return; - } - - // set axis via orientation - if (trace.orientation==='h') { - posAxis = ya; - valAxis = xa; - } else { - posAxis = xa; - valAxis = ya; - } - - // save the box size and box position for use by hover - t.bPos = bPos; - t.bdPos = bdPos; - - // repeatable pseudorandom number generator - seed(); - - // boxes and whiskers - d3.select(this).selectAll('path.box') - .data(Plotly.Lib.identity) - .enter().append('path') - .attr('class','box') - .each(function(d){ - var posc = posAxis.c2p(d.pos + bPos, true), - pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), - pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), - posw0 = posAxis.c2p(d.pos + bPos - wdPos, true), - posw1 = posAxis.c2p(d.pos + bPos + wdPos, true), - q1 = valAxis.c2p(d.q1, true), - q3 = valAxis.c2p(d.q3, true), - // make sure median isn't identical to either of the - // quartiles, so we can see it - m = Plotly.Lib.constrain(valAxis.c2p(d.med, true), - Math.min(q1, q3)+1, Math.max(q1, q3)-1), - lf = valAxis.c2p(trace.boxpoints===false ? d.min : d.lf, true), - uf = valAxis.c2p(trace.boxpoints===false ? d.max : d.uf, 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'+q1+','+posc+'H'+lf+'M'+q3+','+posc+'H'+uf+ // whiskers - ((trace.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'+posc+','+q1+'V'+lf+'M'+posc+','+q3+'V'+uf+ // whiskers - ((trace.whiskerwidth===0) ? '' : // whisker caps - 'M'+posw0+','+lf+'H'+posw1+'M'+posw0+','+uf+'H'+posw1)); - } - }); - - // draw points, if desired - if(trace.boxpoints) { - d3.select(this).selectAll('g.points') - // since box plot points get an extra level of nesting, each - // box needs the trace styling info - .data(function(d){ - d.forEach(function(v){ - v.t = t; - v.trace = trace; - }); - return d; - }) - .enter().append('g') - .attr('class','points') - .selectAll('path') - .data(function(d){ - var pts = (trace.boxpoints==='all') ? d.val : - d.val.filter(function(v){ return (vd.uf); }), - spreadLimit = (d.q3 - d.q1) * JITTERSPREAD, - jitterFactors = [], - maxJitterFactor = 0, - i, - i0, i1, - pmin, - pmax, - jitterFactor, - newJitter; - - // dynamic jitter - if(trace.jitter) { - for(i=0; id.lo) { - p.so=true; - } - return p; - }); - }) - .enter().append('path') - .call(Plotly.Drawing.translatePoints, xa, ya); - } - // draw mean (and stdev diamond) if desired - if(trace.boxmean) { - d3.select(this).selectAll('path.mean') - .data(Plotly.Lib.identity) - .enter().append('path') - .attr('class','mean') - .style('fill','none') - .each(function(d){ - var posc = posAxis.c2p(d.pos + bPos, true), - pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), - pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), - m = valAxis.c2p(d.mean, true), - sl = valAxis.c2p(d.mean-d.sd, true), - sh = valAxis.c2p(d.mean+d.sd, true); - if (trace.orientation==='h') { - d3.select(this).attr('d', - 'M'+m+','+pos0+'V'+pos1+ - ((trace.boxmean!=='sd') ? '' : - 'm0,0L'+sl+','+posc+'L'+m+','+pos0+'L'+sh+','+posc+'Z')); - } else { - d3.select(this).attr('d', - 'M'+pos0+','+m+'H'+pos1+ - ((trace.boxmean!=='sd') ? '' : - 'm0,0L'+posc+','+sl+'L'+pos0+','+m+'L'+posc+','+sh+'Z')); - } - }); - } - }); -}; - -boxes.style = function(gd) { - var s = d3.select(gd).selectAll('g.trace.boxes'); - - s.style('opacity', function(d){ return d[0].trace.opacity; }) - .each(function(d){ - var trace = d[0].trace, - lineWidth = trace.line.width; - d3.select(this).selectAll('path.box') - .style('stroke-width',lineWidth+'px') - .call(Plotly.Color.stroke, trace.line.color) - .call(Plotly.Color.fill, trace.fillcolor); - d3.select(this).selectAll('path.mean') - .style({ - 'stroke-width': lineWidth, - 'stroke-dasharray': (2*lineWidth)+'px,'+lineWidth+'px' - }) - .call(Plotly.Color.stroke, trace.line.color); - d3.select(this).selectAll('g.points path') - .call(Plotly.Drawing.pointStyle, trace); - }); -}; - -boxes.hoverPoints = function(pointData, xval, yval, hovermode) { - // closest mode: handicap box plots a little relative to others - var cd = pointData.cd, - trace = cd[0].trace, - t = cd[0].t, - xa = pointData.xa, - ya = pointData.ya, - closeData = [], - dx, dy, distfn, boxDelta, - posLetter, posAxis, posText, - val, valLetter, valAxis; - - // adjust inbox w.r.t. to calculate box size - boxDelta = (hovermode==='closest') ? 2.5*t.bdPos : t.bdPos; - - if (trace.orientation==='h') { - dx = function(di){ - return Plotly.Fx.inbox(di.min - xval, di.max - xval); - }; - dy = function(di){ - var pos = di.pos + t.bPos - yval; - return Plotly.Fx.inbox(pos - boxDelta, pos + boxDelta); - }; - posLetter = 'y'; - posAxis = ya; - valLetter = 'x'; - valAxis = xa; - } else { - dx = function(di){ - var pos = di.pos + t.bPos - xval; - return Plotly.Fx.inbox(pos - boxDelta, pos + boxDelta); - }; - dy = function(di){ - return Plotly.Fx.inbox(di.min - yval, di.max - yval); - }; - posLetter = 'x'; - posAxis = xa; - valLetter = 'y'; - valAxis = ya; - } - - distfn = Plotly.Fx.getDistanceFunction(hovermode, dx, dy); - Plotly.Fx.getClosest(cd, distfn, pointData); - - // skip the rest (for this trace) if we didn't find a close point - if(pointData.index===false) return; - - // create the item(s) in closedata for this point - - // the closest data point - var di = cd[pointData.index], - lc = trace.line.color, - mc = (trace.marker||{}).color; - if(Plotly.Color.opacity(lc) && trace.line.width) pointData.color = lc; - else if(Plotly.Color.opacity(mc) && trace.boxpoints) pointData.color = mc; - else pointData.color = trace.fillcolor; - - pointData[posLetter+'0'] = posAxis.c2p(di.pos + t.bPos - t.bdPos, true); - pointData[posLetter+'1'] = posAxis.c2p(di.pos + t.bPos + t.bdPos, true); - - posText = Plotly.Axes.tickText(posAxis, posAxis.c2l(di.pos), 'hover').text; - pointData[posLetter+'LabelVal'] = di.pos; - - // box plots: each "point" gets many labels - var usedVals = {}, - attrs = ['med','min','q1','q3','max'], - attr, - pointData2; - if(trace.boxmean) attrs.push('mean'); - if(trace.boxpoints) [].push.apply(attrs,['lf', 'uf']); - - for (var i=0; i1), + // box half width + bdPos = t.dPos*(1-fullLayout.boxgap)*(1-fullLayout.boxgroupgap)/(group ? gd.numboxes : 1), + // box center offset + bPos = group ? 2*t.dPos*(-0.5+(t.boxnum+0.5)/gd.numboxes)*(1-fullLayout.boxgap) : 0, + // whisker width + wdPos = bdPos*trace.whiskerwidth; + if(trace.visible !== true || t.emptybox) { + d3.select(this).remove(); + return; + } + + // set axis via orientation + if (trace.orientation==='h') { + posAxis = ya; + valAxis = xa; + } else { + posAxis = xa; + valAxis = ya; + } + + // save the box size and box position for use by hover + t.bPos = bPos; + t.bdPos = bdPos; + + // repeatable pseudorandom number generator + seed(); + + // boxes and whiskers + d3.select(this).selectAll('path.box') + .data(Lib.identity) + .enter().append('path') + .attr('class','box') + .each(function(d){ + var posc = posAxis.c2p(d.pos + bPos, true), + pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), + pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), + posw0 = posAxis.c2p(d.pos + bPos - wdPos, true), + posw1 = posAxis.c2p(d.pos + bPos + wdPos, true), + q1 = valAxis.c2p(d.q1, true), + q3 = valAxis.c2p(d.q3, true), + // make sure median isn't identical to either of the + // quartiles, so we can see it + m = Lib.constrain(valAxis.c2p(d.med, true), + Math.min(q1, q3)+1, Math.max(q1, q3)-1), + lf = valAxis.c2p(trace.boxpoints===false ? d.min : d.lf, true), + uf = valAxis.c2p(trace.boxpoints===false ? d.max : d.uf, 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'+q1+','+posc+'H'+lf+'M'+q3+','+posc+'H'+uf+ // whiskers + ((trace.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'+posc+','+q1+'V'+lf+'M'+posc+','+q3+'V'+uf+ // whiskers + ((trace.whiskerwidth===0) ? '' : // whisker caps + 'M'+posw0+','+lf+'H'+posw1+'M'+posw0+','+uf+'H'+posw1)); + } + }); + + // draw points, if desired + if(trace.boxpoints) { + d3.select(this).selectAll('g.points') + // since box plot points get an extra level of nesting, each + // box needs the trace styling info + .data(function(d){ + d.forEach(function(v){ + v.t = t; + v.trace = trace; + }); + return d; + }) + .enter().append('g') + .attr('class','points') + .selectAll('path') + .data(function(d){ + var pts = (trace.boxpoints==='all') ? d.val : + d.val.filter(function(v){ return (vd.uf); }), + spreadLimit = (d.q3 - d.q1) * JITTERSPREAD, + jitterFactors = [], + maxJitterFactor = 0, + i, + i0, i1, + pmin, + pmax, + jitterFactor, + newJitter; + + // dynamic jitter + if(trace.jitter) { + for(i=0; id.lo) { + p.so=true; + } + return p; + }); + }) + .enter().append('path') + .call(Plotly.Drawing.translatePoints, xa, ya); + } + // draw mean (and stdev diamond) if desired + if(trace.boxmean) { + d3.select(this).selectAll('path.mean') + .data(Lib.identity) + .enter().append('path') + .attr('class','mean') + .style('fill','none') + .each(function(d){ + var posc = posAxis.c2p(d.pos + bPos, true), + pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), + pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), + m = valAxis.c2p(d.mean, true), + sl = valAxis.c2p(d.mean-d.sd, true), + sh = valAxis.c2p(d.mean+d.sd, true); + if (trace.orientation==='h') { + d3.select(this).attr('d', + 'M'+m+','+pos0+'V'+pos1+ + ((trace.boxmean!=='sd') ? '' : + 'm0,0L'+sl+','+posc+'L'+m+','+pos0+'L'+sh+','+posc+'Z')); + } else { + d3.select(this).attr('d', + 'M'+pos0+','+m+'H'+pos1+ + ((trace.boxmean!=='sd') ? '' : + 'm0,0L'+posc+','+sl+'L'+pos0+','+m+'L'+posc+','+sh+'Z')); + } + }); + } + }); +}; + + + diff --git a/src/traces/box/set_positions.js b/src/traces/box/set_positions.js new file mode 100644 index 00000000000..b6a0b47ec81 --- /dev/null +++ b/src/traces/box/set_positions.js @@ -0,0 +1,82 @@ +'use strict'; + +var Plotly = require('../../plotly'); +var Plots = require('../../plots/plots'); +var Lib = require('../../lib'); + +module.exports = function setPositions(gd, plotinfo) { + var fullLayout = gd._fullLayout, + xa = plotinfo.x(), + ya = plotinfo.y(), + orientations = ['v', 'h'], + posAxis, i, j, k; + + for (i=0; i < orientations.length; ++i) { + var orientation = orientations[i], + boxlist = [], + boxpointlist = [], + minPad = 0, + maxPad = 0, + cd, + t, + trace; + + // set axis via orientation + if (orientation==='h') posAxis = ya; + else posAxis = xa; + + // make list of boxes + for (j=0; j < gd.calcdata.length; ++j) { + cd = gd.calcdata[j]; + t = cd[0].t; + trace = cd[0].trace; + + if (trace.visible === true && Plots.traceIs(trace, 'box') && + !t.emptybox && + trace.orientation === orientation && + trace.xaxis === xa._id && + trace.yaxis === ya._id) { + boxlist.push(j); + if (trace.boxpoints !== false) { + minPad = Math.max(minPad, trace.jitter-trace.pointpos-1); + maxPad = Math.max(maxPad, trace.jitter+trace.pointpos-1); + } + } + } + + // make list of box points + for (j = 0; j < boxlist.length; j++) { + cd = gd.calcdata[boxlist[j]]; + for (k = 0; k < cd.length; k++) boxpointlist.push(cd[k].pos); + } + if (!boxpointlist.length) continue; + + // box plots - update dPos based on multiple traces + // and then use for posAxis autorange + + var boxdv = Lib.distinctVals(boxpointlist), + dPos = boxdv.minDiff/2; + + // if there's no duplication of x points, + // disable 'group' mode by setting numboxes=1 + if(boxpointlist.length===boxdv.vals.length) gd.numboxes = 1; + + // check for forced minimum dtick + Plotly.Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true); + + // set the width of all boxes + for (i=0; i < boxlist.length; ++i) { + gd.calcdata[i][0].t.dPos = dPos; + } + + // autoscale the x axis - including space for points if they're off the side + // TODO: this will overdo it if the outermost boxes don't have + // their points as far out as the other boxes + var padfactor = (1-fullLayout.boxgap) * (1-fullLayout.boxgroupgap) * + dPos / gd.numboxes; + Plotly.Axes.expand(posAxis, boxdv.vals, { + vpadminus: dPos+minPad*padfactor, + vpadplus: dPos+maxPad*padfactor + }); + } +}; diff --git a/src/traces/box/style.js b/src/traces/box/style.js new file mode 100644 index 00000000000..96761d8057e --- /dev/null +++ b/src/traces/box/style.js @@ -0,0 +1,28 @@ +'use strict'; + +var d3 = require('d3'); + +var Plotly = require('../../plotly'); +var Color = require('../../components/color'); + +module.exports = function style(gd) { + var s = d3.select(gd).selectAll('g.trace.boxes'); + + s.style('opacity', function(d){ return d[0].trace.opacity; }) + .each(function(d){ + var trace = d[0].trace, + lineWidth = trace.line.width; + d3.select(this).selectAll('path.box') + .style('stroke-width',lineWidth+'px') + .call(Color.stroke, trace.line.color) + .call(Color.fill, trace.fillcolor); + d3.select(this).selectAll('path.mean') + .style({ + 'stroke-width': lineWidth, + 'stroke-dasharray': (2*lineWidth)+'px,'+lineWidth+'px' + }) + .call(Color.stroke, trace.line.color); + d3.select(this).selectAll('g.points path') + .call(Plotly.Drawing.pointStyle, trace); + }); +}; From 3d9509d7843f1bc49764d8735e17204c05c2428b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Tusz?= Date: Tue, 5 Jan 2016 13:01:10 -0500 Subject: [PATCH 2/5] Fixed missing variable --- src/traces/box/layout_defaults.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/traces/box/layout_defaults.js b/src/traces/box/layout_defaults.js index 326cb558d17..fe106d2154b 100644 --- a/src/traces/box/layout_defaults.js +++ b/src/traces/box/layout_defaults.js @@ -3,9 +3,11 @@ var Plots = require('../../plots/plots'); var Lib = require('../../lib'); +var layoutAttributes = require('./layout_attributes'); + module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { function coerce(attr, dflt) { - return Lib.coerce(layoutIn, layoutOut, boxes.layoutAttributes, attr, dflt); + return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt); } var hasBoxes; From eba8b83e4b562219c9712c04daf6f590b7c4196f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Tusz?= Date: Tue, 5 Jan 2016 12:09:18 -0500 Subject: [PATCH 3/5] Box trace directory split into multiple files --- src/traces/box/calc.js | 138 +++++++ src/traces/box/defaults.js | 59 +++ src/traces/box/hover.js | 97 +++++ src/traces/box/index.js | 622 +----------------------------- src/traces/box/layout_defaults.js | 23 ++ src/traces/box/plot.js | 219 +++++++++++ src/traces/box/set_positions.js | 82 ++++ src/traces/box/style.js | 28 ++ 8 files changed, 658 insertions(+), 610 deletions(-) create mode 100644 src/traces/box/calc.js create mode 100644 src/traces/box/defaults.js create mode 100644 src/traces/box/hover.js create mode 100644 src/traces/box/layout_defaults.js create mode 100644 src/traces/box/plot.js create mode 100644 src/traces/box/set_positions.js create mode 100644 src/traces/box/style.js diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js new file mode 100644 index 00000000000..697fe70051b --- /dev/null +++ b/src/traces/box/calc.js @@ -0,0 +1,138 @@ +'use strict'; + +var isNumeric = require('fast-isnumeric'); + +var Plotly = require('../../plotly'); +var Lib = require('../../lib'); + +module.exports = function calc(gd, trace) { + // outlier definition based on http://www.physics.csbsju.edu/stats/box2.html + var xa = Plotly.Axes.getFromId(gd, trace.xaxis||'x'), + ya = Plotly.Axes.getFromId(gd, trace.yaxis||'y'), + orientation = trace.orientation, + cd = [], + valAxis, valLetter, val, valBinned, + posAxis, posLetter, pos, posDistinct, dPos; + + // Set value (val) and position (pos) keys via orientation + if (orientation==='h') { + valAxis = xa; + valLetter = 'x'; + posAxis = ya; + posLetter = 'y'; + } else { + valAxis = ya; + valLetter = 'y'; + posAxis = xa; + posLetter = 'x'; + } + + val = valAxis.makeCalcdata(trace, valLetter); // get val + + // size autorange based on all source points + // position happens afterward when we know all the pos + Plotly.Axes.expand(valAxis, val, {padded: true}); + + // In vertical (horizontal) box plots: + // if no x (y) data, use x0 (y0), or name + // so if you want one box + // per trace, set x0 (y0) to the x (y) value or category for this trace + // (or set x (y) to a constant array matching y (x)) + function getPos (gd, trace, posLetter, posAxis, val) { + var pos0; + if (posLetter in trace) pos = posAxis.makeCalcdata(trace, posLetter); + else { + if (posLetter+'0' in trace) pos0 = trace[posLetter+'0']; + else if ('name' in trace && ( + posAxis.type==='category' || + (isNumeric(trace.name) && + ['linear','log'].indexOf(posAxis.type)!==-1) || + (Lib.isDateTime(trace.name) && + posAxis.type==='date') + )) { + pos0 = trace.name; + } + else pos0 = gd.numboxes; + pos0 = posAxis.d2c(pos0); + pos = val.map(function(){ return pos0; }); + } + return pos; + } + + pos = getPos(gd, trace, posLetter, posAxis, val); + + // get distinct positions and min difference + var dv = Lib.distinctVals(pos); + posDistinct = dv.vals; + dPos = dv.minDiff/2; + + function binVal (cd, val, pos, posDistinct, dPos) { + var posDistinctLength = posDistinct.length, + valLength = val.length, + valBinned = [], + bins = [], + i, p, n, v; + + // store distinct pos in cd, find bins, init. valBinned + for (i = 0; i < posDistinctLength; ++i) { + p = posDistinct[i]; + cd[i] = {pos: p}; + bins[i] = p - dPos; + valBinned[i] = []; + } + bins.push(posDistinct[posDistinctLength-1] + dPos); + + // bin the values + for (i = 0; i < valLength; ++i) { + v = val[i]; + if(!isNumeric(v)) continue; + n = Lib.findBin(pos[i], bins); + if(n>=0 && n=0 && n1), - // box half width - bdPos = t.dPos*(1-fullLayout.boxgap)*(1-fullLayout.boxgroupgap)/(group ? gd.numboxes : 1), - // box center offset - bPos = group ? 2*t.dPos*(-0.5+(t.boxnum+0.5)/gd.numboxes)*(1-fullLayout.boxgap) : 0, - // whisker width - wdPos = bdPos*trace.whiskerwidth; - if(trace.visible !== true || t.emptybox) { - d3.select(this).remove(); - return; - } - - // set axis via orientation - if (trace.orientation==='h') { - posAxis = ya; - valAxis = xa; - } else { - posAxis = xa; - valAxis = ya; - } - - // save the box size and box position for use by hover - t.bPos = bPos; - t.bdPos = bdPos; - - // repeatable pseudorandom number generator - seed(); - - // boxes and whiskers - d3.select(this).selectAll('path.box') - .data(Plotly.Lib.identity) - .enter().append('path') - .attr('class','box') - .each(function(d){ - var posc = posAxis.c2p(d.pos + bPos, true), - pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), - pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), - posw0 = posAxis.c2p(d.pos + bPos - wdPos, true), - posw1 = posAxis.c2p(d.pos + bPos + wdPos, true), - q1 = valAxis.c2p(d.q1, true), - q3 = valAxis.c2p(d.q3, true), - // make sure median isn't identical to either of the - // quartiles, so we can see it - m = Plotly.Lib.constrain(valAxis.c2p(d.med, true), - Math.min(q1, q3)+1, Math.max(q1, q3)-1), - lf = valAxis.c2p(trace.boxpoints===false ? d.min : d.lf, true), - uf = valAxis.c2p(trace.boxpoints===false ? d.max : d.uf, 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'+q1+','+posc+'H'+lf+'M'+q3+','+posc+'H'+uf+ // whiskers - ((trace.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'+posc+','+q1+'V'+lf+'M'+posc+','+q3+'V'+uf+ // whiskers - ((trace.whiskerwidth===0) ? '' : // whisker caps - 'M'+posw0+','+lf+'H'+posw1+'M'+posw0+','+uf+'H'+posw1)); - } - }); - - // draw points, if desired - if(trace.boxpoints) { - d3.select(this).selectAll('g.points') - // since box plot points get an extra level of nesting, each - // box needs the trace styling info - .data(function(d){ - d.forEach(function(v){ - v.t = t; - v.trace = trace; - }); - return d; - }) - .enter().append('g') - .attr('class','points') - .selectAll('path') - .data(function(d){ - var pts = (trace.boxpoints==='all') ? d.val : - d.val.filter(function(v){ return (vd.uf); }), - spreadLimit = (d.q3 - d.q1) * JITTERSPREAD, - jitterFactors = [], - maxJitterFactor = 0, - i, - i0, i1, - pmin, - pmax, - jitterFactor, - newJitter; - - // dynamic jitter - if(trace.jitter) { - for(i=0; id.lo) { - p.so=true; - } - return p; - }); - }) - .enter().append('path') - .call(Plotly.Drawing.translatePoints, xa, ya); - } - // draw mean (and stdev diamond) if desired - if(trace.boxmean) { - d3.select(this).selectAll('path.mean') - .data(Plotly.Lib.identity) - .enter().append('path') - .attr('class','mean') - .style('fill','none') - .each(function(d){ - var posc = posAxis.c2p(d.pos + bPos, true), - pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), - pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), - m = valAxis.c2p(d.mean, true), - sl = valAxis.c2p(d.mean-d.sd, true), - sh = valAxis.c2p(d.mean+d.sd, true); - if (trace.orientation==='h') { - d3.select(this).attr('d', - 'M'+m+','+pos0+'V'+pos1+ - ((trace.boxmean!=='sd') ? '' : - 'm0,0L'+sl+','+posc+'L'+m+','+pos0+'L'+sh+','+posc+'Z')); - } else { - d3.select(this).attr('d', - 'M'+pos0+','+m+'H'+pos1+ - ((trace.boxmean!=='sd') ? '' : - 'm0,0L'+posc+','+sl+'L'+pos0+','+m+'L'+posc+','+sh+'Z')); - } - }); - } - }); -}; - -boxes.style = function(gd) { - var s = d3.select(gd).selectAll('g.trace.boxes'); - - s.style('opacity', function(d){ return d[0].trace.opacity; }) - .each(function(d){ - var trace = d[0].trace, - lineWidth = trace.line.width; - d3.select(this).selectAll('path.box') - .style('stroke-width',lineWidth+'px') - .call(Plotly.Color.stroke, trace.line.color) - .call(Plotly.Color.fill, trace.fillcolor); - d3.select(this).selectAll('path.mean') - .style({ - 'stroke-width': lineWidth, - 'stroke-dasharray': (2*lineWidth)+'px,'+lineWidth+'px' - }) - .call(Plotly.Color.stroke, trace.line.color); - d3.select(this).selectAll('g.points path') - .call(Plotly.Drawing.pointStyle, trace); - }); -}; - -boxes.hoverPoints = function(pointData, xval, yval, hovermode) { - // closest mode: handicap box plots a little relative to others - var cd = pointData.cd, - trace = cd[0].trace, - t = cd[0].t, - xa = pointData.xa, - ya = pointData.ya, - closeData = [], - dx, dy, distfn, boxDelta, - posLetter, posAxis, posText, - val, valLetter, valAxis; - - // adjust inbox w.r.t. to calculate box size - boxDelta = (hovermode==='closest') ? 2.5*t.bdPos : t.bdPos; - - if (trace.orientation==='h') { - dx = function(di){ - return Plotly.Fx.inbox(di.min - xval, di.max - xval); - }; - dy = function(di){ - var pos = di.pos + t.bPos - yval; - return Plotly.Fx.inbox(pos - boxDelta, pos + boxDelta); - }; - posLetter = 'y'; - posAxis = ya; - valLetter = 'x'; - valAxis = xa; - } else { - dx = function(di){ - var pos = di.pos + t.bPos - xval; - return Plotly.Fx.inbox(pos - boxDelta, pos + boxDelta); - }; - dy = function(di){ - return Plotly.Fx.inbox(di.min - yval, di.max - yval); - }; - posLetter = 'x'; - posAxis = xa; - valLetter = 'y'; - valAxis = ya; - } - - distfn = Plotly.Fx.getDistanceFunction(hovermode, dx, dy); - Plotly.Fx.getClosest(cd, distfn, pointData); - - // skip the rest (for this trace) if we didn't find a close point - if(pointData.index===false) return; - - // create the item(s) in closedata for this point - - // the closest data point - var di = cd[pointData.index], - lc = trace.line.color, - mc = (trace.marker||{}).color; - if(Plotly.Color.opacity(lc) && trace.line.width) pointData.color = lc; - else if(Plotly.Color.opacity(mc) && trace.boxpoints) pointData.color = mc; - else pointData.color = trace.fillcolor; - - pointData[posLetter+'0'] = posAxis.c2p(di.pos + t.bPos - t.bdPos, true); - pointData[posLetter+'1'] = posAxis.c2p(di.pos + t.bPos + t.bdPos, true); - - posText = Plotly.Axes.tickText(posAxis, posAxis.c2l(di.pos), 'hover').text; - pointData[posLetter+'LabelVal'] = di.pos; - - // box plots: each "point" gets many labels - var usedVals = {}, - attrs = ['med','min','q1','q3','max'], - attr, - pointData2; - if(trace.boxmean) attrs.push('mean'); - if(trace.boxpoints) [].push.apply(attrs,['lf', 'uf']); - - for (var i=0; i1), + // box half width + bdPos = t.dPos*(1-fullLayout.boxgap)*(1-fullLayout.boxgroupgap)/(group ? gd.numboxes : 1), + // box center offset + bPos = group ? 2*t.dPos*(-0.5+(t.boxnum+0.5)/gd.numboxes)*(1-fullLayout.boxgap) : 0, + // whisker width + wdPos = bdPos*trace.whiskerwidth; + if(trace.visible !== true || t.emptybox) { + d3.select(this).remove(); + return; + } + + // set axis via orientation + if (trace.orientation==='h') { + posAxis = ya; + valAxis = xa; + } else { + posAxis = xa; + valAxis = ya; + } + + // save the box size and box position for use by hover + t.bPos = bPos; + t.bdPos = bdPos; + + // repeatable pseudorandom number generator + seed(); + + // boxes and whiskers + d3.select(this).selectAll('path.box') + .data(Lib.identity) + .enter().append('path') + .attr('class','box') + .each(function(d){ + var posc = posAxis.c2p(d.pos + bPos, true), + pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), + pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), + posw0 = posAxis.c2p(d.pos + bPos - wdPos, true), + posw1 = posAxis.c2p(d.pos + bPos + wdPos, true), + q1 = valAxis.c2p(d.q1, true), + q3 = valAxis.c2p(d.q3, true), + // make sure median isn't identical to either of the + // quartiles, so we can see it + m = Lib.constrain(valAxis.c2p(d.med, true), + Math.min(q1, q3)+1, Math.max(q1, q3)-1), + lf = valAxis.c2p(trace.boxpoints===false ? d.min : d.lf, true), + uf = valAxis.c2p(trace.boxpoints===false ? d.max : d.uf, 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'+q1+','+posc+'H'+lf+'M'+q3+','+posc+'H'+uf+ // whiskers + ((trace.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'+posc+','+q1+'V'+lf+'M'+posc+','+q3+'V'+uf+ // whiskers + ((trace.whiskerwidth===0) ? '' : // whisker caps + 'M'+posw0+','+lf+'H'+posw1+'M'+posw0+','+uf+'H'+posw1)); + } + }); + + // draw points, if desired + if(trace.boxpoints) { + d3.select(this).selectAll('g.points') + // since box plot points get an extra level of nesting, each + // box needs the trace styling info + .data(function(d){ + d.forEach(function(v){ + v.t = t; + v.trace = trace; + }); + return d; + }) + .enter().append('g') + .attr('class','points') + .selectAll('path') + .data(function(d){ + var pts = (trace.boxpoints==='all') ? d.val : + d.val.filter(function(v){ return (vd.uf); }), + spreadLimit = (d.q3 - d.q1) * JITTERSPREAD, + jitterFactors = [], + maxJitterFactor = 0, + i, + i0, i1, + pmin, + pmax, + jitterFactor, + newJitter; + + // dynamic jitter + if(trace.jitter) { + for(i=0; id.lo) { + p.so=true; + } + return p; + }); + }) + .enter().append('path') + .call(Plotly.Drawing.translatePoints, xa, ya); + } + // draw mean (and stdev diamond) if desired + if(trace.boxmean) { + d3.select(this).selectAll('path.mean') + .data(Lib.identity) + .enter().append('path') + .attr('class','mean') + .style('fill','none') + .each(function(d){ + var posc = posAxis.c2p(d.pos + bPos, true), + pos0 = posAxis.c2p(d.pos + bPos - bdPos, true), + pos1 = posAxis.c2p(d.pos + bPos + bdPos, true), + m = valAxis.c2p(d.mean, true), + sl = valAxis.c2p(d.mean-d.sd, true), + sh = valAxis.c2p(d.mean+d.sd, true); + if (trace.orientation==='h') { + d3.select(this).attr('d', + 'M'+m+','+pos0+'V'+pos1+ + ((trace.boxmean!=='sd') ? '' : + 'm0,0L'+sl+','+posc+'L'+m+','+pos0+'L'+sh+','+posc+'Z')); + } else { + d3.select(this).attr('d', + 'M'+pos0+','+m+'H'+pos1+ + ((trace.boxmean!=='sd') ? '' : + 'm0,0L'+posc+','+sl+'L'+pos0+','+m+'L'+posc+','+sh+'Z')); + } + }); + } + }); +}; + + + diff --git a/src/traces/box/set_positions.js b/src/traces/box/set_positions.js new file mode 100644 index 00000000000..b6a0b47ec81 --- /dev/null +++ b/src/traces/box/set_positions.js @@ -0,0 +1,82 @@ +'use strict'; + +var Plotly = require('../../plotly'); +var Plots = require('../../plots/plots'); +var Lib = require('../../lib'); + +module.exports = function setPositions(gd, plotinfo) { + var fullLayout = gd._fullLayout, + xa = plotinfo.x(), + ya = plotinfo.y(), + orientations = ['v', 'h'], + posAxis, i, j, k; + + for (i=0; i < orientations.length; ++i) { + var orientation = orientations[i], + boxlist = [], + boxpointlist = [], + minPad = 0, + maxPad = 0, + cd, + t, + trace; + + // set axis via orientation + if (orientation==='h') posAxis = ya; + else posAxis = xa; + + // make list of boxes + for (j=0; j < gd.calcdata.length; ++j) { + cd = gd.calcdata[j]; + t = cd[0].t; + trace = cd[0].trace; + + if (trace.visible === true && Plots.traceIs(trace, 'box') && + !t.emptybox && + trace.orientation === orientation && + trace.xaxis === xa._id && + trace.yaxis === ya._id) { + boxlist.push(j); + if (trace.boxpoints !== false) { + minPad = Math.max(minPad, trace.jitter-trace.pointpos-1); + maxPad = Math.max(maxPad, trace.jitter+trace.pointpos-1); + } + } + } + + // make list of box points + for (j = 0; j < boxlist.length; j++) { + cd = gd.calcdata[boxlist[j]]; + for (k = 0; k < cd.length; k++) boxpointlist.push(cd[k].pos); + } + if (!boxpointlist.length) continue; + + // box plots - update dPos based on multiple traces + // and then use for posAxis autorange + + var boxdv = Lib.distinctVals(boxpointlist), + dPos = boxdv.minDiff/2; + + // if there's no duplication of x points, + // disable 'group' mode by setting numboxes=1 + if(boxpointlist.length===boxdv.vals.length) gd.numboxes = 1; + + // check for forced minimum dtick + Plotly.Axes.minDtick(posAxis, boxdv.minDiff, boxdv.vals[0], true); + + // set the width of all boxes + for (i=0; i < boxlist.length; ++i) { + gd.calcdata[i][0].t.dPos = dPos; + } + + // autoscale the x axis - including space for points if they're off the side + // TODO: this will overdo it if the outermost boxes don't have + // their points as far out as the other boxes + var padfactor = (1-fullLayout.boxgap) * (1-fullLayout.boxgroupgap) * + dPos / gd.numboxes; + Plotly.Axes.expand(posAxis, boxdv.vals, { + vpadminus: dPos+minPad*padfactor, + vpadplus: dPos+maxPad*padfactor + }); + } +}; diff --git a/src/traces/box/style.js b/src/traces/box/style.js new file mode 100644 index 00000000000..96761d8057e --- /dev/null +++ b/src/traces/box/style.js @@ -0,0 +1,28 @@ +'use strict'; + +var d3 = require('d3'); + +var Plotly = require('../../plotly'); +var Color = require('../../components/color'); + +module.exports = function style(gd) { + var s = d3.select(gd).selectAll('g.trace.boxes'); + + s.style('opacity', function(d){ return d[0].trace.opacity; }) + .each(function(d){ + var trace = d[0].trace, + lineWidth = trace.line.width; + d3.select(this).selectAll('path.box') + .style('stroke-width',lineWidth+'px') + .call(Color.stroke, trace.line.color) + .call(Color.fill, trace.fillcolor); + d3.select(this).selectAll('path.mean') + .style({ + 'stroke-width': lineWidth, + 'stroke-dasharray': (2*lineWidth)+'px,'+lineWidth+'px' + }) + .call(Color.stroke, trace.line.color); + d3.select(this).selectAll('g.points path') + .call(Plotly.Drawing.pointStyle, trace); + }); +}; From af7f8e36d01a3b043777507f653efdb00124dfc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Tusz?= Date: Tue, 5 Jan 2016 13:01:10 -0500 Subject: [PATCH 4/5] Fixed missing variable --- src/traces/box/layout_defaults.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/traces/box/layout_defaults.js b/src/traces/box/layout_defaults.js index 326cb558d17..fe106d2154b 100644 --- a/src/traces/box/layout_defaults.js +++ b/src/traces/box/layout_defaults.js @@ -3,9 +3,11 @@ var Plots = require('../../plots/plots'); var Lib = require('../../lib'); +var layoutAttributes = require('./layout_attributes'); + module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { function coerce(attr, dflt) { - return Lib.coerce(layoutIn, layoutOut, boxes.layoutAttributes, attr, dflt); + return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt); } var hasBoxes; From d9a694833d9580f7e275fb850cc3527bb412b34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Tusz?= Date: Tue, 5 Jan 2016 15:57:27 -0500 Subject: [PATCH 5/5] Added new 2016 header --- src/traces/box/calc.js | 8 ++++++++ src/traces/box/defaults.js | 8 ++++++++ src/traces/box/hover.js | 8 ++++++++ src/traces/box/index.js | 25 ++++++++++--------------- src/traces/box/layout_attributes.js | 1 - src/traces/box/layout_defaults.js | 9 ++++++++- src/traces/box/plot.js | 8 ++++++++ src/traces/box/set_positions.js | 8 ++++++++ src/traces/box/style.js | 8 ++++++++ 9 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js index 697fe70051b..56785310077 100644 --- a/src/traces/box/calc.js +++ b/src/traces/box/calc.js @@ -1,3 +1,11 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var isNumeric = require('fast-isnumeric'); diff --git a/src/traces/box/defaults.js b/src/traces/box/defaults.js index a6cce5a1bd8..10c14e99233 100644 --- a/src/traces/box/defaults.js +++ b/src/traces/box/defaults.js @@ -1,3 +1,11 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var Lib = require('../../lib'); diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 6dbf9b67d8e..153d51b3b0b 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -1,3 +1,11 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var Plotly = require('../../plotly'); diff --git a/src/traces/box/index.js b/src/traces/box/index.js index 95f8092dbf9..94271a00f13 100644 --- a/src/traces/box/index.js +++ b/src/traces/box/index.js @@ -6,24 +6,11 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; var Plotly = require('../../plotly'); -var boxes = { - attributes: require('./attributes'), - layoutAttributes: require('./layout_attributes'), - supplyDefaults: require('./defaults'), - supplyLayoutDefaults: require('./layout_defaults'), - calc: require('./calc'), - setPositions: require('./set_positions'), - plot: require('./plot'), - style: require('./style'), - hoverPoints: require('./hover') -}; - -Plotly.Plots.register(boxes, 'box', +Plotly.Plots.register(exports, 'box', ['cartesian', 'symbols', 'oriented', 'box', 'showLegend'], { description: [ 'In vertical (horizontal) box plots,', @@ -41,4 +28,12 @@ Plotly.Plots.register(boxes, 'box', ].join(' ') }); -module.exports = boxes; +exports.attributes = require('./attributes'); +exports.layoutAttributes = require('./layout_attributes'); +exports.supplyDefaults = require('./defaults'); +exports.supplyLayoutDefaults = require('./layout_defaults'); +exports.calc = require('./calc'); +exports.setPositions = require('./set_positions'); +exports.plot = require('./plot'); +exports.style = require('./style'); +exports.hoverPoints = require('./hover'); diff --git a/src/traces/box/layout_attributes.js b/src/traces/box/layout_attributes.js index 46ec7843fdb..2cc5fe79cdc 100644 --- a/src/traces/box/layout_attributes.js +++ b/src/traces/box/layout_attributes.js @@ -6,7 +6,6 @@ * LICENSE file in the root directory of this source tree. */ - module.exports = { boxmode: { valType: 'enumerated', diff --git a/src/traces/box/layout_defaults.js b/src/traces/box/layout_defaults.js index fe106d2154b..18b2d1b0b0c 100644 --- a/src/traces/box/layout_defaults.js +++ b/src/traces/box/layout_defaults.js @@ -1,8 +1,15 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var Plots = require('../../plots/plots'); var Lib = require('../../lib'); - var layoutAttributes = require('./layout_attributes'); module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) { diff --git a/src/traces/box/plot.js b/src/traces/box/plot.js index 4d84bf93a76..1fff40461fa 100644 --- a/src/traces/box/plot.js +++ b/src/traces/box/plot.js @@ -1,3 +1,11 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var d3 = require('d3'); diff --git a/src/traces/box/set_positions.js b/src/traces/box/set_positions.js index b6a0b47ec81..6f0e1cd487b 100644 --- a/src/traces/box/set_positions.js +++ b/src/traces/box/set_positions.js @@ -1,3 +1,11 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var Plotly = require('../../plotly'); diff --git a/src/traces/box/style.js b/src/traces/box/style.js index 96761d8057e..bb1800aaf07 100644 --- a/src/traces/box/style.js +++ b/src/traces/box/style.js @@ -1,3 +1,11 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + 'use strict'; var d3 = require('d3');