Skip to content
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

Aggressive splom perf #3057

Merged
merged 30 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
56f2ee9
update scattergl & splom 'text' attr description
etpinard Sep 18, 2018
3574ece
move splom scene ref to fullLayout
etpinard Sep 27, 2018
8d0cac5
use styleOnSelect for scatter[polar]gl and splom
etpinard Sep 27, 2018
8282d91
compute marker.size axis 'ppad' value once per splom traces,
etpinard Sep 27, 2018
73acd7e
merge options before matrix.update call
etpinard Sep 27, 2018
cc5f0ca
speed up 'axrange' edits
etpinard Sep 27, 2018
17e30d2
aggressively try to speed 'axrange' edits for splom
etpinard Sep 27, 2018
4792f08
optimize lsInner for splom
etpinard Sep 27, 2018
f415e96
first-cut editType:'style' pathway for sploms
etpinard Sep 27, 2018
3eb91c0
no need to re-calc 'regl' traces in-and-out of arrayOk values
etpinard Sep 27, 2018
145cad3
try implementing a fast 'markerSize' editType
etpinard Sep 27, 2018
6de1ae4
add supplyDefaults bypass 'axrange' optimization to Plotly.update
etpinard Oct 1, 2018
aaf6312
apply no-need-for-<rect.bg> optimization to all cartesian subplots
etpinard Oct 1, 2018
478c669
speed up splom.clean
etpinard Oct 1, 2018
81eb48b
introduce redrawReglTraces subroutine
etpinard Oct 2, 2018
0243451
:hocho: obsolete sortBasePlotModules
etpinard Oct 2, 2018
dcacd78
use redrawReglTraces on drag
etpinard Oct 2, 2018
68dfbc1
use redrawReglTraces on polar drag
etpinard Oct 2, 2018
c02330c
fix #2797 - clear full canvas and use redrawReglTraces on selections
etpinard Oct 2, 2018
02263b9
use redrawReglTraces in edit subroutines
etpinard Oct 2, 2018
f179c2f
skip canvas/context size mismatch test on CI
etpinard Oct 2, 2018
cd8d8ab
Merge pull request #3067 from plotly/redraw-regl-traces-subroutine
etpinard Oct 2, 2018
0aad7ea
fixup (add missing @gl)
etpinard Oct 2, 2018
078c086
clear axis types when restyling splom show(upper|lower)half
etpinard Oct 2, 2018
00cae48
Revert "clear axis types when restyling splom show(upper|lower)half"
etpinard Oct 3, 2018
5878223
make trace `(x|y)axes` always have the same length dimensions`
etpinard Oct 4, 2018
c2ecb3a
:hocho: obsolete args
etpinard Oct 4, 2018
31d5606
fixup comments
etpinard Oct 4, 2018
ea38664
add noCI tag to misbehaving tests
etpinard Oct 4, 2018
4137433
place splom axes on bottom/left sides when just diagonal is missing
etpinard Oct 4, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,10 @@ function _hover(gd, evt, subplot, noHoverEvent) {
if(fullLayout[subplotId]) {
pointData.subplot = fullLayout[subplotId]._subplot;
}
// add ref to splom scene
if(fullLayout._splomScenes && fullLayout._splomScenes[trace.uid]) {
pointData.scene = fullLayout._splomScenes[trace.uid];
}

closedataPreviousLength = hoverData.length;

Expand Down
27 changes: 19 additions & 8 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1701,15 +1701,26 @@ exports.relayout = function relayout(gd, astr, val) {
seq.push(subroutines.layoutReplot);
}
else if(Object.keys(aobj).length) {
Plots.supplyDefaults(gd);
var flagList = Object.keys(flags).filter(function(k) { return flags[k]; });

// Optimization mostly for large splom traces where
// Plots.supplyDefaults can take > 100ms
if(flagList[0] === 'axrange' && flagList.length === 1) {
alexcjohnson marked this conversation as resolved.
Show resolved Hide resolved
for(var k in specs.rangesAltered) {
var axName = Axes.id2name(k);
var axIn = gd.layout[axName];
var axOut = gd._fullLayout[axName];
axOut.autorange = axIn.autorange;
axOut.range = axIn.range.slice();
axOut.cleanRange();
}
} else {
Plots.supplyDefaults(gd);
}

if(flags.legend) seq.push(subroutines.doLegend);
if(flags.layoutstyle) seq.push(subroutines.layoutStyles);

if(flags.axrange) {
addAxRangeSequence(seq, specs.rangesAltered);
}

if(flags.axrange) addAxRangeSequence(seq, specs.rangesAltered);
if(flags.ticks) seq.push(subroutines.doTicksRelayout);
if(flags.modebar) seq.push(subroutines.doModeBar);
if(flags.camera) seq.push(subroutines.doCamera);
Expand Down Expand Up @@ -1738,8 +1749,8 @@ function addAxRangeSequence(seq, rangesAltered) {
// subroutine of its own so that finalDraw always gets
// executed after drawData
var doTicks = rangesAltered ?
function(gd) { return subroutines.doTicksRelayout(gd, rangesAltered); } :
subroutines.doTicksRelayout;
function(gd) { return Axes.doTicks(gd, Object.keys(rangesAltered), true); } :
function(gd) { return Axes.doTicks(gd, 'redraw'); };
alexcjohnson marked this conversation as resolved.
Show resolved Hide resolved

seq.push(
subroutines.doAutoRangeAndConstraints,
Expand Down
217 changes: 117 additions & 100 deletions src/plot_api/subroutines.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,25 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;

fullLayout._paperdiv.style({
width: fullLayout.width + 'px',
height: fullLayout.height + 'px'
})
.selectAll('.main-svg')
.call(Drawing.setSize, fullLayout.width, fullLayout.height);
gd._context.setBackground(gd, fullLayout.paper_bgcolor);

exports.drawMainTitle(gd);
ModeBar.manage(gd);

// _has('cartesian') means SVG specifically, not GL2D - but GL2D
// can still get here because it makes some of the SVG structure
// for shared features like selections.
var hasSVGCartesian = fullLayout._has('cartesian');
var i;
if(!fullLayout._has('cartesian')) {
return gd._promises.length && Promise.all(gd._promises);
}

function getLinePosition(ax, counterAx, side) {
var lwHalf = ax._lw / 2;
Expand Down Expand Up @@ -103,25 +116,21 @@ function lsInner(gd) {
ax._mainSubplot = findMainSubplot(ax, fullLayout);
}

fullLayout._paperdiv
.style({
width: fullLayout.width + 'px',
height: fullLayout.height + 'px'
})
.selectAll('.main-svg')
.call(Drawing.setSize, fullLayout.width, fullLayout.height);

gd._context.setBackground(gd, fullLayout.paper_bgcolor);

var subplotSelection = fullLayout._paper.selectAll('g.subplot');

// figure out which backgrounds we need to draw, and in which layers
// to put them
// figure out which backgrounds we need to draw,
// and in which layers to put them
var lowerBackgroundIDs = [];
var backgroundIds = [];
var lowerDomains = [];
subplotSelection.each(function(d) {
var subplot = d[0];
var plotinfo = fullLayout._plots[subplot];
// no need to draw background when paper and plot color are the same color,
// activate mode just for large splom (which benefit the most from this
// optimization), but this could apply to all cartesian subplots.
var noNeedForBg = (
fullLayout._hasOnlyLargeSploms &&
fullLayout.paper_bgcolor === fullLayout.plot_bgcolor
alexcjohnson marked this conversation as resolved.
Show resolved Hide resolved
);

for(subplot in fullLayout._plots) {
plotinfo = fullLayout._plots[subplot];

if(plotinfo.mainplot) {
// mainplot is a reference to the main plot this one is overlaid on
Expand All @@ -131,23 +140,26 @@ function lsInner(gd) {
plotinfo.bg.remove();
}
plotinfo.bg = undefined;
return;
}

var xDomain = plotinfo.xaxis.domain;
var yDomain = plotinfo.yaxis.domain;
var plotgroup = plotinfo.plotgroup;

if(overlappingDomain(xDomain, yDomain, lowerDomains)) {
var pgNode = plotgroup.node();
var plotgroupBg = plotinfo.bg = Lib.ensureSingle(plotgroup, 'rect', 'bg');
pgNode.insertBefore(plotgroupBg.node(), pgNode.childNodes[0]);
} else {
plotgroup.select('rect.bg').remove();
lowerBackgroundIDs.push(subplot);
lowerDomains.push([xDomain, yDomain]);
var xDomain = plotinfo.xaxis.domain;
var yDomain = plotinfo.yaxis.domain;
var plotgroup = plotinfo.plotgroup;

if(overlappingDomain(xDomain, yDomain, lowerDomains)) {
var pgNode = plotgroup.node();
var plotgroupBg = plotinfo.bg = Lib.ensureSingle(plotgroup, 'rect', 'bg');
pgNode.insertBefore(plotgroupBg.node(), pgNode.childNodes[0]);
backgroundIds.push(subplot);
} else {
plotgroup.select('rect.bg').remove();
lowerDomains.push([xDomain, yDomain]);
if(!noNeedForBg) {
lowerBackgroundIDs.push(subplot);
backgroundIds.push(subplot);
}
}
}
});
}

// now create all the lower-layer backgrounds at once now that
// we have the list of subplots that need them
Expand All @@ -163,86 +175,97 @@ function lsInner(gd) {
fullLayout._plots[subplot].bg = d3.select(this);
});

subplotSelection.each(function(d) {
var subplot = d[0];
var plotinfo = fullLayout._plots[subplot];
var xa = plotinfo.xaxis;
var ya = plotinfo.yaxis;
// style all backgrounds
for(i = 0; i < backgroundIds.length; i++) {
plotinfo = fullLayout._plots[backgroundIds[i]];
xa = plotinfo.xaxis;
ya = plotinfo.yaxis;

if(plotinfo.bg && hasSVGCartesian) {
if(plotinfo.bg) {
plotinfo.bg
.call(Drawing.setRect,
xa._offset - pad, ya._offset - pad,
xa._length + 2 * pad, ya._length + 2 * pad)
.call(Color.fill, fullLayout.plot_bgcolor)
.style('stroke-width', 0);
}
}

// Clip so that data only shows up on the plot area.
var clipId = plotinfo.clipId = 'clip' + fullLayout._uid + subplot + 'plot';
if(!fullLayout._hasOnlyLargeSploms) {
for(subplot in fullLayout._plots) {
plotinfo = fullLayout._plots[subplot];
xa = plotinfo.xaxis;
ya = plotinfo.yaxis;

var plotClip = Lib.ensureSingleById(fullLayout._clips, 'clipPath', clipId, function(s) {
s.classed('plotclip', true)
.append('rect');
});
// Clip so that data only shows up on the plot area.
var clipId = plotinfo.clipId = 'clip' + fullLayout._uid + subplot + 'plot';

plotinfo.clipRect = plotClip.select('rect').attr({
width: xa._length,
height: ya._length
});
var plotClip = Lib.ensureSingleById(fullLayout._clips, 'clipPath', clipId, function(s) {
s.classed('plotclip', true)
.append('rect');
});

Drawing.setTranslate(plotinfo.plot, xa._offset, ya._offset);
plotinfo.clipRect = plotClip.select('rect').attr({
width: xa._length,
height: ya._length
});

var plotClipId;
var layerClipId;
Drawing.setTranslate(plotinfo.plot, xa._offset, ya._offset);

if(plotinfo._hasClipOnAxisFalse) {
plotClipId = null;
layerClipId = clipId;
} else {
plotClipId = clipId;
layerClipId = null;
}
var plotClipId;
var layerClipId;

Drawing.setClipUrl(plotinfo.plot, plotClipId);
if(plotinfo._hasClipOnAxisFalse) {
plotClipId = null;
layerClipId = clipId;
} else {
plotClipId = clipId;
layerClipId = null;
}

// stash layer clipId value (null or same as clipId)
// to DRY up Drawing.setClipUrl calls on trace-module and trace layers
// downstream
plotinfo.layerClipId = layerClipId;
Drawing.setClipUrl(plotinfo.plot, plotClipId);

// figure out extra axis line and tick positions as needed
if(!hasSVGCartesian) return;
// stash layer clipId value (null or same as clipId)
// to DRY up Drawing.setClipUrl calls on trace-module and trace layers
// downstream
plotinfo.layerClipId = layerClipId;
}
}

var xLinesXLeft, xLinesXRight, xLinesYBottom, xLinesYTop,
leftYLineWidth, rightYLineWidth;
var yLinesYBottom, yLinesYTop, yLinesXLeft, yLinesXRight,
connectYBottom, connectYTop;
var extraSubplot;
var xLinesXLeft, xLinesXRight, xLinesYBottom, xLinesYTop,
leftYLineWidth, rightYLineWidth;
var yLinesYBottom, yLinesYTop, yLinesXLeft, yLinesXRight,
connectYBottom, connectYTop;
var extraSubplot;

function xLinePath(y) {
return 'M' + xLinesXLeft + ',' + y + 'H' + xLinesXRight;
}
function xLinePath(y) {
return 'M' + xLinesXLeft + ',' + y + 'H' + xLinesXRight;
}

function xLinePathFree(y) {
return 'M' + xa._offset + ',' + y + 'h' + xa._length;
}
function xLinePathFree(y) {
return 'M' + xa._offset + ',' + y + 'h' + xa._length;
}

function yLinePath(x) {
return 'M' + x + ',' + yLinesYTop + 'V' + yLinesYBottom;
}
function yLinePath(x) {
return 'M' + x + ',' + yLinesYTop + 'V' + yLinesYBottom;
}

function yLinePathFree(x) {
return 'M' + x + ',' + ya._offset + 'v' + ya._length;
}
function yLinePathFree(x) {
return 'M' + x + ',' + ya._offset + 'v' + ya._length;
}

function mainPath(ax, pathFn, pathFnFree) {
if(!ax.showline || subplot !== ax._mainSubplot) return '';
if(!ax._anchorAxis) return pathFnFree(ax._mainLinePosition);
var out = pathFn(ax._mainLinePosition);
if(ax.mirror) out += pathFn(ax._mainMirrorPosition);
return out;
}
function mainPath(ax, pathFn, pathFnFree) {
if(!ax.showline || subplot !== ax._mainSubplot) return '';
if(!ax._anchorAxis) return pathFnFree(ax._mainLinePosition);
var out = pathFn(ax._mainLinePosition);
if(ax.mirror) out += pathFn(ax._mainMirrorPosition);
return out;
}

for(subplot in fullLayout._plots) {
plotinfo = fullLayout._plots[subplot];
xa = plotinfo.xaxis;
ya = plotinfo.yaxis;

/*
* x lines get longer where they meet y lines, to make a crisp corner.
Expand Down Expand Up @@ -323,11 +346,9 @@ function lsInner(gd) {
ya.linecolor : 'rgba(0,0,0,0)');
}
plotinfo.ylines.attr('d', yPath);
});
}

Axes.makeClipPaths(gd);
exports.drawMainTitle(gd);
ModeBar.manage(gd);

return gd._promises.length && Promise.all(gd._promises);
}
Expand Down Expand Up @@ -498,12 +519,8 @@ exports.doLegend = function(gd) {
return Plots.previousPromises(gd);
};

exports.doTicksRelayout = function(gd, rangesAltered) {
if(rangesAltered) {
Axes.doTicks(gd, Object.keys(rangesAltered), true);
} else {
Axes.doTicks(gd, 'redraw');
}
exports.doTicksRelayout = function(gd) {
Axes.doTicks(gd, 'redraw');

if(gd._fullLayout._hasOnlyLargeSploms) {
clearGlCanvases(gd);
Expand Down
1 change: 0 additions & 1 deletion src/plots/cartesian/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,6 @@ function makeSubplotLayer(gd, plotinfo) {
// and other places
// - we don't (x|y)lines and (x|y)axislayer for most subplots
// usually just the bottom x and left y axes.
plotinfo.plot = ensureSingle(plotgroup, 'g', 'plot');
plotinfo.xlines = ensureSingle(plotgroup, 'path', 'xlines-above');
plotinfo.ylines = ensureSingle(plotgroup, 'path', 'ylines-above');
plotinfo.xaxislayer = ensureSingle(plotgroup, 'g', 'xaxislayer-above');
Expand Down
4 changes: 3 additions & 1 deletion src/plots/cartesian/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,9 @@ function determineSearchTraces(gd, xAxes, yAxes, subplot) {
// FIXME: make sure we don't have more than single axis for splom
trace._xaxes[xAxisIds[0]] && trace._yaxes[yAxisIds[0]]
) {
searchTraces.push(createSearchInfo(trace._module, cd, xAxes[0], yAxes[0]));
var info = createSearchInfo(trace._module, cd, xAxes[0], yAxes[0]);
info.scene = gd._fullLayout._splomScenes[trace.uid];
searchTraces.push(info);
} else {
if(xAxisIds.indexOf(trace.xaxis) === -1) continue;
if(yAxisIds.indexOf(trace.yaxis) === -1) continue;
Expand Down
10 changes: 8 additions & 2 deletions src/plots/polar/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ var radialAxisAttrs = {
visible: extendFlat({}, axesAttrs.visible, {dflt: true}),
type: axesAttrs.type,

autorange: axesAttrs.autorange,
autorange: extendFlat({}, axesAttrs.autorange, {editType: 'plot'}),
rangemode: {
valType: 'enumerated',
values: ['tozero', 'nonnegative', 'normal'],
Expand All @@ -75,7 +75,13 @@ var radialAxisAttrs = {
'of the input data (same behavior as for cartesian axes).'
].join(' ')
},
range: axesAttrs.range,
range: extendFlat({}, axesAttrs.range, {
items: [
{valType: 'any', editType: 'plot', impliedEdits: {'^autorange': false}},
{valType: 'any', editType: 'plot', impliedEdits: {'^autorange': false}}
],
editType: 'plot'
}),

categoryorder: axesAttrs.categoryorder,
categoryarray: axesAttrs.categoryarray,
Expand Down
Loading