Skip to content

Commit 81ddaca

Browse files
authored
Merge pull request #2116 from plotly/violins-dev
Violin plots
2 parents 4b8b10d + 789121c commit 81ddaca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+3389
-433
lines changed

lib/index-cartesian.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Plotly.register([
1919
require('./histogram2dcontour'),
2020
require('./pie'),
2121
require('./contour'),
22-
require('./scatterternary')
22+
require('./scatterternary'),
23+
require('./violin')
2324
]);
2425

2526
module.exports = Plotly;

lib/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Plotly.register([
2121
require('./pie'),
2222
require('./contour'),
2323
require('./scatterternary'),
24-
require('./sankey'),
24+
require('./violin'),
2525

2626
require('./scatter3d'),
2727
require('./surface'),
@@ -34,10 +34,13 @@ Plotly.register([
3434
require('./pointcloud'),
3535
require('./heatmapgl'),
3636
require('./parcoords'),
37-
require('./table'),
3837

3938
require('./scattermapbox'),
4039

40+
require('./sankey'),
41+
42+
require('./table'),
43+
4144
require('./carpet'),
4245
require('./scattercarpet'),
4346
require('./contourcarpet'),

lib/violin.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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+
module.exports = require('../src/traces/violin');

src/components/fx/hover.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ function _hover(gd, evt, subplot, noHoverEvent) {
381381

382382
// Now find the points.
383383
if(trace._module && trace._module.hoverPoints) {
384-
var newPoints = trace._module.hoverPoints(pointData, xval, yval, mode);
384+
var newPoints = trace._module.hoverPoints(pointData, xval, yval, mode, fullLayout._hoverlayer);
385385
if(newPoints) {
386386
var newPoint;
387387
for(var newPointNum = 0; newPointNum < newPoints.length; newPointNum++) {

src/components/legend/style.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ module.exports = function style(s, gd) {
197197
var trace = d[0].trace,
198198
pts = d3.select(this).select('g.legendpoints')
199199
.selectAll('path.legendbox')
200-
.data(Registry.traceIs(trace, 'box') && trace.visible ? [d] : []);
200+
.data(Registry.traceIs(trace, 'box-violin') && trace.visible ? [d] : []);
201201
pts.enter().append('path').classed('legendbox', true)
202202
// if we want the median bar, prepend M6,0H-6
203203
.attr('d', 'M6,6H-6V-6H6Z')

src/components/modebar/manage.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ function isSelectable(fullData) {
179179
if(scatterSubTypes.hasMarkers(trace) || scatterSubTypes.hasText(trace)) {
180180
selectable = true;
181181
}
182-
} else if(Registry.traceIs(trace, 'box')) {
183-
if(trace.boxpoints === 'all') {
182+
} else if(Registry.traceIs(trace, 'box-violin')) {
183+
if(trace.boxpoints === 'all' || trace.points === 'all') {
184184
selectable = true;
185185
}
186186
}

src/lib/geometry2d.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,52 @@ exports.getVisibleSegment = function getVisibleSegment(path, bounds, buffer) {
193193
Math.abs(pt0.y - ptTotal.y) < 0.1
194194
};
195195
};
196+
197+
/**
198+
* Find point on SVG path corresponding to a given constraint coordinate
199+
*
200+
* @param {SVGPathElement} path
201+
* @param {Number} val : constraint coordinate value
202+
* @param {String} coord : 'x' or 'y' the constraint coordinate
203+
* @param {Object} opts :
204+
* - {Number} pathLength : supply total path length before hand
205+
* - {Number} tolerance
206+
* - {Number} iterationLimit
207+
* @return {SVGPoint}
208+
*/
209+
exports.findPointOnPath = function findPointOnPath(path, val, coord, opts) {
210+
opts = opts || {};
211+
212+
var pathLength = opts.pathLength || path.getTotalLength();
213+
var tolerance = opts.tolerance || 1e-3;
214+
var iterationLimit = opts.iterationLimit || 30;
215+
216+
// if path starts at a val greater than the path tail (like on vertical violins),
217+
// we must flip the sign of the computed diff.
218+
var mul = path.getPointAtLength(0)[coord] > path.getPointAtLength(pathLength)[coord] ? -1 : 1;
219+
220+
var i = 0;
221+
var b0 = 0;
222+
var b1 = pathLength;
223+
var mid;
224+
var pt;
225+
var diff;
226+
227+
while(i < iterationLimit) {
228+
mid = (b0 + b1) / 2;
229+
pt = path.getPointAtLength(mid);
230+
diff = pt[coord] - val;
231+
232+
if(Math.abs(diff) < tolerance) {
233+
return pt;
234+
} else {
235+
if(mul * diff > 0) {
236+
b1 = mid;
237+
} else {
238+
b0 = mid;
239+
}
240+
i++;
241+
}
242+
}
243+
return pt;
244+
};

src/lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ lib.segmentDistance = geom2dModule.segmentDistance;
8282
lib.getTextLocation = geom2dModule.getTextLocation;
8383
lib.clearLocationCache = geom2dModule.clearLocationCache;
8484
lib.getVisibleSegment = geom2dModule.getVisibleSegment;
85+
lib.findPointOnPath = geom2dModule.findPointOnPath;
8586

8687
var extendModule = require('./extend');
8788
lib.extendFlat = extendModule.extendFlat;

src/plots/cartesian/constants.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,13 @@ module.exports = {
5757
DFLTRANGEX: [-1, 6],
5858
DFLTRANGEY: [-1, 4],
5959

60-
// Layers to keep trace types in the right order.
61-
// from back to front:
62-
// 1. heatmaps, 2D histos and contour maps
63-
// 2. bars / 1D histos
64-
// 3. errorbars for bars and scatter
65-
// 4. scatter
66-
// 5. box plots
60+
// Layers to keep trace types in the right order
6761
traceLayerClasses: [
6862
'imagelayer',
6963
'maplayer',
7064
'barlayer',
7165
'carpetlayer',
66+
'violinlayer',
7267
'boxlayer',
7368
'scatterlayer'
7469
],

src/plots/cartesian/type_defaults.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function setAutoType(ax, data) {
7575

7676
for(var i = 0; i < data.length; i++) {
7777
trace = data[i];
78-
if(!Registry.traceIs(trace, 'box') ||
78+
if(!Registry.traceIs(trace, 'box-violin') ||
7979
(trace[axLetter + 'axis'] || axLetter) !== id) continue;
8080

8181
if(trace[posLetter] !== undefined) boxPositions.push(trace[posLetter][0]);
@@ -113,7 +113,7 @@ function getBoxPosLetter(trace) {
113113

114114
function isBoxWithoutPositionCoords(trace, axLetter) {
115115
var posLetter = getBoxPosLetter(trace),
116-
isBox = Registry.traceIs(trace, 'box'),
116+
isBox = Registry.traceIs(trace, 'box-violin'),
117117
isCandlestick = Registry.traceIs(trace._fullInput || {}, 'candlestick');
118118

119119
return (

0 commit comments

Comments
 (0)