Skip to content

Fix relayout constrained axes + various multi-subplot perf improvements #2628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 14, 2018
47 changes: 47 additions & 0 deletions src/plot_api/subroutines.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ exports.lsInner = function(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);
}

fullLayout._paperdiv
Expand Down Expand Up @@ -324,6 +329,48 @@ exports.lsInner = function(gd) {
return gd._promises.length && Promise.all(gd._promises);
};

function findMainSubplot(ax, fullLayout) {
Copy link
Contributor Author

@etpinard etpinard May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcjohnson I didn't bother making the "find main subplot" algo faster as you proposed in #2549 (comment), I was happy enough with skipping this whole thing except for sploms with showlowerhalf: false with c947b2c

var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand Down
37 changes: 0 additions & 37 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,43 +801,6 @@ plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLa
null :
axisIDs.getFromId(mockGd, ax.anchor);
}

for(i = 0; i < axList.length; i++) {
// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax = axList[i];
var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';
// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}
// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !newSubplots[mainSubplotID]) {
mainSubplotID = '';
for(j = 0; j < ids.length; j++) {
id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);
if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = axisIDs.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}
ax._mainSubplot = mainSubplotID || nextBestMainSubplotID;
}
};

// This function clears any trace attributes with valType: color and
Expand Down
35 changes: 25 additions & 10 deletions test/jasmine/tests/plot_api_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,30 +643,27 @@ describe('Test plot api', function() {
});
}

var trace = {y: [1, 2, 1]};

var specs = [
['relayout', ['xaxis.range[0]', 0]],
['relayout', ['xaxis.range[1]', 3]],
['relayout', ['xaxis.range', [-1, 5]]],
['update', [{}, {'xaxis.range': [-1, 10]}]],
['react', [[trace], {xaxis: {range: [0, 1]}}]]
['update', [{}, {'xaxis.range': [-1, 10]}]]
];

specs.forEach(function(s) {
// create 'real' div for Plotly.react to work
gd = createGraphDiv();
Plotly.plot(gd, [trace], {xaxis: {range: [1, 2]}});
mock(gd);
gd = mock({
data: [{y: [1, 2, 1]}],
layout: {
xaxis: {range: [1, 2]}
}
});

Plotly[s[0]](gd, s[1][0], s[1][1]);

_assert([
'Plotly.', s[0],
'(gd, ', JSON.stringify(s[1][0]), ', ', JSON.stringify(s[1][1]), ')'
].join(''));

destroyGraphDiv();
});
});

Expand Down Expand Up @@ -2773,6 +2770,24 @@ describe('Test plot api', function() {
.then(done);
});

it('picks up minimal sequence for cartesian axis range updates', function(done) {
var data = [{y: [1, 2, 1]}];
var layout = {xaxis: {range: [1, 2]}};
var layout2 = {xaxis: {range: [0, 1]}};

Plotly.newPlot(gd, data, layout)
.then(countPlots)
.then(function() {
return Plotly.react(gd, data, layout2);
})
.then(function() {
expect(subroutines.doTicksRelayout).toHaveBeenCalledTimes(1);
expect(subroutines.layoutStyles).not.toHaveBeenCalled();
})
.catch(failTest)
.then(done);
});

it('redraws annotations one at a time', function(done) {
var data = [{y: [1, 2, 3], mode: 'markers'}];
var layout = {};
Expand Down