diff --git a/src/components/colorscale/calc.js b/src/components/colorscale/calc.js index fe300909f5d..8d095e8642d 100644 --- a/src/components/colorscale/calc.js +++ b/src/components/colorscale/calc.js @@ -27,9 +27,12 @@ module.exports = function calc(trace, vals, containerStr, cLetter) { inputContainer = trace._input; } - var auto = container[cLetter + 'auto'], - min = container[cLetter + 'min'], - max = container[cLetter + 'max'], + var autoAttr = cLetter + 'auto', + minAttr = cLetter + 'min', + maxAttr = cLetter + 'max', + auto = container[autoAttr], + min = container[minAttr], + max = container[maxAttr], scl = container.colorscale; if(auto !== false || min === undefined) { @@ -45,11 +48,21 @@ module.exports = function calc(trace, vals, containerStr, cLetter) { max += 0.5; } - container[cLetter + 'min'] = min; - container[cLetter + 'max'] = max; + container[minAttr] = min; + container[maxAttr] = max; - inputContainer[cLetter + 'min'] = min; - inputContainer[cLetter + 'max'] = max; + inputContainer[minAttr] = min; + inputContainer[maxAttr] = max; + + /* + * If auto was explicitly false but min or max was missing, + * we filled in the missing piece here but later the trace does + * not look auto. + * Otherwise make sure the trace still looks auto as far as later + * changes are concerned. + */ + inputContainer[autoAttr] = (auto !== false || + (min === undefined && max === undefined)); if(container.autocolorscale) { if(min * max < 0) scl = scales.RdBu; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index c3860746323..d3f652a3c53 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -1599,7 +1599,10 @@ function _restyle(gd, aobj, _traces) { flags.docolorbars = true; } - if(recalcAttrs.indexOf(ai) !== -1) { + var aiArrayStart = ai.indexOf('['), + aiAboveArray = aiArrayStart === -1 ? ai : ai.substr(0, aiArrayStart); + + if(recalcAttrs.indexOf(aiAboveArray) !== -1) { // major enough changes deserve autoscale, autobin, and // non-reversed axes so people don't get confused if(['orientation', 'type'].indexOf(ai) !== -1) { @@ -1622,8 +1625,8 @@ function _restyle(gd, aobj, _traces) { } flags.docalc = true; } - else if(replotAttrs.indexOf(ai) !== -1) flags.doplot = true; - else if(autorangeAttrs.indexOf(ai) !== -1) flags.docalcAutorange = true; + else if(replotAttrs.indexOf(aiAboveArray) !== -1) flags.doplot = true; + else if(autorangeAttrs.indexOf(aiAboveArray) !== -1) flags.docalcAutorange = true; } // do we need to force a recalc? diff --git a/src/traces/contour/calc.js b/src/traces/contour/calc.js index fa0946363d0..07e86c2f2fc 100644 --- a/src/traces/contour/calc.js +++ b/src/traces/contour/calc.js @@ -42,7 +42,15 @@ module.exports = function calc(gd, trace) { } // copy auto-contour info back to the source data. - trace._input.contours = extendFlat({}, contours); + // previously we copied the whole contours object back, but that had + // other info (coloring, showlines) that should be left to supplyDefaults + if(!trace._input.contours) trace._input.contours = {}; + extendFlat(trace._input.contours, { + start: contours.start, + end: contours.end, + size: contours.size + }); + trace._input.autocontour = true; } else { // sanity checks on manually-supplied start/end/size diff --git a/test/jasmine/tests/contour_test.js b/test/jasmine/tests/contour_test.js index bc456c8ac03..764a5d94218 100644 --- a/test/jasmine/tests/contour_test.js +++ b/test/jasmine/tests/contour_test.js @@ -296,15 +296,20 @@ describe('contour calc', function() { contoursFinal.forEach(function(spec) { var out = _calc({ z: [[0, 2], [3, 5]], - contours: contoursIn, + contours: Lib.extendFlat({}, contoursIn), ncontours: spec.inputNcontours }).trace; ['start', 'end', 'size'].forEach(function(attr) { - expect(out.contours[attr]).toBe(spec[attr], [contoursIn, attr]); + expect(out.contours[attr]).toBe(spec[attr], [contoursIn, spec.inputNcontours, attr]); // all these get copied back to the input trace - expect(out._input.contours[attr]).toBe(spec[attr], [contoursIn, attr]); + expect(out._input.contours[attr]).toBe(spec[attr], [contoursIn, spec.inputNcontours, attr]); }); + + expect(out._input.autocontour).toBe(true); + expect(out._input.zauto).toBe(true); + expect(out._input.zmin).toBe(0); + expect(out._input.zmax).toBe(5); }); }); }); diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js index 05af47433cd..f50635e555c 100644 --- a/test/jasmine/tests/plot_api_test.js +++ b/test/jasmine/tests/plot_api_test.js @@ -282,7 +282,36 @@ describe('Test plot api', function() { expect(gd._fullData[0].marker.color).toBe(colorDflt[0]); expect(gd._fullData[1].marker.color).toBe(colorDflt[1]); }); + }); + + describe('Plotly.restyle unmocked', function() { + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + afterEach(function() { + destroyGraphDiv(); + }); + + it('should redo auto z/contour when editing z array', function() { + Plotly.plot(gd, [{type: 'contour', z: [[1, 2], [3, 4]]}]).then(function() { + expect(gd.data[0].zauto).toBe(true, gd.data[0]); + expect(gd.data[0].zmin).toBe(1); + expect(gd.data[0].zmax).toBe(4); + + expect(gd.data[0].autocontour).toBe(true); + expect(gd.data[0].contours).toEqual({start: 1.5, end: 3.5, size: 0.5}); + + return Plotly.restyle(gd, {'z[0][0]': 10}); + }).then(function() { + expect(gd.data[0].zmin).toBe(2); + expect(gd.data[0].zmax).toBe(10); + + expect(gd.data[0].contours).toEqual({start: 3, end: 9, size: 1}); + }); + }); }); describe('Plotly.deleteTraces', function() {