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

Violin plots #2116

Merged
merged 26 commits into from
Nov 1, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c578cde
replace gd.numboxes by fullLayout._numBoxes
etpinard Oct 24, 2017
8f34227
replace 'emptybox' with 'empty' in box calc item
etpinard Oct 24, 2017
c8f38ff
factor out box defaults and boxpoint plot methods
etpinard Oct 24, 2017
3438eae
first cut violin
etpinard Oct 24, 2017
d779509
first cut violin mocks
etpinard Oct 24, 2017
bb252a5
Merge branch 'master' into violins-dev
etpinard Oct 30, 2017
ea43b25
rename 'box' category 'box-violin'
etpinard Oct 31, 2017
a706f2a
factor out box/whiskers and mean/sd plotting routine
etpinard Oct 31, 2017
1eb453b
split box hover into onBoxes and onPoints routines
etpinard Oct 31, 2017
7769f20
implement violinmode, violingroup and violingroupgap
etpinard Oct 31, 2017
ad51966
2nd cut violin calc/plot attributes + improve violin curve paths
etpinard Oct 31, 2017
4a40fc7
add findPointOnPath geometry2d util function
etpinard Oct 31, 2017
6ffc379
implement violin 'inner' style options
etpinard Oct 31, 2017
dfa918f
pass hoverlayer to trace module hoverPoints
etpinard Oct 31, 2017
bc6bc02
implement violin hover
etpinard Oct 31, 2017
e737664
2nd cut violin mocks
etpinard Oct 31, 2017
e625c44
1st cut violin jasmine tests
etpinard Oct 31, 2017
14bded3
fill violin attribute descriptions + fix typo in comment
etpinard Oct 31, 2017
48758d8
fixup scalemode 'count' calculation
etpinard Oct 31, 2017
17f65d0
add inner box and mean line to side-by-side violin mock
etpinard Oct 31, 2017
71700de
2nd cut violin jasmine tests
etpinard Oct 31, 2017
677aacc
remove 'kernel' from violin attributes
etpinard Nov 1, 2017
0a32b98
update box and meanline attribute syntax
etpinard Nov 1, 2017
3c9e0a0
add violin style mock
etpinard Nov 1, 2017
ea66dea
add editType to new violin attr containers
etpinard Nov 1, 2017
789121c
update violin layout attr descriptions
etpinard Nov 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/index-cartesian.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ Plotly.register([
require('./histogram2dcontour'),
require('./pie'),
require('./contour'),
require('./scatterternary')
require('./scatterternary'),
require('./violin')
]);

module.exports = Plotly;
7 changes: 5 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Plotly.register([
require('./pie'),
require('./contour'),
require('./scatterternary'),
require('./sankey'),
require('./violin'),

require('./scatter3d'),
require('./surface'),
Expand All @@ -34,10 +34,13 @@ Plotly.register([
require('./pointcloud'),
require('./heatmapgl'),
require('./parcoords'),
require('./table'),

require('./scattermapbox'),

require('./sankey'),

require('./table'),

require('./carpet'),
require('./scattercarpet'),
require('./contourcarpet'),
Expand Down
11 changes: 11 additions & 0 deletions lib/violin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright 2012-2017, 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';

module.exports = require('../src/traces/violin');
9 changes: 2 additions & 7 deletions src/plots/cartesian/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,13 @@ module.exports = {
DFLTRANGEX: [-1, 6],
DFLTRANGEY: [-1, 4],

// Layers to keep trace types in the right order.
// from back to front:
// 1. heatmaps, 2D histos and contour maps
// 2. bars / 1D histos
// 3. errorbars for bars and scatter
// 4. scatter
// 5. box plots
// Layers to keep trace types in the right order
traceLayerClasses: [
'imagelayer',
'maplayer',
'barlayer',
'carpetlayer',
'violinlayer',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making sure violins are under boxes always.

'boxlayer',
'scatterlayer'
],
Expand Down
6 changes: 3 additions & 3 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,6 @@ plots.purge = function(gd) {
delete gd.firstscatter;
delete gd._hmlumcount;
delete gd._hmpixcount;
delete gd.numboxes;
delete gd._transitionData;
delete gd._transitioning;
delete gd._initialAutoSize;
Expand Down Expand Up @@ -2159,8 +2158,9 @@ plots.doCalcdata = function(gd, traces) {
// firstscatter: fill-to-next on the first trace goes to zero
gd.firstscatter = true;

// how many box plots do we have (in case they're grouped)
gd.numboxes = 0;
// how many box/violins plots do we have (in case they're grouped)
fullLayout._numBoxes = 0;
fullLayout._numViolins = 0;

// for calculating avg luminosity of heatmaps
gd._hmpixcount = 0;
Expand Down
16 changes: 10 additions & 6 deletions src/traces/box/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ var Axes = require('../../plots/cartesian/axes');

// outlier definition based on http://www.physics.csbsju.edu/stats/box2.html
module.exports = function calc(gd, trace) {
var fullLayout = gd._fullLayout;
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
var orientation = trace.orientation;
var cd = [];

var numKey = '_numBoxes';

var i;
var valAxis, valLetter;
var posAxis, posLetter;
Expand All @@ -37,7 +40,7 @@ module.exports = function calc(gd, trace) {
}

var val = valAxis.makeCalcdata(trace, valLetter);
var pos = getPos(trace, posLetter, posAxis, val, gd.numboxes);
var pos = getPos(trace, posLetter, posAxis, val, fullLayout[numKey]);

var dv = Lib.distinctVals(pos);
var posDistinct = dv.vals;
Expand Down Expand Up @@ -115,13 +118,14 @@ module.exports = function calc(gd, trace) {

if(cd.length > 0) {
cd[0].t = {
boxnum: gd.numboxes,
num: fullLayout[numKey],
dPos: dPos
};
gd.numboxes++;

fullLayout[numKey]++;
return cd;
} else {
return [{t: {emptybox: true}}];
return [{t: {empty: true}}];
}
};

Expand All @@ -130,7 +134,7 @@ module.exports = function calc(gd, trace) {
// 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(trace, posLetter, posAxis, val, numboxes) {
function getPos(trace, posLetter, posAxis, val, num) {
if(posLetter in trace) {
return posAxis.makeCalcdata(trace, posLetter);
}
Expand All @@ -150,7 +154,7 @@ function getPos(trace, posLetter, posAxis, val, numboxes) {
)) {
pos0 = trace.name;
} else {
pos0 = numboxes;
pos0 = num;
}

var pos0c = posAxis.d2c(pos0, 0, trace[posLetter + 'calendar']);
Expand Down
43 changes: 30 additions & 13 deletions src/traces/box/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,25 @@ var Color = require('../../components/color');

var attributes = require('./attributes');

module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
function coerce(attr, dflt) {
return Lib.coerce(traceIn, traceOut, attributes, attr, dflt);
}

handleSampleDefaults(traceIn, traceOut, coerce, layout);
if(traceOut.visible === false) return;

coerce('line.color', (traceIn.marker || {}).color || defaultColor);
coerce('line.width');
coerce('fillcolor', Color.addOpacity(traceOut.line.color, 0.5));

coerce('whiskerwidth');
coerce('boxmean');

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

function handleSampleDefaults(traceIn, traceOut, coerce, layout) {
var y = coerce('y');
var x = coerce('x');

Expand All @@ -39,25 +53,22 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
handleCalendarDefaults(traceIn, traceOut, ['x', 'y'], layout);

coerce('orientation', defaultOrientation);
}

coerce('line.color', (traceIn.marker || {}).color || defaultColor);
coerce('line.width');
coerce('fillcolor', Color.addOpacity(traceOut.line.color, 0.5));

coerce('whiskerwidth');
coerce('boxmean');
function handlePointsDefaults(traceIn, traceOut, coerce, opts) {
var prefix = opts.prefix;

var outlierColorDflt = Lib.coerce2(traceIn, traceOut, attributes, 'marker.outliercolor');
var lineoutliercolor = coerce('marker.line.outliercolor');

var boxpoints = coerce(
'boxpoints',
var points = coerce(
prefix + 'points',
(outlierColorDflt || lineoutliercolor) ? 'suspectedoutliers' : undefined
);

if(boxpoints) {
coerce('jitter', boxpoints === 'all' ? 0.3 : 0);
coerce('pointpos', boxpoints === 'all' ? -1.5 : 0);
if(points) {
coerce('jitter', points === 'all' ? 0.3 : 0);
coerce('pointpos', points === 'all' ? -1.5 : 0);

coerce('marker.symbol');
coerce('marker.opacity');
Expand All @@ -66,7 +77,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
coerce('marker.line.color');
coerce('marker.line.width');

if(boxpoints === 'suspectedoutliers') {
if(points === 'suspectedoutliers') {
coerce('marker.line.outliercolor', traceOut.marker.color);
coerce('marker.line.outlierwidth');
}
Expand All @@ -77,4 +88,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}

coerce('hoveron');
}

module.exports = {
supplyDefaults: supplyDefaults,
handleSampleDefaults: handleSampleDefaults,
handlePointsDefaults: handlePointsDefaults
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a separate reorganisation commit, to show a new way to factor out common trace module blocks. I think this method is a little more consistent with ES6 modules. For example here, supplyDefaults would be the default export.

};
6 changes: 3 additions & 3 deletions src/traces/box/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ var Box = {};

Box.attributes = require('./attributes');
Box.layoutAttributes = require('./layout_attributes');
Box.supplyDefaults = require('./defaults');
Box.supplyLayoutDefaults = require('./layout_defaults');
Box.supplyDefaults = require('./defaults').supplyDefaults;
Box.supplyLayoutDefaults = require('./layout_defaults').supplyLayoutDefaults;
Box.calc = require('./calc');
Box.setPositions = require('./set_positions');
Box.plot = require('./plot');
Box.plot = require('./plot').plot;
Box.style = require('./style');
Box.hoverPoints = require('./hover');
Box.selectPoints = require('./select');
Expand Down
24 changes: 16 additions & 8 deletions src/traces/box/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ var Registry = require('../../registry');
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, layoutAttributes, attr, dflt);
}

function _supply(layoutIn, layoutOut, fullData, coerce, prefix) {
var hasBoxes;
for(var i = 0; i < fullData.length; i++) {
if(Registry.traceIs(fullData[i], 'box')) {
Expand All @@ -26,7 +22,19 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
}
if(!hasBoxes) return;

coerce('boxmode');
coerce('boxgap');
coerce('boxgroupgap');
coerce(prefix + 'mode');
coerce(prefix + 'gap');
coerce(prefix + 'groupgap');
}

function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
function coerce(attr, dflt) {
return Lib.coerce(layoutIn, layoutOut, layoutAttributes, attr, dflt);
}
_supply(layoutIn, layoutOut, fullData, coerce, 'box');
}

module.exports = {
supplyLayoutDefaults: supplyLayoutDefaults,
_supply: _supply
};
Loading