Skip to content

Aggressive splom perf #3057

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 30 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from 3 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
43 changes: 16 additions & 27 deletions src/plot_api/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ var Plots = require('../plots/plots');
var AxisIds = require('../plots/cartesian/axis_ids');
var cleanId = AxisIds.cleanId;
var getFromTrace = AxisIds.getFromTrace;
var id2name = AxisIds.id2name;
var Color = require('../components/color');


Expand Down Expand Up @@ -571,35 +570,25 @@ exports.hasParent = function(aobj, attr) {
* @param {object} layoutUpdate: any update being done concurrently to the layout,
* which may supercede clearing the axis types
*/
var xy = ['x', 'y'];
var xyz = ['x', 'y', 'z'];
var axLetters = ['x', 'y', 'z'];
exports.clearAxisTypes = function(gd, traces, layoutUpdate) {
for(var i = 0; i < traces.length; i++) {
var trace = gd._fullData[i];
var letters = Registry.traceIs(trace, 'gl3d') ? xyz : xy;

for(var j = 0; j < letters.length; j++) {
var l = letters[j];
var axes = trace.type === 'splom' ?
trace[l + 'axes'].map(function(id) { return gd._fullLayout[id2name(id)]; }) :
[getFromTrace(gd, trace, l)];

for(var k = 0; k < axes.length; k++) {
var ax = axes[k];

// do not clear log type - that's never an auto result so must have been intentional
if(ax && ax.type !== 'log') {
var axAttr = ax._name;
var sceneName = ax._id.substr(1);
if(sceneName.substr(0, 5) === 'scene') {
if(layoutUpdate[sceneName] !== undefined) continue;
axAttr = sceneName + '.' + axAttr;
}
var typeAttr = axAttr + '.type';

if(layoutUpdate[axAttr] === undefined && layoutUpdate[typeAttr] === undefined) {
Lib.nestedProperty(gd.layout, typeAttr).set(null);
}
for(var j = 0; j < 3; j++) {
var ax = getFromTrace(gd, trace, axLetters[j]);

// do not clear log type - that's never an auto result so must have been intentional
if(ax && ax.type !== 'log') {
var axAttr = ax._name;
var sceneName = ax._id.substr(1);
if(sceneName.substr(0, 5) === 'scene') {
if(layoutUpdate[sceneName] !== undefined) continue;
axAttr = sceneName + '.' + axAttr;
}
var typeAttr = axAttr + '.type';

if(layoutUpdate[axAttr] === undefined && layoutUpdate[typeAttr] === undefined) {
Lib.nestedProperty(gd.layout, typeAttr).set(null);
}
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ exports.plot = function(gd, data, layout, config) {
Lib.error(msg);
} else {
Lib.log(msg + ' Clearing graph and plotting again.');
Plots.cleanPlot([], {}, gd._fullData, fullLayout, gd.calcdata);
Plots.cleanPlot([], {}, gd._fullData, fullLayout);
Plots.supplyDefaults(gd);
fullLayout = gd._fullLayout;
Plots.doCalcdata(gd);
Expand Down Expand Up @@ -614,7 +614,7 @@ exports.newPlot = function(gd, data, layout, config) {
gd = Lib.getGraphDiv(gd);

// remove gl contexts
Plots.cleanPlot([], {}, gd._fullData || [], gd._fullLayout || {}, gd.calcdata || []);
Plots.cleanPlot([], {}, gd._fullData || [], gd._fullLayout || {});

Plots.purge(gd);
return exports.plot(gd, data, layout, config);
Expand Down Expand Up @@ -3199,10 +3199,9 @@ exports.purge = function purge(gd) {

var fullLayout = gd._fullLayout || {};
var fullData = gd._fullData || [];
var calcdata = gd.calcdata || [];

// remove gl contexts
Plots.cleanPlot([], {}, fullData, fullLayout, calcdata);
Plots.cleanPlot([], {}, fullData, fullLayout);

// purge properties
Plots.purge(gd);
Expand Down
6 changes: 3 additions & 3 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ plots.supplyDefaults = function(gd, opts) {
plots.linkSubplots(newFullData, newFullLayout, oldFullData, oldFullLayout);

// clean subplots and other artifacts from previous plot calls
plots.cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout, oldCalcdata);
plots.cleanPlot(newFullData, newFullLayout, oldFullData, oldFullLayout);

// relink functions and _ attributes to promote consistency between plots
relinkPrivateKeys(newFullLayout, oldFullLayout);
Expand Down Expand Up @@ -714,15 +714,15 @@ plots._hasPlotType = function(category) {
return false;
};

plots.cleanPlot = function(newFullData, newFullLayout, oldFullData, oldFullLayout, oldCalcdata) {
plots.cleanPlot = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
var i, j;

var basePlotModules = oldFullLayout._basePlotModules || [];
for(i = 0; i < basePlotModules.length; i++) {
var _module = basePlotModules[i];

if(_module.clean) {
_module.clean(newFullData, newFullLayout, oldFullData, oldFullLayout, oldCalcdata);
_module.clean(newFullData, newFullLayout, oldFullData, oldFullLayout);
}
}

Expand Down
13 changes: 8 additions & 5 deletions src/traces/splom/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ function makeAxesValObject(axLetter) {
},
description: [
'Sets the list of ' + axLetter + ' axes',
'corresponding to this splom trace.',
'corresponding to dimensions of this splom trace.',
'By default, a splom will match the first N ' + axLetter + 'axes',
'where N is the number of input dimensions.'
'where N is the number of input dimensions.',
'Note that, in case where `diagonal.visible` is false and `showupperhalf`',
'or `showlowerhalf` is false, this splom trace will generate',
'one less x-axis and one less y-axis.',
].join(' ')
};
}
Expand Down Expand Up @@ -125,7 +128,7 @@ module.exports = {
valType: 'boolean',
role: 'info',
dflt: true,
editType: 'calc+clearAxisTypes',
editType: 'calc',
description: [
'Determines whether or not subplots on the diagonal are displayed.'
].join(' ')
Expand All @@ -142,7 +145,7 @@ module.exports = {
valType: 'boolean',
role: 'info',
dflt: true,
editType: 'calc+clearAxisTypes',
editType: 'calc',
description: [
'Determines whether or not subplots on the upper half',
'from the diagonal are displayed.'
Expand All @@ -152,7 +155,7 @@ module.exports = {
valType: 'boolean',
role: 'info',
dflt: true,
editType: 'calc+clearAxisTypes',
editType: 'calc',
description: [
'Determines whether or not subplots on the lower half',
'from the diagonal are displayed.'
Expand Down
136 changes: 67 additions & 69 deletions src/traces/splom/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,97 +73,95 @@ function handleAxisDefaults(traceIn, traceOut, layout, coerce) {
var showDiag = traceOut.diagonal.visible;
var i, j;

// N.B. one less x axis AND one less y axis when hiding one half and the diagonal
var axDfltLength = !showDiag && (!showUpper || !showLower) ? dimLength - 1 : dimLength;
var xAxesDflt = new Array(dimLength);
var yAxesDflt = new Array(dimLength);

var xaxes = coerce('xaxes', fillAxisIdArray('x', axDfltLength));
var yaxes = coerce('yaxes', fillAxisIdArray('y', axDfltLength));
for(i = 0; i < dimLength; i++) {
var suffix = i ? i + 1 : '';
xAxesDflt[i] = 'x' + suffix;
yAxesDflt[i] = 'y' + suffix;
}

// to avoid costly indexOf
traceOut._xaxes = arrayToHashObject(xaxes);
traceOut._yaxes = arrayToHashObject(yaxes);
var xaxes = coerce('xaxes', xAxesDflt);
var yaxes = coerce('yaxes', yAxesDflt);

// allow users to under-specify number of axes
var axLength = Math.min(axDfltLength, xaxes.length, yaxes.length);
// build list of [x,y] axis corresponding to each dimensions[i],
// very useful for passing options to regl-splom
var diag = traceOut._diag = new Array(dimLength);

// fill in splom subplot keys
for(i = 0; i < axLength; i++) {
for(j = 0; j < axLength; j++) {
var id = xaxes[i] + yaxes[j];
// lookup for 'drawn' x|y axes, to avoid costly indexOf downstream
traceOut._xaxes = {};
traceOut._yaxes = {};

if(i > j && showUpper) {
layout._splomSubplots[id] = 1;
} else if(i < j && showLower) {
layout._splomSubplots[id] = 1;
} else if(i === j && (showDiag || !showLower || !showUpper)) {
// need to include diagonal subplots when
// hiding one half and the diagonal
layout._splomSubplots[id] = 1;
// list of 'drawn' x|y axes, use to generate list of subplots
var xList = [];
var yList = [];

function fillAxisStashes(axId, dim, list) {
if(!axId) return;

var axLetter = axId.charAt(0);
var stash = layout._splomAxes[axLetter];

traceOut['_' + axLetter + 'axes'][axId] = 1;
list.push(axId);

if(!(axId in stash)) {
var s = stash[axId] = {};
if(dim) {
s.label = dim.label || '';
if(dim.visible && dim.axis) {
s.type = dim.axis.type;
}
}
}
}

// build list of [x,y] axis corresponding to each dimensions[i],
// very useful for passing options to regl-splom
var diag = traceOut._diag = new Array(dimLength);

// cases where showDiag and showLower or showUpper are false
// no special treatment as the xaxes and yaxes items no longer match
// the dimensions items 1-to-1
var xShift = !showDiag && !showLower ? -1 : 0;
var yShift = !showDiag && !showUpper ? -1 : 0;
// no special treatment as the 'drawn' x-axes and y-axes no longer match
// the dimensions items and xaxes|yaxes 1-to-1
var mustShiftX = !showDiag && !showLower;
var mustShiftY = !showDiag && !showUpper;

for(i = 0; i < dimLength; i++) {
var dim = dimensions[i];
var xaId = xaxes[i + xShift];
var yaId = yaxes[i + yShift];

fillAxisStash(layout, xaId, dim);
fillAxisStash(layout, yaId, dim);

// note that some the entries here may be undefined
diag[i] = [xaId, yaId];
}
var i0 = i === 0;
var iN = i === dimLength - 1;

// when lower half is omitted, override grid default
// to make sure axes remain on the left/bottom of the plot area
if(!showLower) {
layout._splomGridDflt.xside = 'bottom';
layout._splomGridDflt.yside = 'left';
}
}
var xaId = (i0 && mustShiftX) || (iN && mustShiftY) ?
undefined :
xaxes[i];

function fillAxisIdArray(axLetter, len) {
var out = new Array(len);
var yaId = (i0 && mustShiftY) || (iN && mustShiftX) ?
undefined :
yaxes[i];

for(var i = 0; i < len; i++) {
out[i] = axLetter + (i ? i + 1 : '');
fillAxisStashes(xaId, dim, xList);
fillAxisStashes(yaId, dim, yList);
diag[i] = [xaId, yaId];
}

return out;
}

function fillAxisStash(layout, axId, dim) {
if(!axId) return;

var axLetter = axId.charAt(0);
var stash = layout._splomAxes[axLetter];
// fill in splom subplot keys
for(i = 0; i < xList.length; i++) {
for(j = 0; j < yList.length; j++) {
var id = xList[i] + yList[j];

if(!(axId in stash)) {
var s = stash[axId] = {};
if(dim) {
s.label = dim.label || '';
if(dim.visible && dim.axis) {
s.type = dim.axis.type;
if(i > j && showUpper) {
layout._splomSubplots[id] = 1;
} else if(i < j && showLower) {
layout._splomSubplots[id] = 1;
} else if(i === j && (showDiag || !showLower || !showUpper)) {
// need to include diagonal subplots when
// hiding one half and the diagonal
layout._splomSubplots[id] = 1;
}
}
}
}

function arrayToHashObject(arr) {
var obj = {};
for(var i = 0; i < arr.length; i++) {
obj[arr[i]] = 1;
// when lower half is omitted, override grid default
// to make sure axes remain on the left/bottom of the plot area
if(!showLower) {
layout._splomGridDflt.xside = 'bottom';
layout._splomGridDflt.yside = 'left';
}
return obj;
}
Loading