diff --git a/draftlogs/7950_fix.md b/draftlogs/7950_fix.md new file mode 100644 index 00000000000..0326814ba32 --- /dev/null +++ b/draftlogs/7950_fix.md @@ -0,0 +1 @@ + - Fix box, violin, candlestick and ohlc traces losing their forced minimum tick spacing when a graph div is updated in place with `Plotly.react` or `Plotly.restyle` [[#7950](https://github.com/plotly/plotly.js/pull/7950)] diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js index cc3c6ccf7ee..ef3d7ae74ca 100644 --- a/src/plots/cartesian/set_convert.js +++ b/src/plots/cartesian/set_convert.js @@ -58,7 +58,7 @@ function isValidCategory(v) { * Creates/updates these conversion functions, and a few more utilities * like cleanRange, and makeCalcdata * - * also clears ._minDtick, ._forceTick0 + * also creates ax.clearCalc, which clears ._minDtick, ._forceTick0 */ module.exports = function setConvert(ax, fullLayout) { fullLayout = fullLayout || {}; @@ -952,6 +952,12 @@ module.exports = function setConvert(ax, fullLayout) { // should skip if not category nor multicategory ax.clearCalc = function() { + // for bar charts and box plots: reset forced minimum tick spacing. + // this has to happen here rather than in setConvert, as the values + // are relinked onto the new fullLayout after supplyDefaults runs + delete ax._minDtick; + delete ax._forceTick0; + var group = ax._matchGroup; if(group) { var categories = null; @@ -1024,8 +1030,4 @@ module.exports = function setConvert(ax, fullLayout) { // even though it won't be needed by this axis ax._separators = fullLayout.separators; ax._numFormat = locale ? locale.numberFormat : numberFormat; - - // and for bar charts and box plots: reset forced minimum tick spacing - delete ax._minDtick; - delete ax._forceTick0; }; diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 15eca358dfe..df78b999bf0 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -8303,6 +8303,45 @@ describe('more react tests', function() { expect(gd._fullLayout.xaxis.range).toBeCloseToArray([-0.173, 2]); }).then(done, done.fail); }); + + it('should not carry over the forced minimum tick spacing of the previous figure', function(done) { + var layout = {width: 700, height: 400}; + + var scatterFig = { + data: [{y: [1, 2, 3]}], + layout: layout + }; + + // one box per integer position - each box forces a tick of its own + var boxFig = { + data: [{ + type: 'box', + x: [1, 1, 2, 2, 3, 3], + y: [1, 2, 3, 4, 5, 6] + }], + layout: layout + }; + + function getXLabels() { + return gd._fullLayout.xaxis._vals.map(function(d) { return d.text; }); + } + + Plotly.newPlot(gd, boxFig) + .then(function() { + expect(getXLabels()).toEqual(['1', '2', '3']); + + // scatter cancels the forcing for its own figure only + return Plotly.newPlot(gd, scatterFig); + }) + .then(function() { + return Plotly.react(gd, boxFig); + }) + .then(function() { + expect(gd._fullLayout.xaxis._minDtick).toBe(1); + expect(getXLabels()).toEqual(['1', '2', '3']); + }) + .then(done, done.fail); + }); }); describe('category preservation tests on gd passed to Plotly.react()', function() { diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index d962aab7e1b..0a9e00cea51 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -1649,7 +1649,8 @@ describe('Test plot api', function () { return Plotly.restyle(gd, { x0: 12.3 }); }) .then(function () { - checkTicks('x', ['12', '12.5'], 'switched to numeric'); + // a single box forces one tick at its own position + checkTicks('x', ['12.3'], 'switched to numeric'); expect(gd._fullLayout.xaxis.type).toBe('linear'); }) .then(done, done.fail);