From 44fa26926c4beaba5bc9f22f7b629bfd498a0cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 6 Nov 2018 12:07:18 -0500 Subject: [PATCH 1/5] inherit violin 'width' from box.width --- src/traces/violin/attributes.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/traces/violin/attributes.js b/src/traces/violin/attributes.js index 1842ba1fd9a..8006deda635 100644 --- a/src/traces/violin/attributes.js +++ b/src/traces/violin/attributes.js @@ -136,18 +136,13 @@ module.exports = { ].join(' ') }), - width: { - valType: 'number', - min: 0, - role: 'info', - dflt: 0, - editType: 'calc', + width: extendFlat({}, boxAttrs.width, { description: [ 'Sets the width of the violin.', 'If *0* (default value) the width is automatically selected based on the positions', 'of other violin traces in the same subplot.', ].join(' ') - }, + }), marker: boxAttrs.marker, text: boxAttrs.text, From f5ba38c2184dc5c65a8551adeb6c0b31b901fb78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 6 Nov 2018 12:26:24 -0500 Subject: [PATCH 2/5] rm useless attrs in test mock --- .../mocks/violin_box_multiple_widths.json | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/test/image/mocks/violin_box_multiple_widths.json b/test/image/mocks/violin_box_multiple_widths.json index 4e885c097fc..d8f8cb54dfd 100644 --- a/test/image/mocks/violin_box_multiple_widths.json +++ b/test/image/mocks/violin_box_multiple_widths.json @@ -3,57 +3,33 @@ "type": "violin", "width": 0.315, "x": [0, 5, 7, 8], - "points": "none", "side": "positive", - "box": { - "visible": false - }, - "boxpoints": false, "line": { "color": "black" }, "fillcolor": "#8dd3c7", "opacity": 0.6, - "meanline": { - "visible": false - }, "y0": 0.0 }, { "type": "violin", "x": [0, 5, 7, 8], - "points": "none", "side": "positive", - "box": { - "visible": false - }, - "boxpoints": false, "line": { "color": "black" }, "fillcolor": "#d3c78d", "opacity": 0.6, - "meanline": { - "visible": false - }, "y0": 0.1 }, { "type": "box", "width": 0.5421, "x": [0, 5, 7, 8], - "points": "none", "side": "positive", - "box": { - "visible": false - }, - "boxpoints": false, "line": { "color": "black" }, "fillcolor": "#c78dd3", "opacity": 0.6, - "meanline": { - "visible": false - }, "y0": 0.2 }], "layout": { From 34722d30de5538ccfd7ff6c2b52c7737e8a7dd74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 6 Nov 2018 16:59:42 -0500 Subject: [PATCH 3/5] mention that 'width' is in data coordinates --- src/traces/box/attributes.js | 4 ++-- src/traces/violin/attributes.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/traces/box/attributes.js b/src/traces/box/attributes.js index 58a4f47bcd8..e2f60b39ba1 100644 --- a/src/traces/box/attributes.js +++ b/src/traces/box/attributes.js @@ -179,9 +179,9 @@ module.exports = { dflt: 0, editType: 'calc', description: [ - 'Sets the width of the box.', + 'Sets the width of the box in data coordinate', 'If *0* (default value) the width is automatically selected based on the positions', - 'of other box traces in the same subplot.', + 'of other box traces in the same subplot.' ].join(' ') }, diff --git a/src/traces/violin/attributes.js b/src/traces/violin/attributes.js index 8006deda635..bdf6e3af3dc 100644 --- a/src/traces/violin/attributes.js +++ b/src/traces/violin/attributes.js @@ -138,7 +138,7 @@ module.exports = { width: extendFlat({}, boxAttrs.width, { description: [ - 'Sets the width of the violin.', + 'Sets the width of the violin in data coordinates.', 'If *0* (default value) the width is automatically selected based on the positions', 'of other violin traces in the same subplot.', ].join(' ') From d1aed48c1dc6ba567aed47f904023843545820c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 6 Nov 2018 17:01:30 -0500 Subject: [PATCH 4/5] ignore box/violin *gap and *groupgap when 'width' is set --- src/traces/box/layout_attributes.js | 9 ++++-- src/traces/box/plot.js | 21 +++++++++--- src/traces/violin/layout_attributes.js | 9 ++++-- src/traces/violin/plot.js | 30 ++++++++++++++---- .../baselines/violin_box_multiple_widths.png | Bin 27008 -> 29286 bytes .../mocks/violin_box_multiple_widths.json | 10 ++++-- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/traces/box/layout_attributes.js b/src/traces/box/layout_attributes.js index 2b75d7f4877..38b3658d264 100644 --- a/src/traces/box/layout_attributes.js +++ b/src/traces/box/layout_attributes.js @@ -22,7 +22,8 @@ module.exports = { 'If *group*, the boxes are plotted next to one another', 'centered around the shared location.', 'If *overlay*, the boxes are plotted over one another,', - 'you might need to set *opacity* to see them multiple boxes.' + 'you might need to set *opacity* to see them multiple boxes.', + 'Has no effect on traces that have *width* set.' ].join(' ') }, boxgap: { @@ -34,7 +35,8 @@ module.exports = { editType: 'calc', description: [ 'Sets the gap (in plot fraction) between boxes of', - 'adjacent location coordinates.' + 'adjacent location coordinates.', + 'Has no effect on traces that have *width* set.' ].join(' ') }, boxgroupgap: { @@ -46,7 +48,8 @@ module.exports = { editType: 'calc', description: [ 'Sets the gap (in plot fraction) between boxes of', - 'the same location coordinate.' + 'the same location coordinate.', + 'Has no effect on traces that have *width* set.' ].join(' ') } }; diff --git a/src/traces/box/plot.js b/src/traces/box/plot.js index 236bfe2b7ea..c362db07ada 100644 --- a/src/traces/box/plot.js +++ b/src/traces/box/plot.js @@ -22,8 +22,9 @@ function plot(gd, plotinfo, cdbox, boxLayer) { var xa = plotinfo.xaxis; var ya = plotinfo.yaxis; var numBoxes = fullLayout._numBoxes; - var groupFraction = (1 - fullLayout.boxgap); var group = (fullLayout.boxmode === 'group' && numBoxes > 1); + var groupFraction = (1 - fullLayout.boxgap); + var groupGapFraction = 1 - fullLayout.boxgroupgap; Lib.makeTraceGroups(boxLayer, cdbox, 'trace boxes').each(function(cd) { var plotGroup = d3.select(this); @@ -31,10 +32,22 @@ function plot(gd, plotinfo, cdbox, boxLayer) { var t = cd0.t; var trace = cd0.trace; if(!plotinfo.isRangePlot) cd0.node3 = plotGroup; - // box half width - var bdPos = t.dPos * groupFraction * (1 - fullLayout.boxgroupgap) / (group ? numBoxes : 1); + + // position coordinate delta + var dPos = t.dPos; + // box half width; + var bdPos; // box center offset - var bPos = group ? 2 * t.dPos * (-0.5 + (t.num + 0.5) / numBoxes) * groupFraction : 0; + var bPos; + + if(trace.width) { + bdPos = dPos; + bPos = 0; + } else { + bdPos = dPos * groupFraction * groupGapFraction / (group ? numBoxes : 1); + bPos = group ? 2 * dPos * (-0.5 + (t.num + 0.5) / numBoxes) * groupFraction : 0; + } + // whisker width var wdPos = bdPos * trace.whiskerwidth; diff --git a/src/traces/violin/layout_attributes.js b/src/traces/violin/layout_attributes.js index b02e309c660..ce6f1f2651a 100644 --- a/src/traces/violin/layout_attributes.js +++ b/src/traces/violin/layout_attributes.js @@ -19,19 +19,22 @@ module.exports = { 'If *group*, the violins are plotted next to one another', 'centered around the shared location.', 'If *overlay*, the violins are plotted over one another,', - 'you might need to set *opacity* to see them multiple violins.' + 'you might need to set *opacity* to see them multiple violins.', + 'Has no effect on traces that have *width* set.' ].join(' ') }), violingap: extendFlat({}, boxLayoutAttrs.boxgap, { description: [ 'Sets the gap (in plot fraction) between violins of', - 'adjacent location coordinates.' + 'adjacent location coordinates.', + 'Has no effect on traces that have *width* set.' ].join(' ') }), violingroupgap: extendFlat({}, boxLayoutAttrs.boxgroupgap, { description: [ 'Sets the gap (in plot fraction) between violins of', - 'the same location coordinate.' + 'the same location coordinate.', + 'Has no effect on traces that have *width* set.' ].join(' ') }) }; diff --git a/src/traces/violin/plot.js b/src/traces/violin/plot.js index 43b53a8046e..49126a86e30 100644 --- a/src/traces/violin/plot.js +++ b/src/traces/violin/plot.js @@ -20,6 +20,10 @@ module.exports = function plot(gd, plotinfo, cdViolins, violinLayer) { var fullLayout = gd._fullLayout; var xa = plotinfo.xaxis; var ya = plotinfo.yaxis; + var numViolins = fullLayout._numViolins; + var group = (fullLayout.violinmode === 'group' && numViolins > 1); + var groupFraction = 1 - fullLayout.violingap; + var groupGapFraction = 1 - fullLayout.violingroupgap; function makePath(pts) { var segments = linePoints(pts, { @@ -39,16 +43,30 @@ module.exports = function plot(gd, plotinfo, cdViolins, violinLayer) { var t = cd0.t; var trace = cd0.trace; if(!plotinfo.isRangePlot) cd0.node3 = plotGroup; - var numViolins = fullLayout._numViolins; - var group = (fullLayout.violinmode === 'group' && numViolins > 1); - var groupFraction = 1 - fullLayout.violingap; + + // position coordinate delta + var dPos = t.dPos; // violin max half width - var bdPos = t.bdPos = t.dPos * groupFraction * (1 - fullLayout.violingroupgap) / (group ? numViolins : 1); + var bdPos; // violin center offset - var bPos = t.bPos = group ? 2 * t.dPos * (-0.5 + (t.num + 0.5) / numViolins) * groupFraction : 0; + var bPos; // half-width within which to accept hover for this violin // always split the distance to the closest violin - t.wHover = t.dPos * (group ? groupFraction / numViolins : 1); + var wHover; + + if(trace.width) { + bdPos = dPos; + bPos = 0; + wHover = dPos; + } else { + bdPos = dPos * groupFraction * groupGapFraction / (group ? numViolins : 1); + bPos = group ? 2 * dPos * (-0.5 + (t.num + 0.5) / numViolins) * groupFraction : 0; + wHover = dPos * (group ? groupFraction / numViolins : 1); + } + + t.bdPos = bdPos; + t.bPos = bPos; + t.wHover = wHover; if(trace.visible !== true || t.empty) { plotGroup.remove(); diff --git a/test/image/baselines/violin_box_multiple_widths.png b/test/image/baselines/violin_box_multiple_widths.png index 689bc9e6f1409deb3cbab57c89367cf513dc32f9..d84c0ec8dc3e1e799f9381fc8a6d8d0939af6b05 100644 GIT binary patch literal 29286 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%0A5a|=Kb*8EjRL8xI9Mx+vULLz`J-t;qD_KBk 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 literal 27008 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 diff --git a/test/image/mocks/violin_box_multiple_widths.json b/test/image/mocks/violin_box_multiple_widths.json index d8f8cb54dfd..f8bb39d0f81 100644 --- a/test/image/mocks/violin_box_multiple_widths.json +++ b/test/image/mocks/violin_box_multiple_widths.json @@ -1,7 +1,8 @@ { "data": [{ "type": "violin", - "width": 0.315, + "width": 0.4, + "name": "width: 0.4", "x": [0, 5, 7, 8], "side": "positive", "line": { @@ -12,6 +13,7 @@ "y0": 0.0 }, { "type": "violin", + "name": "auto", "x": [0, 5, 7, 8], "side": "positive", "line": { @@ -22,7 +24,8 @@ "y0": 0.1 }, { "type": "box", - "width": 0.5421, + "width": 0.6, + "name": "width: 0.6", "x": [0, 5, 7, 8], "side": "positive", "line": { @@ -34,7 +37,8 @@ }], "layout": { "title": "Joyplot - Violin with multiple widths", + "legend": {"x": 0}, "xaxis": {"zeroline": false}, - "violingap": 0 + "yaxis": {"dtick": 0.1, "gridcolor": "black"} } } From c70f7d532055af63a2416c0a60167d0f2f81216d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 6 Nov 2018 17:03:13 -0500 Subject: [PATCH 5/5] do not coerce scale* attrs when violin 'width' is set - do not fill in fullLayout._violinScaleGroupStats for traces with set 'width' - use maxKDE key instead of maxWidth to avoid confusing --- src/traces/violin/calc.js | 35 +++++++++++++++++++------------ src/traces/violin/defaults.js | 4 +--- src/traces/violin/plot.js | 17 +++++++-------- test/jasmine/tests/violin_test.js | 19 ++++++++++++++++- 4 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/traces/violin/calc.js b/src/traces/violin/calc.js index 1994f4235c3..52a72e57462 100644 --- a/src/traces/violin/calc.js +++ b/src/traces/violin/calc.js @@ -25,18 +25,10 @@ module.exports = function calc(gd, trace) { trace[trace.orientation === 'h' ? 'xaxis' : 'yaxis'] ); - var violinScaleGroupStats = fullLayout._violinScaleGroupStats; - var scaleGroup = trace.scalegroup; - var groupStats = violinScaleGroupStats[scaleGroup]; - if(!groupStats) { - groupStats = violinScaleGroupStats[scaleGroup] = { - maxWidth: 0, - maxCount: 0 - }; - } - var spanMin = Infinity; var spanMax = -Infinity; + var maxKDE = 0; + var maxCount = 0; for(var i = 0; i < cd.length; i++) { var cdi = cd[i]; @@ -61,12 +53,11 @@ module.exports = function calc(gd, trace) { for(var k = 0, t = span[0]; t < (span[1] + step / 2); k++, t += step) { var v = kde(t); - groupStats.maxWidth = Math.max(groupStats.maxWidth, v); cdi.density[k] = {v: v, t: t}; + maxKDE = Math.max(maxKDE, v); } - groupStats.maxCount = Math.max(groupStats.maxCount, vals.length); - + maxCount = Math.max(maxCount, vals.length); spanMin = Math.min(spanMin, span[0]); spanMax = Math.max(spanMax, span[1]); } @@ -74,6 +65,24 @@ module.exports = function calc(gd, trace) { var extremes = Axes.findExtremes(valAxis, [spanMin, spanMax], {padded: true}); trace._extremes[valAxis._id] = extremes; + if(trace.width) { + cd[0].t.maxKDE = maxKDE; + } else { + var violinScaleGroupStats = fullLayout._violinScaleGroupStats; + var scaleGroup = trace.scalegroup; + var groupStats = violinScaleGroupStats[scaleGroup]; + + if(groupStats) { + groupStats.maxKDE = Math.max(groupStats.maxKDE, maxKDE); + groupStats.maxCount = Math.max(groupStats.maxCount, maxCount); + } else { + violinScaleGroupStats[scaleGroup] = { + maxKDE: maxKDE, + maxCount: maxCount + }; + } + } + cd[0].t.labels.kde = Lib._(gd, 'kde:'); return cd; diff --git a/src/traces/violin/defaults.js b/src/traces/violin/defaults.js index 7cb660ec0a3..3b394518d87 100644 --- a/src/traces/violin/defaults.js +++ b/src/traces/violin/defaults.js @@ -27,13 +27,11 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('bandwidth'); coerce('side'); + var width = coerce('width'); if(!width) { coerce('scalegroup', traceOut.name); coerce('scalemode'); - } else { - traceOut.scalegroup = ''; - traceOut.scalemode = 'width'; } var span = coerce('span'); diff --git a/src/traces/violin/plot.js b/src/traces/violin/plot.js index 49126a86e30..de046a5a9b2 100644 --- a/src/traces/violin/plot.js +++ b/src/traces/violin/plot.js @@ -78,7 +78,6 @@ module.exports = function plot(gd, plotinfo, cdViolins, violinLayer) { var hasBothSides = trace.side === 'both'; var hasPositiveSide = hasBothSides || trace.side === 'positive'; var hasNegativeSide = hasBothSides || trace.side === 'negative'; - var groupStats = fullLayout._violinScaleGroupStats[trace.scalegroup]; var violins = plotGroup.selectAll('path.violin').data(Lib.identity); @@ -94,15 +93,15 @@ module.exports = function plot(gd, plotinfo, cdViolins, violinLayer) { var len = density.length; var posCenter = d.pos + bPos; var posCenterPx = posAxis.c2p(posCenter); - var scale; - switch(trace.scalemode) { - case 'width': - scale = groupStats.maxWidth / bdPos; - break; - case 'count': - scale = (groupStats.maxWidth / bdPos) * (groupStats.maxCount / d.pts.length); - break; + var scale; + if(trace.width) { + scale = t.maxKDE / bdPos; + } else { + var groupStats = fullLayout._violinScaleGroupStats[trace.scalegroup]; + scale = trace.scalemode === 'count' ? + (groupStats.maxKDE / bdPos) * (groupStats.maxCount / d.pts.length) : + groupStats.maxKDE / bdPos; } var pathPos, pathNeg, path; diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index a7e973ff1f2..643f7548e5d 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -142,6 +142,23 @@ describe('Test violin defaults', function() { expect(traceOut.meanline.color).toBe('blue'); expect(traceOut.meanline.width).toBe(10); }); + + it('should not coerce *scalegroup* and *scalemode* when *width* is set', function() { + _supply({ + y: [1, 2, 1], + width: 1 + }); + expect(traceOut.scalemode).toBeUndefined(); + expect(traceOut.scalegroup).toBeUndefined(); + + _supply({ + y: [1, 2, 1], + // width=0 is ignored during calc + width: 0 + }); + expect(traceOut.scalemode).toBe('width'); + expect(traceOut.scalegroup).toBe(''); + }); }); describe('Test violin calc:', function() { @@ -236,7 +253,7 @@ describe('Test violin calc:', function() { name: 'one', y: [0, 0, 0, 0, 10, 10, 10, 10] }); - expect(fullLayout._violinScaleGroupStats.one.maxWidth).toBeCloseTo(0.055); + expect(fullLayout._violinScaleGroupStats.one.maxKDE).toBeCloseTo(0.055); expect(fullLayout._violinScaleGroupStats.one.maxCount).toBe(8); });