From f61187fc6c00e3df6217ca19a1ecabc6ef1b4241 Mon Sep 17 00:00:00 2001 From: wbrgss Date: Mon, 14 Dec 2020 18:26:39 -0500 Subject: [PATCH 1/2] Only run emptyCategories loop when restyle or relayout calc flag is true --- src/plot_api/plot_api.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index ffd6bb863b5..941f172e269 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2737,16 +2737,6 @@ function react(gd, data, layout, config) { applyUIRevisions(gd.data, gd.layout, oldFullData, oldFullLayout); - var allNames = Object.getOwnPropertyNames(oldFullLayout); - for(var q = 0; q < allNames.length; q++) { - var name = allNames[q]; - var start = name.substring(0, 5); - if(start === 'xaxis' || start === 'yaxis') { - var emptyCategories = oldFullLayout[name]._emptyCategories; - if(emptyCategories) emptyCategories(); - } - } - // "true" skips updating calcdata and remapping arrays from calcTransforms, // which supplyDefaults usually does at the end, but we may need to NOT do // if the diff (which we haven't determined yet) says we'll recalc @@ -2772,10 +2762,22 @@ function react(gd, data, layout, config) { if(updateAutosize(gd)) relayoutFlags.layoutReplot = true; - // clear calcdata if required - if(restyleFlags.calc || relayoutFlags.calc) gd.calcdata = undefined; + // clear calcdata and empty categories if required + if(restyleFlags.calc || relayoutFlags.calc) { + gd.calcdata = undefined; + var allNames = Object.getOwnPropertyNames(newFullLayout); + for(var q = 0; q < allNames.length; q++) { + var name = allNames[q]; + var start = name.substring(0, 5); + if(start === 'xaxis' || start === 'yaxis') { + var emptyCategories = newFullLayout[name]._emptyCategories; + if(emptyCategories) emptyCategories(); + } + } // otherwise do the calcdata updates and calcTransform array remaps that we skipped earlier - else Plots.supplyDefaultsUpdateCalc(gd.calcdata, newFullData); + } else { + Plots.supplyDefaultsUpdateCalc(gd.calcdata, newFullData); + } // Note: what restyle/relayout use impliedEdits and clearAxisTypes for // must be handled by the user when using Plotly.react. From eed5c8a2bceb6f6bb0a8c360bab26ea9cd8fd2df Mon Sep 17 00:00:00 2001 From: wbrgss Date: Tue, 15 Dec 2020 14:00:20 -0500 Subject: [PATCH 2/2] Add test for categories/axes label preservation on Plotly.react(gd, ...) --- test/jasmine/tests/axes_test.js | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 94d7979cce8..a3da155704f 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -6896,6 +6896,64 @@ describe('more react tests', function() { }); }); +describe('category preservation tests on gd passed to Plotly.react()', function() { + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + function _hover(gd, opts) { + Fx.hover(gd, opts); + // needed for successive hover events + Lib.clearThrottle(); + } + + it('should preserve categories and axis ticklabels', function(done) { + var fig = { + data: [{ + type: 'bar', + y: [3, 5, 3, 2], + x: ['a', 'b', 'c', 'd'] + }], + layout: { + width: 500, + height: 500 + } + }; + + Plotly.newPlot(gd, fig) + .then(function(gd) { + return Plotly.react(gd, fig); + }) + .then(function() { + expect(gd._fullLayout.xaxis._categories).toEqual(['a', 'b', 'c', 'd']); + expect(gd._fullLayout.xaxis._categoriesMap).toEqual({a: 0, b: 1, c: 2, d: 3}); + }) + .then(function() { + _hover(gd, { xval: fig.data[0].x.indexOf('a') }); + expect(d3.selectAll('g.axistext').select('text').html()).toEqual('a'); + }) + .then(function() { + _hover(gd, { xval: fig.data[0].x.indexOf('b') }); + expect(d3.selectAll('g.axistext').select('text').html()).toEqual('b'); + }) + .then(function() { + _hover(gd, { xval: fig.data[0].x.indexOf('c') }); + expect(d3.selectAll('g.axistext').select('text').html()).toEqual('c'); + }) + .then(function() { + _hover(gd, { xval: fig.data[0].x.indexOf('d') }); + expect(d3.selectAll('g.axistext').select('text').html()).toEqual('d'); + }) + + .catch(failTest) + .then(done); + }); +}); + describe('more matching axes tests', function() { var gd;