From 49724290f70bc52e8c418ae2da8cb03daf1cca64 Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 10 Feb 2020 18:16:55 -0500 Subject: [PATCH 1/8] fix issue 4567 - display narrow bars --- src/traces/bar/plot.js | 19 +-- test/image/baselines/bar_show_narrow.png | Bin 0 -> 29268 bytes test/image/mocks/bar_show_narrow.json | 166 +++++++++++++++++++++++ test/jasmine/tests/bar_test.js | 51 +++++++ 4 files changed, 224 insertions(+), 12 deletions(-) create mode 100644 test/image/baselines/bar_show_narrow.png create mode 100644 test/image/mocks/bar_show_narrow.json diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index aed04eb5dc4..59c3f6b1b86 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -157,9 +157,6 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) if(isBlank && isHorizontal) x1 = x0; if(isBlank && !isHorizontal) y1 = y0; - var spansHorizontal = isHorizontal && (x0 !== x1); - var spansVertical = !isHorizontal && (y0 !== y1); - // in waterfall mode `between` we need to adjust bar end points to match the connector width if(adjustPixel && !isBlank) { if(isHorizontal) { @@ -194,7 +191,9 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) d3.round(Math.round(v) - offset, 2) : v; } - function expandToVisible(v, vc) { + function expandToVisible(v, vc, hideZeroSpan) { + if(hideZeroSpan && v === vc) return v; + // if it's not in danger of disappearing entirely, // round more precisely return Math.abs(v - vc) >= 2 ? roundWithLine(v) : @@ -215,14 +214,10 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) var op = Color.opacity(mc); var fixpx = (op < 1 || lw > 0.01) ? roundWithLine : expandToVisible; - if(spansHorizontal) { - x0 = fixpx(x0, x1); - x1 = fixpx(x1, x0); - } - if(spansVertical) { - y0 = fixpx(y0, y1); - y1 = fixpx(y1, y0); - } + x0 = fixpx(x0, x1, isHorizontal); + x1 = fixpx(x1, x0, isHorizontal); + y0 = fixpx(y0, y1, !isHorizontal); + y1 = fixpx(y1, y0, !isHorizontal); } var sel = transition(Lib.ensureSingle(bar, 'path'), fullLayout, opts, makeOnCompleteCallback); diff --git a/test/image/baselines/bar_show_narrow.png b/test/image/baselines/bar_show_narrow.png new file mode 100644 index 0000000000000000000000000000000000000000..ff641a371b10dfb40a7a8a61d445680d49873cb5 GIT binary patch literal 29268 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 literal 0 HcmV?d00001 diff --git a/test/image/mocks/bar_show_narrow.json b/test/image/mocks/bar_show_narrow.json new file mode 100644 index 00000000000..db168bb48ab --- /dev/null +++ b/test/image/mocks/bar_show_narrow.json @@ -0,0 +1,166 @@ +{ + "data": [ + { + "type": "bar", + "width": 0.001, + "x": [ + "A", + "B", + "C", + "D" + ], + "y": [ + 0.001, + 0.01, + 0.1, + 1 + ] + }, + { + "type": "bar", + "width": 0.001, + "x": [ + "A", + "B", + "C", + "D" + ], + "y": [ + 0.001, + 0.01, + 0.1, + 1 + ], + "xaxis": "x2", + "yaxis": "y2" + }, + { + "type": "bar", + "width": 0.001, + "orientation": "h", + "x": [ + 0.001, + 0.01, + 0.1, + 1 + ], + "y": [ + "A", + "B", + "C", + "D" + ], + "text": [ + 0, + null, + 0.001, + 1 + ], + "xaxis": "x3", + "yaxis": "y3" + }, + { + "type": "bar", + "width": 0.001, + "orientation": "h", + "x": [ + 0.001, + 0.01, + 0.1, + 1 + ], + "y": [ + "A", + "B", + "C", + "D" + ], + "xaxis": "x4", + "yaxis": "y4" + } + ], + "layout": { + "showlegend": false, + "width": 800, + "height": 800, + "dragmode": "pan", + "xaxis": { + "domain": [ + 0, + 0.48 + ] + }, + "xaxis2": { + "autorange": "reversed", + "anchor": "y2", + "domain": [ + 0.52, + 1 + ] + }, + "xaxis3": { + "range": [ + -0.01, + 1 + ], + "zeroline": false, + "anchor": "y3", + "domain": [ + 0, + 0.48 + ] + }, + "xaxis4": { + "range": [ + -0.01, + 1 + ], + "zeroline": false, + "autorange": "reversed", + "anchor": "y4", + "domain": [ + 0.52, + 1 + ] + }, + "yaxis": { + "range": [ + -0.01, + 1 + ], + "zeroline": false, + "domain": [ + 0, + 0.48 + ] + }, + "yaxis2": { + "range": [ + -0.01, + 1 + ], + "zeroline": false, + "autorange": "reversed", + "anchor": "x2", + "domain": [ + 0.52, + 1 + ] + }, + "yaxis3": { + "anchor": "x3", + "domain": [ + 0.52, + 1 + ] + }, + "yaxis4": { + "autorange": "reversed", + "anchor": "x4", + "domain": [ + 0, + 0.48 + ] + } + } +} diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 171d7b8e3c6..9d03fda6910 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -2026,6 +2026,57 @@ describe('A bar plot', function() { .then(done); }); + it('should show up narrow bars as thin bars', function(done) { + var mock = Lib.extendDeep({}, require('@mocks/bar_show_narrow.json')); + + function getArea(path) { + var pos = path + .substr(1, path.length - 2) + .replace('V', ',') + .replace('H', ',') + .replace('V', ',') + .split(','); + var dx = +pos[0]; + var dy = +pos[1]; + dy -= +pos[2]; + dx -= +pos[3]; + + return Math.abs(dx * dy); + } + + Plotly.plot(gd, mock) + .then(function() { + var nodes = gd.querySelectorAll('g.point > path'); + expect(nodes.length).toBe(16, '# of bars'); + + [ + [0, true], + [1, true], + [2, true], + [3, true], + [4, true], + [5, true], + [6, true], + [7, true], + [8, true], + [9, true], + [10, true], + [11, true], + [12, true], + [13, true], + [14, true], + [15, true] + ].forEach(function(e) { + var i = e[0]; + var d = nodes[i].getAttribute('d'); + var visible = e[1]; + expect(getArea(d) > 0).toBe(visible, 'item:' + i); + }); + }) + .catch(failTest) + .then(done); + }); + it('should not show up null and zero bars as thin bars', function(done) { var mock = Lib.extendDeep({}, require('@mocks/bar_hide_nulls.json')); From c71ca70be71e1dd4935d89d6c70e91b152c1d7cc Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 09:42:09 -0500 Subject: [PATCH 2/8] should not force x1=x0 and y1=y0 --- src/traces/bar/plot.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index 59c3f6b1b86..f89da697ad7 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -149,14 +149,13 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) ); // display zeros if line.width > 0 - if(isBlank && shouldDisplayZeros && helpers.getLineWidth(trace, di) && (isHorizontal ? x1 - x0 === 0 : y1 - y0 === 0)) { + if(isBlank && shouldDisplayZeros && + helpers.getLineWidth(trace, di) && + (isHorizontal ? x0 === x1 : y0 === y1)) { isBlank = false; } di.isBlank = isBlank; - if(isBlank && isHorizontal) x1 = x0; - if(isBlank && !isHorizontal) y1 = y0; - // in waterfall mode `between` we need to adjust bar end points to match the connector width if(adjustPixel && !isBlank) { if(isHorizontal) { @@ -182,9 +181,9 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) mc = di.mc || trace.marker.color; } - var offset = d3.round((lw / 2) % 1, 2); - function roundWithLine(v) { + var offset = d3.round((lw / 2) % 1, 2); + // if there are explicit gaps, don't round, // it can make the gaps look crappy return (opts.gap === 0 && opts.groupgap === 0) ? From 7f3fb34fc3300f7670a9d92e0054802efb105ac2 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 10:08:23 -0500 Subject: [PATCH 3/8] add test to ensure narrow bars are displayed similar to v1.52.1 and before --- test/jasmine/tests/bar_test.js | 112 ++++++++++++++------------------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 9d03fda6910..650c3a78fe0 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -2026,75 +2026,24 @@ describe('A bar plot', function() { .then(done); }); - it('should show up narrow bars as thin bars', function(done) { - var mock = Lib.extendDeep({}, require('@mocks/bar_show_narrow.json')); - - function getArea(path) { - var pos = path - .substr(1, path.length - 2) - .replace('V', ',') - .replace('H', ',') - .replace('V', ',') - .split(','); - var dx = +pos[0]; - var dy = +pos[1]; - dy -= +pos[2]; - dx -= +pos[3]; - - return Math.abs(dx * dy); - } - - Plotly.plot(gd, mock) - .then(function() { - var nodes = gd.querySelectorAll('g.point > path'); - expect(nodes.length).toBe(16, '# of bars'); - - [ - [0, true], - [1, true], - [2, true], - [3, true], - [4, true], - [5, true], - [6, true], - [7, true], - [8, true], - [9, true], - [10, true], - [11, true], - [12, true], - [13, true], - [14, true], - [15, true] - ].forEach(function(e) { - var i = e[0]; - var d = nodes[i].getAttribute('d'); - var visible = e[1]; - expect(getArea(d) > 0).toBe(visible, 'item:' + i); - }); - }) - .catch(failTest) - .then(done); - }); + function getArea(path) { + var pos = path + .substr(1, path.length - 2) + .replace('V', ',') + .replace('H', ',') + .replace('V', ',') + .split(','); + var dx = +pos[0]; + var dy = +pos[1]; + dy -= +pos[2]; + dx -= +pos[3]; + + return Math.abs(dx * dy); + } it('should not show up null and zero bars as thin bars', function(done) { var mock = Lib.extendDeep({}, require('@mocks/bar_hide_nulls.json')); - function getArea(path) { - var pos = path - .substr(1, path.length - 2) - .replace('V', ',') - .replace('H', ',') - .replace('V', ',') - .split(','); - var dx = +pos[0]; - var dy = +pos[1]; - dy -= +pos[2]; - dx -= +pos[3]; - - return Math.abs(dx * dy); - } - Plotly.plot(gd, mock) .then(function() { var nodes = gd.querySelectorAll('g.point > path'); @@ -2127,6 +2076,39 @@ describe('A bar plot', function() { .catch(failTest) .then(done); }); + + describe('show narrow bars', function() { + ['initial zoom', 'after zoom out'].forEach(function(zoomStr) { + it(zoomStr, function(done) { + var mock = Lib.extendDeep({}, require('@mocks/bar_show_narrow.json')); + + if(zoomStr === 'after zoom out') { + mock.layout.xaxis.range = [-14.9, 17.9]; + mock.layout.xaxis2.range = [17.9, -14.9]; + mock.layout.xaxis3.range = [-3.9, 4.9]; + mock.layout.xaxis4.range = [4.9, -3.9]; + + mock.layout.yaxis.range = [-3.9, 4.9]; + mock.layout.yaxis2.range = [4.9, -3.9]; + mock.layout.yaxis3.range = [-14.9, 17.9]; + mock.layout.yaxis4.range = [17.9, -14.9]; + } + + Plotly.plot(gd, mock) + .then(function() { + var nodes = gd.querySelectorAll('g.point > path'); + expect(nodes.length).toBe(16, '# of bars'); + + for(var i = 0; i < 16; i++) { + var d = nodes[i].getAttribute('d'); + expect(getArea(d) > 0).toBe(true, 'item:' + i); + } + }) + .catch(failTest) + .then(done); + }); + }); + }); }); describe('bar visibility toggling:', function() { From c1ee8c2279058d61e7075a9967899a038b75e45e Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 12:25:28 -0500 Subject: [PATCH 4/8] add comment regarding not showing zero span bars --- src/traces/bar/plot.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index f89da697ad7..b9981388236 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -191,7 +191,13 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) } function expandToVisible(v, vc, hideZeroSpan) { - if(hideZeroSpan && v === vc) return v; + if(hideZeroSpan && v === vc) { + // should not expand zero span bars + // when start and end positions are identical + // i.e. for vertical when y0 === y1 + // and for horizontal when x0 === x1 + return v; + } // if it's not in danger of disappearing entirely, // round more precisely From 4c323bcd03ea4cd768c4ce46f1e786aa3113bc51 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 13:06:49 -0500 Subject: [PATCH 5/8] force x1=x0 and y1=y0 again but only with transition --- src/traces/bar/plot.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index b9981388236..e1261fc52c7 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -114,6 +114,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) } var isHorizontal = (trace.orientation === 'h'); + var withTransition = hasTransition(opts); var pointGroup = Lib.ensureSingle(plotGroup, 'g', 'points'); @@ -156,6 +157,14 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) } di.isBlank = isBlank; + if(isBlank && withTransition) { + if(isHorizontal) { + x1 = x0; + } else { + y1 = y0; + } + } + // in waterfall mode `between` we need to adjust bar end points to match the connector width if(adjustPixel && !isBlank) { if(isHorizontal) { @@ -231,7 +240,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) .attr('d', 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z') .call(Drawing.setClipUrl, plotinfo.layerClipId, gd); - if(!fullLayout.uniformtext.mode && hasTransition(opts)) { + if(!fullLayout.uniformtext.mode && withTransition) { var styleFns = Drawing.makePointStyleFns(trace); Drawing.singlePointStyle(di, sel, trace, styleFns, gd); } From 8ebc0301f1eaf3f4e54eeebab7923bc2bf6d96be Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 15:19:50 -0500 Subject: [PATCH 6/8] add comment for transitioning empty bars --- src/traces/bar/plot.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index e1261fc52c7..3c931404d98 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -157,6 +157,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) } di.isBlank = isBlank; + // for empty bars, ensure start and end positions are equal when having transition if(isBlank && withTransition) { if(isHorizontal) { x1 = x0; From c83839f38fac056905b4dc609c0b0f44ddc026c6 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 16:30:14 -0500 Subject: [PATCH 7/8] revise blank bar logic --- src/traces/bar/plot.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/traces/bar/plot.js b/src/traces/bar/plot.js index 3c931404d98..11b72020351 100644 --- a/src/traces/bar/plot.js +++ b/src/traces/bar/plot.js @@ -140,25 +140,29 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback) var y0 = xy[1][0]; var y1 = xy[1][1]; - var isBlank = ( - x0 === x1 || - y0 === y1 || - !isNumeric(x0) || - !isNumeric(x1) || - !isNumeric(y0) || - !isNumeric(y1) - ); + // empty bars + var isBlank = (isHorizontal ? x1 - x0 : y1 - y0) === 0; // display zeros if line.width > 0 - if(isBlank && shouldDisplayZeros && - helpers.getLineWidth(trace, di) && - (isHorizontal ? x0 === x1 : y0 === y1)) { + if(isBlank && shouldDisplayZeros && helpers.getLineWidth(trace, di)) { isBlank = false; } + + // skip nulls + if(!isBlank) { + isBlank = ( + !isNumeric(x0) || + !isNumeric(x1) || + !isNumeric(y0) || + !isNumeric(y1) + ); + } + + // record isBlank di.isBlank = isBlank; - // for empty bars, ensure start and end positions are equal when having transition - if(isBlank && withTransition) { + // for blank bars, ensure start and end positions are equal - important for smooth transitions + if(isBlank) { if(isHorizontal) { x1 = x0; } else { From 494775bfccc1e517917ecabb7cb494c3412d9e53 Mon Sep 17 00:00:00 2001 From: archmoj Date: Tue, 11 Feb 2020 17:47:59 -0500 Subject: [PATCH 8/8] add transition tests for blank bars - as currently pass on master too --- test/jasmine/tests/bar_test.js | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 650c3a78fe0..f9951e2ddd8 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -2870,6 +2870,67 @@ describe('bar tweening', function() { .catch(failTest) .then(done); }); + + it('blank vertical bars', function(done) { + var mockCopy = { + data: [{ + type: 'bar', + x: ['A', 'B', 'C'], + y: [null, 5, 3], + marker: { + line: { + width: 10 + } + } + }], + layout: { + width: 400, + height: 300 + } + }; + + var tests = [ + [0, '.point path', 'attr', 'd', ['M8,120V120H72V120Z', 'M88,120V6H152V120Z', 'M168,120V52H232V120Z']], + [300, '.point path', 'attr', 'd', ['M8,120V52H72V120Z', 'M88,120V74H152V120Z', 'M168,120V65H232V120Z']], + [600, '.point path', 'attr', 'd', ['M8,120V6H72V120Z', 'M88,120V120H152V120Z', 'M168,120V74H232V120Z']] + ]; + var animateOpts = {data: [{y: [5, null, 2]}]}; + + checkTransition(gd, mockCopy, animateOpts, transitionOpts, tests) + .catch(failTest) + .then(done); + }); + + it('blank horizontal bars', function(done) { + var mockCopy = { + data: [{ + type: 'bar', + orientation: 'h', + y: ['A', 'B', 'C'], + x: [null, 5, 3], + marker: { + line: { + width: 10 + } + } + }], + layout: { + width: 400, + height: 300 + } + }; + + var tests = [ + [0, '.point path', 'attr', 'd', ['M0,116V84H0V116Z', 'M0,76V44H228V76Z', 'M0,36V4H137V36Z']], + [300, '.point path', 'attr', 'd', ['M0,116V84H137V116Z', 'M0,76V44H91V76Z', 'M0,36V4H109V36Z']], + [600, '.point path', 'attr', 'd', ['M0,116V84H228V116Z', 'M0,76V44H0V76Z', 'M0,36V4H91V36Z']] + ]; + var animateOpts = {data: [{x: [5, null, 2]}]}; + + checkTransition(gd, mockCopy, animateOpts, transitionOpts, tests) + .catch(failTest) + .then(done); + }); }); describe('bar uniformtext', function() {