From 63afa3c2fd43f091b33e19a0a7d565e02c2638b0 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Thu, 12 May 2022 10:51:33 -0400 Subject: [PATCH 01/10] revise box & violin hover labels - order & handle duplicates --- src/traces/box/hover.js | 41 +++++++++++++++++------- test/jasmine/tests/box_test.js | 44 +++++++++++++++++--------- test/jasmine/tests/hover_label_test.js | 17 ++++++++-- test/jasmine/tests/violin_test.js | 21 ++++++++---- 4 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 6ae73777347..86b68c3cc86 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -44,7 +44,6 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { var trace = cd[0].trace; var t = cd[0].t; var isViolin = trace.type === 'violin'; - var closeBoxData = []; var pLetter, vLetter, pAxis, vAxis, vVal, pVal, dx, dy, dPos, hoverPseudoDistance, spikePseudoDistance; @@ -141,22 +140,27 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { pointData.spikeDistance = dxy(di) * spikePseudoDistance / hoverPseudoDistance; pointData[spikePosAttr] = pAxis.c2p(di.pos, true); - // box plots: each "point" gets many labels - var usedVals = {}; - var attrs = ['med', 'q1', 'q3', 'min', 'max']; + var hasMean = trace.boxmean || (trace.meanline || {}).visible; + var hasFences = trace.boxpoints || trace.points; - if(trace.boxmean || (trace.meanline || {}).visible) { - attrs.push('mean'); - } - if(trace.boxpoints || trace.points) { - attrs.push('lf', 'uf'); - } + // labels with euqual values (e.g. when min === q1) should be presented in certain order + var attrs = + (hasFences && hasMean) ? ['uf', 'max', 'q3', 'mean', 'q1', 'min', 'lf'] : + (hasFences && !hasMean) ? ['uf', 'max', 'q3', 'q1', 'min', 'lf'] : + (!hasFences && hasMean) ? ['max', 'q3', 'mean', 'q1', 'min'] : + ['max', 'q3', 'q1', 'min']; + + if(trace.orientation === 'h') attrs.reverse(); + + // always put median at the start so that it get the extra label + attrs = ['med'].concat(attrs); + var closeBoxData = []; + var lf, uf, min, max; for(var i = 0; i < attrs.length; i++) { var attr = attrs[i]; - if(!(attr in di) || (di[attr] in usedVals)) continue; - usedVals[di[attr]] = true; + if(!(attr in di)) continue; // copy out to a new object for each value to label var val = di[attr]; @@ -185,6 +189,19 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { pointData2.hovertemplate = false; closeBoxData.push(pointData2); + + if(attr === 'lf') lf = val; + if(attr === 'uf') uf = val; + if(attr === 'max') max = val; + if(attr === 'min') min = val; + } + + // reduce labels if uf === max or lf === min + if(uf === max) { + closeBoxData = closeBoxData.filter(function(e) { return e.attr !== 'uf'; }); + } + if(lf === min) { + closeBoxData = closeBoxData.filter(function(e) { return e.attr !== 'lf'; }); } return closeBoxData; diff --git a/test/jasmine/tests/box_test.js b/test/jasmine/tests/box_test.js index ac271d4df97..e6a1d207ff8 100644 --- a/test/jasmine/tests/box_test.js +++ b/test/jasmine/tests/box_test.js @@ -795,12 +795,18 @@ describe('Test box hover:', function() { return fig; }, nums: [ - 'q1: 0.3', 'median: 0.45', 'q3: 0.6', 'max: 1', 'median: 0.55', 'min: 0', 'q1: 0.1', - 'q3: 0.6', 'max: 0.7', 'median: 0.45', 'q1: 0.2', 'q3: 0.6', 'max: 0.9' + 'median: 0.45', 'median: 0.45', 'median: 0.55', + 'min: 0', 'min: 0.1', 'min: 0.2', + 'q1: 0.1', 'q1: 0.2', 'q1: 0.3', + 'q3: 0.6', 'q3: 0.6', 'q3: 0.6', + 'max: 0.7', 'max: 0.9', 'max: 1' ], name: [ - '', 'kale', '', '', 'radishes', '', '', - '', '', 'carrots', '', '', '' + 'carrots', 'kale', 'radishes', + '', '', '', + '', '', '', + '', '', '', + '', '', '' ], axis: 'day 1' }, { @@ -909,20 +915,28 @@ describe('Test box hover:', function() { }, pos: [430, 130], nums: [ - 'max: 1', 'mean ± σ: 0.6833333 ± 0.2409472', 'min: 0.3', - 'q1: 0.5', 'q3: 0.9', 'median: 0.7'], - name: ['', '', '', '', '', 'carrots'], - axis: 'day 2', - hOrder: [0, 4, 5, 1, 3, 2] + 'median: 0.7', + 'min: 0.3', + 'q1: 0.5', + 'q3: 0.9', + 'max: 1', + 'mean ± σ: 0.6833333 ± 0.2409472', + ], + name: ['carrots', '', '', '', '', ''], + axis: 'day 2' }, { desc: 'orientation:h | hovermode:closest', mock: require('@mocks/box_grouped_horz.json'), pos: [430, 130], nums: [ - '(max: 1, day 2)', '(mean ± σ: 0.6833333 ± 0.2409472, day 2)', '(min: 0.3, day 2)', - '(q1: 0.5, day 2)', '(q3: 0.9, day 2)', '(median: 0.7, day 2)'], - name: ['', '', '', '', '', 'carrots'], - hOrder: [0, 4, 5, 1, 3, 2] + '(median: 0.7, day 2)', + '(min: 0.3, day 2)', + '(q1: 0.5, day 2)', + '(q3: 0.9, day 2)', + '(max: 1, day 2)', + '(mean ± σ: 0.6833333 ± 0.2409472, day 2)' + ], + name: ['carrots', '', '', '', '', ''], }, { desc: 'on boxpoints with numeric positions | hovermode:closest', mock: { @@ -987,8 +1001,8 @@ describe('Test box hover:', function() { } }, pos: [200, 200], - nums: ['median: 2', 'q1: 1', 'q3: 3'], - name: ['', '', ''], + nums: ['median: 2', 'min: 1', 'q1: 1', 'q3: 3', 'max: 3'], + name: ['', '', '', '', ''], axis: 'A' }, { desc: 'q1/median/q3 signature on points', diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 0461344a3f1..933ca74bb81 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4673,6 +4673,10 @@ describe('hovermode: (x|y)unified', function() { assertLabel({title: '3', items: [ 'trace 0 : 2', + 'min: 1', + 'q1: 1', + 'q3: 1', + 'max: 1', 'trace 1 : median: 1', 'trace 3 : 2', 'trace 2 : 2', @@ -6262,7 +6266,16 @@ describe('hover on traces with (x|y)hoverformat', function() { {type: 'scattergl', nums: '(02/01/2000, 1.00)'}, {type: 'histogram', nums: '(02/01/2000, 1.00)'}, {type: 'bar', nums: '(02/01/2000, 1.00)'}, - {type: 'box', nums: '(02/01/2000, median: 1.00)'}, + {type: 'box', + name: ['', '', '', '', ''], + nums: [ + '(02/01/2000, median: 1.00)', + '(02/01/2000, max: 1.00)', + '(02/01/2000, q3: 1.00)', + '(02/01/2000, q1: 1.00)', + '(02/01/2000, min: 1.00)' + ] + }, {type: 'ohlc', nums: '02/01/2000\nopen: 4.00\nhigh: 5.00\nlow: 2.00\nclose: 3.00 ▼'}, {type: 'candlestick', nums: '02/01/2000\nopen: 4.00\nhigh: 5.00\nlow: 2.00\nclose: 3.00 ▼'}, {type: 'waterfall', nums: '(02/01/2000, 1.00)\n1.00 ▲\nInitial: 0.00'}, @@ -6286,7 +6299,7 @@ describe('hover on traces with (x|y)hoverformat', function() { .then(function() { _hover(200, 200); }) .then(function() { assertHoverLabelContent({ - name: '', + name: t.name ? t.name : '', nums: t.nums }); }) diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index 4b111891583..3d9b1de64e8 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -394,13 +394,20 @@ describe('Test violin hover:', function() { return fig; }, nums: [ - 'q3: 0.6', 'median: 0.45', 'q3: 0.6', 'max: 1', 'y: 0.9266848, kde: 0.383', - 'median: 0.55', 'min: 0', 'q1: 0.3', 'q1: 0.2', 'max: 0.7', 'y: 0.9266848, kde: 0.182', - 'median: 0.45', 'q1: 0.1', 'q3: 0.6', 'max: 0.9', 'y: 0.9266848, kde: 0.435' + 'median: 0.45', 'median: 0.45', 'median: 0.55', + 'min: 0', 'min: 0.1', 'min: 0.2', + 'q1: 0.1', 'q1: 0.2', 'q1: 0.3', + 'q3: 0.6', 'q3: 0.6', 'q3: 0.6', + 'max: 0.7', 'max: 0.9', 'max: 1', + 'y: 0.9266848, kde: 0.383', 'y: 0.9266848, kde: 0.182', 'y: 0.9266848, kde: 0.435' ], name: [ - '', 'kale', '', '', '', 'radishes', '', '', '', '', - '', 'carrots', '', '', '', '' + 'carrots', 'kale', 'radishes', + '', '', '', + '', '', '', + '', '', '', + '', '', '', + '', '', '' ], axis: 'day 1' }, { @@ -531,13 +538,13 @@ describe('Test violin hover:', function() { return fig; }, nums: [ - 'max: 50.81', 'median: 18.24', 'min: 3.07', + 'max: 50.81', 'min: 3.07', 'median: 18.24', 'q1: 13.8575', 'q3: 24.975', 'upper fence: 39.42' ], name: ['', '', '', '', '', ''], axis: 'Sat', hoverLabelPos: [ - [364, 270], [352, 270], [339, 270], + [364, 270], [339, 270], [352, 270], [346, 270], [349, 270], [387, 270] ] }, { From ca5f2d981f75a823f3d013f7c17f9125e7fbac8d Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Thu, 12 May 2022 19:03:19 -0400 Subject: [PATCH 02/10] draft log for PR 6189 --- draftlogs/6189_fix.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/6189_fix.md diff --git a/draftlogs/6189_fix.md b/draftlogs/6189_fix.md new file mode 100644 index 00000000000..ddf1ac2645c --- /dev/null +++ b/draftlogs/6189_fix.md @@ -0,0 +1 @@ + - Fix undesirable missing hover labels of `box` & `violin` traces [[#6189](https://github.com/plotly/plotly.js/pull/6189)] From f7262481cb28bbd9f811400502459db23bc5d7a9 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Thu, 26 May 2022 09:55:47 -0400 Subject: [PATCH 03/10] revise order of displaying lf and uf in box hover --- src/traces/box/hover.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 86b68c3cc86..c982a1ae90d 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -145,8 +145,8 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { // labels with euqual values (e.g. when min === q1) should be presented in certain order var attrs = - (hasFences && hasMean) ? ['uf', 'max', 'q3', 'mean', 'q1', 'min', 'lf'] : - (hasFences && !hasMean) ? ['uf', 'max', 'q3', 'q1', 'min', 'lf'] : + (hasFences && hasMean) ? ['max', 'uf', 'q3', 'mean', 'q1', 'lf', 'min'] : + (hasFences && !hasMean) ? ['max', 'uf', 'q3', 'q1', 'lf', 'min'] : (!hasFences && hasMean) ? ['max', 'q3', 'mean', 'q1', 'min'] : ['max', 'q3', 'q1', 'min']; From e189c4dc842a4d627fcd204bf5dc1d28cfba6f02 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Thu, 26 May 2022 15:56:27 -0400 Subject: [PATCH 04/10] display upper/lower fences even if equal to man/min --- src/traces/box/hover.js | 14 ------ test/jasmine/tests/box_test.js | 40 +++++++++------ test/jasmine/tests/hover_label_test.js | 18 +++++-- test/jasmine/tests/violin_test.js | 69 +++++++++++++++----------- 4 files changed, 76 insertions(+), 65 deletions(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index c982a1ae90d..024086b89e3 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -156,7 +156,6 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { attrs = ['med'].concat(attrs); var closeBoxData = []; - var lf, uf, min, max; for(var i = 0; i < attrs.length; i++) { var attr = attrs[i]; @@ -189,19 +188,6 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { pointData2.hovertemplate = false; closeBoxData.push(pointData2); - - if(attr === 'lf') lf = val; - if(attr === 'uf') uf = val; - if(attr === 'max') max = val; - if(attr === 'min') min = val; - } - - // reduce labels if uf === max or lf === min - if(uf === max) { - closeBoxData = closeBoxData.filter(function(e) { return e.attr !== 'uf'; }); - } - if(lf === min) { - closeBoxData = closeBoxData.filter(function(e) { return e.attr !== 'lf'; }); } return closeBoxData; diff --git a/test/jasmine/tests/box_test.js b/test/jasmine/tests/box_test.js index e6a1d207ff8..c30e59b8d12 100644 --- a/test/jasmine/tests/box_test.js +++ b/test/jasmine/tests/box_test.js @@ -743,8 +743,8 @@ describe('Test box hover:', function() { fig.layout.hovermode = 'x'; return fig; }, - nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'], - name: ['radishes', '', '', '', ''], + nums: ['median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7'], + name: ['radishes', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'with mean', @@ -755,8 +755,8 @@ describe('Test box hover:', function() { fig.layout.hovermode = 'x'; return fig; }, - nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', 'mean: 0.45'], - name: ['radishes', '', '', '', '', ''], + nums: ['median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7', 'mean: 0.45'], + name: ['radishes', '', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'with sd', @@ -768,10 +768,10 @@ describe('Test box hover:', function() { return fig; }, nums: [ - 'median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', + 'median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7', 'mean ± σ: 0.45 ± 0.2362908' ], - name: ['radishes', '', '', '', '', ''], + name: ['radishes', '', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'with boxpoints fences', @@ -797,8 +797,10 @@ describe('Test box hover:', function() { nums: [ 'median: 0.45', 'median: 0.45', 'median: 0.55', 'min: 0', 'min: 0.1', 'min: 0.2', + 'lower fence: 0', 'lower fence: 0.1', 'lower fence: 0.2', 'q1: 0.1', 'q1: 0.2', 'q1: 0.3', 'q3: 0.6', 'q3: 0.6', 'q3: 0.6', + 'upper fence: 0.7', 'upper fence: 0.9', 'upper fence: 1', 'max: 0.7', 'max: 0.9', 'max: 1' ], name: [ @@ -806,6 +808,8 @@ describe('Test box hover:', function() { '', '', '', '', '', '', '', '', '', + '', '', '', + '', '', '', '', '', '' ], axis: 'day 1' @@ -847,8 +851,8 @@ describe('Test box hover:', function() { return fig; }, pos: [215, 200], - nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'], - name: ['radishes', '', '', '', ''], + nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', 'lower fence: 0', 'upper fence: 0.7'], + name: ['radishes', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'hoveron boxes+points | hovermode x (box AND closest point)', @@ -861,8 +865,8 @@ describe('Test box hover:', function() { fig.layout.hovermode = 'x'; return fig; }, - nums: ['0.6', 'median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'], - name: ['radishes', 'radishes', '', '', '', ''], + nums: ['0.6', 'median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', 'lower fence: 0', 'upper fence: 0.7'], + name: ['radishes', 'radishes', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'text items on hover', @@ -920,9 +924,11 @@ describe('Test box hover:', function() { 'q1: 0.5', 'q3: 0.9', 'max: 1', + 'lower fence: 0.3', + 'upper fence: 1', 'mean ± σ: 0.6833333 ± 0.2409472', ], - name: ['carrots', '', '', '', '', ''], + name: ['carrots', '', '', '', '', '', '', ''], axis: 'day 2' }, { desc: 'orientation:h | hovermode:closest', @@ -934,9 +940,11 @@ describe('Test box hover:', function() { '(q1: 0.5, day 2)', '(q3: 0.9, day 2)', '(max: 1, day 2)', + '(lower fence: 0.3, day 2)', + '(upper fence: 1, day 2)', '(mean ± σ: 0.6833333 ± 0.2409472, day 2)' ], - name: ['carrots', '', '', '', '', ''], + name: ['carrots', '', '', '', '', '', '', ''], }, { desc: 'on boxpoints with numeric positions | hovermode:closest', mock: { @@ -981,8 +989,8 @@ describe('Test box hover:', function() { } }, pos: [200, 200], - nums: ['median: 2', 'q1: 1.5', 'q3: 2.5', 'max: 3', 'min: 1'], - name: ['', '', '', '', ''], + nums: ['median: 2', 'q1: 1.5', 'q3: 2.5', 'max: 3', 'min: 1', 'lower fence: 1', 'upper fence: 3'], + name: ['', '', '', '', '', '', ''], axis: 'trace 0' }, { desc: 'q1/median/q3 signature on boxes', @@ -1001,8 +1009,8 @@ describe('Test box hover:', function() { } }, pos: [200, 200], - nums: ['median: 2', 'min: 1', 'q1: 1', 'q3: 3', 'max: 3'], - name: ['', '', '', '', ''], + nums: ['median: 2', 'min: 1', 'q1: 1', 'q3: 3', 'max: 3', 'lower fence: 1', 'upper fence: 3'], + name: ['', '', '', '', '', '', ''], axis: 'A' }, { desc: 'q1/median/q3 signature on points', diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index 933ca74bb81..e733f2d2bd0 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -2833,21 +2833,25 @@ describe('hover on traces with (x|y)period positioning', function() { .then(function() { _hover(385, 355); }) .then(function() { assertHoverLabelContent({ - name: ['', '', '', 'box (v)', ''], + name: ['', '', '', 'box (v)', '', '', ''], nums: [ '(Jan 2001, min: 2)', + '(Jan 2001, lower fence: 2)', '(Jan 2001, q1: 4)', - '(Jan 2001, q3: 8)', '(Jan 2001, median: 6)', - '(Jan 2001, max: 10)', + '(Jan 2001, q3: 8)', + '(Jan 2001, upper fence: 10)', + '(Jan 2001, max: 10)' ] }); }) .then(function() { _hover(475, 120); }) .then(function() { assertHoverLabelContent({ - name: ['', '', '', '', 'box (h)'], + name: ['', '', '', '', '', '', 'box (h)'], nums: [ + '(upper fence: 8, Jan 2004)', + '(lower fence: 0, Jan 2004)', '(max: 8, Jan 2004)', '(min: 0, Jan 2004)', '(q1: 2, Jan 2004)', @@ -4674,8 +4678,10 @@ describe('hovermode: (x|y)unified', function() { assertLabel({title: '3', items: [ 'trace 0 : 2', 'min: 1', + 'lower fence: 1', 'q1: 1', 'q3: 1', + 'upper fence: 1', 'max: 1', 'trace 1 : median: 1', 'trace 3 : 2', @@ -6267,12 +6273,14 @@ describe('hover on traces with (x|y)hoverformat', function() { {type: 'histogram', nums: '(02/01/2000, 1.00)'}, {type: 'bar', nums: '(02/01/2000, 1.00)'}, {type: 'box', - name: ['', '', '', '', ''], + name: ['', '', '', '', '', '', ''], nums: [ '(02/01/2000, median: 1.00)', '(02/01/2000, max: 1.00)', + '(02/01/2000, upper fence: 1.00)', '(02/01/2000, q3: 1.00)', '(02/01/2000, q1: 1.00)', + '(02/01/2000, lower fence: 1.00)', '(02/01/2000, min: 1.00)' ] }, diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index 3d9b1de64e8..2311a4ccaa4 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -366,10 +366,10 @@ describe('Test violin hover:', function() { return fig; }, nums: [ - 'median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', + 'median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7', 'y: 0.9266848, kde: 0.182' ], - name: ['radishes', '', '', '', '', ''], + name: ['radishes', '', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'with mean', @@ -381,25 +381,30 @@ describe('Test violin hover:', function() { return fig; }, nums: [ - 'median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7', 'mean: 0.45', + 'median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7', 'mean: 0.45', 'y: 0.9266848, kde: 0.182' ], - name: ['radishes', '', '', '', '', '', ''], + name: ['radishes', '', '', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'with overlaid violins', patch: function(fig) { fig.layout.violinmode = 'overlay'; fig.layout.hovermode = 'x'; + fig.layout.height = 700; + return fig; }, nums: [ 'median: 0.45', 'median: 0.45', 'median: 0.55', 'min: 0', 'min: 0.1', 'min: 0.2', + 'lower fence: 0', 'lower fence: 0.1', 'lower fence: 0.2', 'q1: 0.1', 'q1: 0.2', 'q1: 0.3', 'q3: 0.6', 'q3: 0.6', 'q3: 0.6', + 'upper fence: 0.7', 'upper fence: 0.9', 'upper fence: 1', 'max: 0.7', 'max: 0.9', 'max: 1', - 'y: 0.9266848, kde: 0.383', 'y: 0.9266848, kde: 0.182', 'y: 0.9266848, kde: 0.435' + 'y: 1.211363, kde: 0.119', + 'y: 1.211363, kde: 0.168' ], name: [ 'carrots', 'kale', 'radishes', @@ -407,7 +412,10 @@ describe('Test violin hover:', function() { '', '', '', '', '', '', '', '', '', - '', '', '' + '', '', '', + '', '', '', + '', + '', ], axis: 'day 1' }, { @@ -446,8 +454,8 @@ describe('Test violin hover:', function() { fig.layout.hovermode = 'x'; return fig; }, - nums: ['median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'], - name: ['radishes', '', '', '', ''], + nums: ['median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7'], + name: ['radishes', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'hoveron violins+points | hovermode x (violin AND closest point)', @@ -461,8 +469,8 @@ describe('Test violin hover:', function() { return fig; }, pos: [207, 240], - nums: ['0.7', 'median: 0.55', 'min: 0', 'q1: 0.3', 'q3: 0.6', 'max: 0.7'], - name: ['radishes', 'radishes', '', '', '', ''], + nums: ['0.7', 'median: 0.55', 'min: 0', 'lower fence: 0', 'q1: 0.3', 'q3: 0.6', 'upper fence: 0.7', 'max: 0.7'], + name: ['radishes', 'radishes', '', '', '', '', '', ''], axis: 'day 1' }, { desc: 'text items on hover', @@ -539,13 +547,18 @@ describe('Test violin hover:', function() { }, nums: [ 'max: 50.81', 'min: 3.07', 'median: 18.24', - 'q1: 13.8575', 'q3: 24.975', 'upper fence: 39.42' + 'q1: 13.8575', 'q3: 24.975', 'upper fence: 39.42', 'lower fence: 3.07' ], - name: ['', '', '', '', '', ''], + name: ['', '', '', '', '', '', ''], axis: 'Sat', hoverLabelPos: [ - [364, 270], [339, 270], [352, 270], - [346, 270], [349, 270], [387, 270] + [363, 270], + [338, 270], + [377, 270], + [351, 270], + [345, 270], + [385, 270], + [347, 270] ] }, { desc: 'single horizontal violin', @@ -555,10 +568,9 @@ describe('Test violin hover:', function() { return fig; }, pos: [310, 160], - nums: ['median: C', 'min: A', 'q1: B', 'q3: D', 'max: G', 'upper fence: D', 'x: C, kde: 1.005'], - name: ['categories', '', '', '', '', '', ''], + nums: ['median: C', 'min: A', 'q1: B', 'q3: D', 'max: G', 'upper fence: D', 'lower fence: A', 'x: C, kde: 1.005'], + name: ['categories', '', '', '', '', '', '', ''], axis: 'categories', - hOrder: [4, 5, 3, 6, 0, 2, 1], isRotated: true }, { desc: 'multiple horizontal violins', @@ -572,10 +584,9 @@ describe('Test violin hover:', function() { fig.layout.hovermode = 'y'; return fig; }, - nums: ['median: 0.4', 'min: 0.1', 'q1: 0.2', 'q3: 0.7', 'max: 0.9'], - name: ['kale', '', '', '', ''], + nums: ['median: 0.4', 'min: 0.1', 'lower fence: 0.1', 'q1: 0.2', 'q3: 0.7', 'upper fence: 0.9', 'max: 0.9'], + name: ['kale', '', '', '', '', '', ''], axis: 'day 2', - hOrder: [4, 3, 0, 2, 1], isRotated: true }, { desc: 'multiple horizontal violins (under hovermode:closest)', @@ -590,11 +601,10 @@ describe('Test violin hover:', function() { }, pos: [200, 175], nums: [ - '(median: 0.7, day 2)', '(min: 0.2, day 2)', '(q1: 0.5, day 2)', - '(q3: 0.8, day 2)', '(max: 0.9, day 2)' + '(median: 0.7, day 2)', '(min: 0.2, day 2)', '(lower fence: 0.2, day 2)', '(q1: 0.5, day 2)', + '(q3: 0.8, day 2)', '(upper fence: 0.9, day 2)', '(max: 0.9, day 2)' ], - name: ['radishes', '', '', '', ''], - hOrder: [4, 3, 0, 2, 1], + name: ['radishes', '', '', '', '', '', ''], isRotated: true }, { desc: 'hovering over single pt on horizontal violin should not rotate labels', @@ -623,10 +633,9 @@ describe('Test violin hover:', function() { return fig; }, pos: [430, 130], - nums: ['max: 0.9', 'min: 0.1', 'q1: 0.2', 'q3: 0.7', 'median: 0.4'], - name: ['', '', '', '', 'kale'], + nums: ['upper fence: 0.9', 'lower fence: 0.1', 'max: 0.9', 'min: 0.1', 'q1: 0.2', 'q3: 0.7', 'median: 0.4'], + name: ['', '', '', '', '', '', 'kale'], axis: '2018 - day 2', - hOrder: [0, 3, 4, 2, 1] }, { desc: 'orientation:h | hovermode:closest', mock: require('@mocks/violin_grouped_horz-multicategory.json'), @@ -639,12 +648,12 @@ describe('Test violin hover:', function() { }, pos: [430, 130], nums: [ + '(upper fence: 0.9, 2018 - day 2)', '(lower fence: 0.1, 2018 - day 2)', '(max: 0.9, 2018 - day 2)', '(min: 0.1, 2018 - day 2)', '(q1: 0.2, 2018 - day 2)', '(q3: 0.7, 2018 - day 2)', '(median: 0.4, 2018 - day 2)' ], - name: ['', '', '', '', 'kale'], - hOrder: [0, 3, 4, 2, 1] + name: ['', '', '', '', '', '', 'kale'] }, { desc: 'on points with numeric positions | orientation:h | hovermode:closest', mock: { @@ -752,7 +761,7 @@ describe('Test violin hover:', function() { actual = actual.sort(function(a, b) { return a[1].top - b[1].top; }); - expect(actual.length).toBe(8, '# of value hover labels'); + expect(actual.length).toBe(9, '# of value hover labels'); for(var i = 0; i < actual.length - 1; i++) { var a = actual[i]; From 3be88c47fd43f48e4382a8ec58e360e0622018a2 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Mon, 30 May 2022 18:05:52 -0400 Subject: [PATCH 05/10] consider reversed axes in ordering box hover --- src/traces/box/hover.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 024086b89e3..7e5ba9fc95b 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -150,7 +150,14 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { (!hasFences && hasMean) ? ['max', 'q3', 'mean', 'q1', 'min'] : ['max', 'q3', 'q1', 'min']; - if(trace.orientation === 'h') attrs.reverse(); + var rev = vAxis.range[1] < vAxis.range[0]; + + if( + (!rev && trace.orientation === 'h') || + (rev && trace.orientation === 'v') + ) { + attrs.reverse(); + } // always put median at the start so that it get the extra label attrs = ['med'].concat(attrs); From e2f6d0c4f49a27dba5d8237a61de163330d290b0 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Tue, 31 May 2022 11:55:30 -0400 Subject: [PATCH 06/10] display mid in the middle --- src/traces/box/hover.js | 23 +++++++++++++---------- test/jasmine/tests/box_test.js | 3 ++- test/jasmine/tests/hover_label_test.js | 2 +- test/jasmine/tests/violin_test.js | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 7e5ba9fc95b..2b14f85cfec 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -145,10 +145,10 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { // labels with euqual values (e.g. when min === q1) should be presented in certain order var attrs = - (hasFences && hasMean) ? ['max', 'uf', 'q3', 'mean', 'q1', 'lf', 'min'] : - (hasFences && !hasMean) ? ['max', 'uf', 'q3', 'q1', 'lf', 'min'] : - (!hasFences && hasMean) ? ['max', 'q3', 'mean', 'q1', 'min'] : - ['max', 'q3', 'q1', 'min']; + (hasFences && hasMean) ? ['max', 'uf', 'q3', 'med', 'mean', 'q1', 'lf', 'min'] : + (hasFences && !hasMean) ? ['max', 'uf', 'q3', 'med', 'q1', 'lf', 'min'] : + (!hasFences && hasMean) ? ['max', 'q3', 'med', 'mean', 'q1', 'min'] : + ['max', 'q3', 'med', 'q1', 'min']; var rev = vAxis.range[1] < vAxis.range[0]; @@ -159,9 +159,6 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { attrs.reverse(); } - // always put median at the start so that it get the extra label - attrs = ['med'].concat(attrs); - var closeBoxData = []; for(var i = 0; i < attrs.length; i++) { var attr = attrs[i]; @@ -187,9 +184,15 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { } // only keep name and spikes on the first item (median) - pointData.name = ''; - pointData.spikeDistance = undefined; - pointData[spikePosAttr] = undefined; + if(attr === 'med') { + pointData.name = ''; + pointData.spikeDistance = undefined; + pointData[spikePosAttr] = undefined; + } else { + pointData2.name = ''; + pointData2.spikeDistance = undefined; + pointData2[spikePosAttr] = undefined; + } // no hovertemplate support yet pointData2.hovertemplate = false; diff --git a/test/jasmine/tests/box_test.js b/test/jasmine/tests/box_test.js index c30e59b8d12..8af768907e6 100644 --- a/test/jasmine/tests/box_test.js +++ b/test/jasmine/tests/box_test.js @@ -782,10 +782,11 @@ describe('Test box hover:', function() { }, pos: [350, 200], nums: [ + '23.25', 'median: 8.15', 'min: 0.75', 'q1: 6.8', 'q3: 10.25', 'max: 23.25', 'lower fence: 5.25', 'upper fence: 12' ], - name: ['', '', '', '', '', '', ''], + name: ['', '', '', '', '', '', '', ''], axis: 'trace 0' }, { desc: 'with overlaid boxes', diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index e733f2d2bd0..66ea5a85b58 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -4680,10 +4680,10 @@ describe('hovermode: (x|y)unified', function() { 'min: 1', 'lower fence: 1', 'q1: 1', + 'trace 1 : median: 1', 'q3: 1', 'upper fence: 1', 'max: 1', - 'trace 1 : median: 1', 'trace 3 : 2', 'trace 2 : 2', 'trace 5 : 2', diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js index 2311a4ccaa4..f1c126936ad 100644 --- a/test/jasmine/tests/violin_test.js +++ b/test/jasmine/tests/violin_test.js @@ -552,10 +552,10 @@ describe('Test violin hover:', function() { name: ['', '', '', '', '', '', ''], axis: 'Sat', hoverLabelPos: [ - [363, 270], [338, 270], [377, 270], [351, 270], + [363, 270], [345, 270], [385, 270], [347, 270] From 59831f6ba0fa69a5840d73ff94a72fa523daf79b Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Wed, 1 Jun 2022 09:37:03 -0400 Subject: [PATCH 07/10] fix violin spikelines --- src/traces/box/hover.js | 29 ++++++++++++++++++----------- src/traces/violin/hover.js | 16 ++++++++++++---- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 2b14f85cfec..47dc06de91f 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -159,6 +159,9 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { attrs.reverse(); } + var spikeDistance = pointData.spikeDistance; + var spikePosition = pointData[spikePosAttr]; + var closeBoxData = []; for(var i = 0; i < attrs.length; i++) { var attr = attrs[i]; @@ -183,23 +186,27 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { pointData2[vLetter + 'err'] = di.sd; } - // only keep name and spikes on the first item (median) - if(attr === 'med') { - pointData.name = ''; - pointData.spikeDistance = undefined; - pointData[spikePosAttr] = undefined; - } else { - pointData2.name = ''; - pointData2.spikeDistance = undefined; - pointData2[spikePosAttr] = undefined; - } - // no hovertemplate support yet pointData2.hovertemplate = false; closeBoxData.push(pointData2); } + // only keep name and spikes on the first item (median) + pointData.name = ''; + pointData.spikeDistance = undefined; + pointData[spikePosAttr] = undefined; + for(var k = 0; k < closeBoxData.length; k++) { + if(closeBoxData[k].attr !== 'med') { + closeBoxData[k].name = ''; + closeBoxData[k].spikeDistance = undefined; + closeBoxData[k][spikePosAttr] = undefined; + } else { + closeBoxData[k].spikeDistance = spikeDistance; + closeBoxData[k][spikePosAttr] = spikePosition; + } + } + return closeBoxData; } diff --git a/src/traces/violin/hover.js b/src/traces/violin/hover.js index eb716dc80ae..883350e4032 100644 --- a/src/traces/violin/hover.js +++ b/src/traces/violin/hover.js @@ -56,11 +56,19 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, opts) { kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal, trace[vLetter + 'hoverformat']) + ', ' + cd[0].t.labels.kde + ' ' + kdeVal.toFixed(3); // move the spike to the KDE point - kdePointData.spikeDistance = closeBoxData[0].spikeDistance; + var medId = 0; + for(var k = 0; k < closeBoxData.length; k++) { + if(closeBoxData[k].attr === 'med') { + medId = k; + break; + } + } + + kdePointData.spikeDistance = closeBoxData[medId].spikeDistance; var spikePosAttr = pLetter + 'Spike'; - kdePointData[spikePosAttr] = closeBoxData[0][spikePosAttr]; - closeBoxData[0].spikeDistance = undefined; - closeBoxData[0][spikePosAttr] = undefined; + kdePointData[spikePosAttr] = closeBoxData[medId][spikePosAttr]; + closeBoxData[medId].spikeDistance = undefined; + closeBoxData[medId][spikePosAttr] = undefined; // no hovertemplate support yet kdePointData.hovertemplate = false; From 54d182f6f79c4381217124b521284c461fc20135 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi <33888540+archmoj@users.noreply.github.com> Date: Tue, 14 Jun 2022 12:29:18 -0400 Subject: [PATCH 08/10] Update src/traces/box/hover.js Co-authored-by: Alex Johnson --- src/traces/box/hover.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index 47dc06de91f..fb8d9ed4603 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -152,10 +152,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { var rev = vAxis.range[1] < vAxis.range[0]; - if( - (!rev && trace.orientation === 'h') || - (rev && trace.orientation === 'v') - ) { + if(trace.orientation === (rev ? 'v' : 'h')) { attrs.reverse(); } From f3f3c5c426ace4d607eba3a267afc6f0f822fd40 Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi <33888540+archmoj@users.noreply.github.com> Date: Tue, 14 Jun 2022 12:29:34 -0400 Subject: [PATCH 09/10] Update src/traces/box/hover.js Co-authored-by: Alex Johnson --- src/traces/box/hover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index fb8d9ed4603..dd7cf455c39 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -189,7 +189,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { closeBoxData.push(pointData2); } - // only keep name and spikes on the first item (median) + // only keep name and spikes on the median pointData.name = ''; pointData.spikeDistance = undefined; pointData[spikePosAttr] = undefined; From 98d841ea356854de4b3c20675af86c0f0e68a66b Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi <33888540+archmoj@users.noreply.github.com> Date: Tue, 14 Jun 2022 12:29:59 -0400 Subject: [PATCH 10/10] Update src/traces/box/hover.js Co-authored-by: Alex Johnson --- src/traces/box/hover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js index dd7cf455c39..479d434f42c 100644 --- a/src/traces/box/hover.js +++ b/src/traces/box/hover.js @@ -143,7 +143,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) { var hasMean = trace.boxmean || (trace.meanline || {}).visible; var hasFences = trace.boxpoints || trace.points; - // labels with euqual values (e.g. when min === q1) should be presented in certain order + // labels with equal values (e.g. when min === q1) should still be presented in the order they have when they're unequal var attrs = (hasFences && hasMean) ? ['max', 'uf', 'q3', 'med', 'mean', 'q1', 'lf', 'min'] : (hasFences && !hasMean) ? ['max', 'uf', 'q3', 'med', 'q1', 'lf', 'min'] :