Skip to content

Commit 756308f

Browse files
committed
record real initial axis (auto)range so we can update to autorange
1 parent 7ab8630 commit 756308f

File tree

5 files changed

+111
-12
lines changed

5 files changed

+111
-12
lines changed

src/plot_api/plot_api.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,7 +1445,8 @@ function storeCurrent(attr, val, newVal, preGUI) {
14451445
* of the calling routine.
14461446
*
14471447
* @param {object} container: the input attributes container (eg `layout` or a `trace`)
1448-
* @param {object} fullContainer: the full partner to `container`
1448+
* @param {object} preGUI: where original values should be stored, either
1449+
* `layout._preGUI` or `layout._tracePreGUI[uid]`
14491450
* @param {object} edits: the {attr: val} object as normally passed to `relayout` etc
14501451
*/
14511452
exports._storeDirectGUIEdit = function(container, preGUI, edits) {
@@ -2367,7 +2368,7 @@ exports._guiUpdate = guiEdit(update);
23672368
// Ordered by most common edits first, to minimize our search time
23682369
var layoutUIControlPatterns = [
23692370
{pattern: /^hiddenlabels/, attr: 'legend.uirevision'},
2370-
{pattern: /^((x|y)axis\d*)\.((auto)?range|title)/, autofill: true},
2371+
{pattern: /^((x|y)axis\d*)\.((auto)?range|title)/},
23712372

23722373
// showspikes and modes include those nested inside scenes
23732374
{pattern: /axis\d*\.showspikes$/, attr: 'modebar.uirevision'},
@@ -2376,8 +2377,7 @@ var layoutUIControlPatterns = [
23762377
{pattern: /^(scene\d*)\.camera/},
23772378
{pattern: /^(geo\d*)\.(projection|center)/},
23782379
{pattern: /^(ternary\d*\.[abc]axis)\.(min|title)$/},
2379-
{pattern: /^(polar\d*\.radialaxis)\.(auto)?range/, autofill: true},
2380-
{pattern: /^(polar\d*\.radialaxis)\.(angle|title)/},
2380+
{pattern: /^(polar\d*\.radialaxis)\.((auto)?range|angle|title)/},
23812381
{pattern: /^(polar\d*\.angularaxis)\.rotation/},
23822382
{pattern: /^(mapbox\d*)\.(center|zoom|bearing|pitch)/},
23832383

@@ -2411,7 +2411,7 @@ function findUIPattern(key, patternSpecs) {
24112411
var spec = patternSpecs[i];
24122412
var match = key.match(spec.pattern);
24132413
if(match) {
2414-
return {head: match[1], attr: spec.attr, autofill: spec.autofill};
2414+
return {head: match[1], attr: spec.attr};
24152415
}
24162416
}
24172417
}
@@ -2464,6 +2464,8 @@ function valsMatch(v1, v2) {
24642464
function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
24652465
var layoutPreGUI = oldFullLayout._preGUI;
24662466
var key, revAttr, oldRev, newRev, match, preGUIVal, newNP, newVal;
2467+
var bothInheritAutorange = [];
2468+
var newRangeAccepted = {};
24672469
for(key in layoutPreGUI) {
24682470
match = findUIPattern(key, layoutUIControlPatterns);
24692471
if(match) {
@@ -2485,8 +2487,11 @@ function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
24852487
// storing *that* in preGUI... oh well, for now at least I limit
24862488
// this to attributes that get autofilled, which AFAICT among
24872489
// the GUI-editable attributes is just axis.range/autorange.
2488-
if(valsMatch(newVal, preGUIVal) || (match.autofill && newVal === undefined)) {
2489-
newNP.set(nestedProperty(oldFullLayout, key).get());
2490+
if(valsMatch(newVal, preGUIVal)) {
2491+
if(newVal === undefined && key.substr(key.length - 9) === 'autorange') {
2492+
bothInheritAutorange.push(key.substr(0, key.length - 10));
2493+
}
2494+
newNP.set(undefinedToNull(nestedProperty(oldFullLayout, key).get()));
24902495
continue;
24912496
}
24922497
}
@@ -2498,12 +2503,26 @@ function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
24982503
// point (either because it changed or revision changed)
24992504
// so remove it from _preGUI for next time.
25002505
delete layoutPreGUI[key];
2506+
2507+
if(key.substr(key.length - 8, 6) === 'range[') {
2508+
newRangeAccepted[key.substr(0, key.length - 9)] = 1;
2509+
}
2510+
}
2511+
2512+
// Special logic for `autorange`, since it interacts with `range`:
2513+
// If the new figure's matching `range` was kept, and `autorange`
2514+
// wasn't supplied explicitly in either the original or the new figure,
2515+
// we shouldn't alter that - but we may just have done that, so fix it.
2516+
for(var i = 0; i < bothInheritAutorange.length; i++) {
2517+
var axAttr = bothInheritAutorange[i];
2518+
if(newRangeAccepted[axAttr]) {
2519+
var newAx = nestedProperty(layout, axAttr).get();
2520+
if(newAx) delete newAx.autorange;
2521+
}
25012522
}
25022523

25032524
// Now traces - try to match them up by uid (in case we added/deleted in
25042525
// the middle), then fall back on index.
2505-
// var tracei = -1;
2506-
// for(var fulli = 0; fulli < oldFullData.length; fulli++) {
25072526
var allTracePreGUI = oldFullLayout._tracePreGUI;
25082527
for(var uid in allTracePreGUI) {
25092528
var tracePreGUI = allTracePreGUI[uid];
@@ -2550,8 +2569,8 @@ function applyUIRevisions(data, layout, oldFullData, oldFullLayout) {
25502569
if(preGUIVal === null) preGUIVal = undefined;
25512570
newNP = nestedProperty(newTrace, key);
25522571
newVal = newNP.get();
2553-
if(valsMatch(newVal, preGUIVal) || (match.autofill && newVal === undefined)) {
2554-
newNP.set(nestedProperty(fullInput, key).get());
2572+
if(valsMatch(newVal, preGUIVal)) {
2573+
newNP.set(undefinedToNull(nestedProperty(fullInput, key).get()));
25552574
continue;
25562575
}
25572576
}

src/plots/cartesian/autorange.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var isNumeric = require('fast-isnumeric');
1212

1313
var Lib = require('../../lib');
1414
var FP_SAFE = require('../../constants/numerical').FP_SAFE;
15+
var Registry = require('../../registry');
1516

1617
module.exports = {
1718
getAutoRange: getAutoRange,
@@ -250,6 +251,13 @@ function doAutoRange(gd, ax) {
250251
// but we want to report its results back to layout
251252

252253
axIn = ax._input;
254+
255+
// before we edit _input, store preGUI values
256+
var edits = {};
257+
edits[ax._attr + '.range'] = ax.range;
258+
edits[ax._attr + '.autorange'] = ax.autorange;
259+
Registry.call('_storeDirectGUIEdit', gd.layout, gd._fullLayout._preGUI, edits);
260+
253261
axIn.range = ax.range.slice();
254262
axIn.autorange = ax.autorange;
255263
}

src/plots/cartesian/layout_defaults.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
158158
axLayoutOut._shapeIndices = [];
159159

160160
// set up some private properties
161-
axLayoutOut._name = axName;
161+
axLayoutOut._name = axLayoutOut._attr = axName;
162162
var id = axLayoutOut._id = name2id(axName);
163163

164164
var overlayableAxes = getOverlayableAxes(axLetter, axName);

src/plots/polar/layout_defaults.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ function handleDefaults(contIn, contOut, coerce, opts) {
5353
var axIn = contIn[axName];
5454
var axOut = Template.newContainer(contOut, axName);
5555
axOut._id = axOut._name = axName;
56+
axOut._attr = opts.id + '.' + axName;
5657
axOut._traceIndices = subplotData.map(function(t) { return t._expandedIndex; });
5758

5859
var dataAttr = constants.axisName2dataArray[axName];

test/jasmine/tests/plot_api_react_test.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,77 @@ describe('Plotly.react and uirevision attributes', function() {
10871087
.then(done);
10881088
});
10891089

1090+
it('respects reverting an explicit cartesian axis range to auto', function(done) {
1091+
function fig(xRange, yRange) {
1092+
return {
1093+
data: [{z: [[1, 2], [3, 4]], type: 'heatmap', x: [0, 1, 2], y: [3, 4, 5]}],
1094+
layout: {
1095+
xaxis: {range: xRange},
1096+
yaxis: {range: yRange},
1097+
uirevision: 'a'
1098+
}
1099+
};
1100+
}
1101+
1102+
function setRanges(xRange, yRange) {
1103+
return function() {
1104+
return Registry.call('_guiRelayout', gd, {
1105+
'xaxis.range': xRange,
1106+
'yaxis.range': yRange
1107+
});
1108+
};
1109+
}
1110+
1111+
function checkRanges(xRange, yRange) {
1112+
return checkState([], {
1113+
'xaxis.range': [xRange],
1114+
'yaxis.range': [yRange]
1115+
});
1116+
}
1117+
1118+
Plotly.newPlot(gd, fig([1, 3], [4, 6]))
1119+
.then(checkRanges([1, 3], [4, 6]))
1120+
.then(setRanges([2, 4], [5, 7]))
1121+
.then(checkRanges([2, 4], [5, 7]))
1122+
.then(_react(fig(undefined, undefined)))
1123+
.then(checkRanges([0, 2], [3, 5]))
1124+
.catch(failTest)
1125+
.then(done);
1126+
});
1127+
1128+
it('respects reverting an explicit polar axis range to auto', function(done) {
1129+
function fig(range) {
1130+
return {
1131+
data: [{type: 'barpolar', r: [1, 1], theta: [0, 90]}],
1132+
layout: {
1133+
polar: {radialaxis: {range: range}},
1134+
uirevision: 'a'
1135+
}
1136+
};
1137+
}
1138+
1139+
function setRange(range) {
1140+
return function() {
1141+
return Registry.call('_guiRelayout', gd, {
1142+
'polar.radialaxis.range': range
1143+
});
1144+
};
1145+
}
1146+
1147+
function checkRange(range) {
1148+
return checkState([], {'polar.radialaxis.range': [range]});
1149+
}
1150+
1151+
Plotly.newPlot(gd, fig([1, 3]))
1152+
.then(checkRange([1, 3]))
1153+
.then(setRange([2, 4]))
1154+
.then(checkRange([2, 4]))
1155+
.then(_react(fig(undefined)))
1156+
.then(checkRange([0, 1.05263]))
1157+
.catch(failTest)
1158+
.then(done);
1159+
});
1160+
10901161
function _run(figFn, editFn, checkInitial, checkEdited) {
10911162
// figFn should take 2 args (main uirevision and partial uirevision)
10921163
// and return a figure {data, layout}

0 commit comments

Comments
 (0)