Skip to content

Commit 97cb217

Browse files
authored
Merge pull request #3057 from plotly/splom-perf
Aggressive splom perf
2 parents 30ed4a4 + 4137433 commit 97cb217

29 files changed

+1798
-531
lines changed

Diff for: src/components/fx/hover.js

+4
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,10 @@ function _hover(gd, evt, subplot, noHoverEvent) {
471471
if(fullLayout[subplotId]) {
472472
pointData.subplot = fullLayout[subplotId]._subplot;
473473
}
474+
// add ref to splom scene
475+
if(fullLayout._splomScenes && fullLayout._splomScenes[trace.uid]) {
476+
pointData.scene = fullLayout._splomScenes[trace.uid];
477+
}
474478

475479
closedataPreviousLength = hoverData.length;
476480

Diff for: src/plot_api/edit_types.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var isPlainObject = Lib.isPlainObject;
1515
var traceOpts = {
1616
valType: 'flaglist',
1717
extras: ['none'],
18-
flags: ['calc', 'clearAxisTypes', 'plot', 'style', 'colorbars'],
18+
flags: ['calc', 'clearAxisTypes', 'plot', 'style', 'markerSize', 'colorbars'],
1919
description: [
2020
'trace attributes should include an `editType` string matching this flaglist.',
2121
'*calc* is the most extensive: a full `Plotly.plot` starting by clearing `gd.calcdata`',
@@ -24,7 +24,8 @@ var traceOpts = {
2424
'cause the automatic axis type detection to change. Log type will not be cleared, as that',
2525
'is never automatically chosen so must have been user-specified.',
2626
'*plot* calls `Plotly.plot` but without first clearing `gd.calcdata`.',
27-
'*style* only calls `module.style` for all trace modules and redraws the legend.',
27+
'*style* only calls `module.style` (or module.editStyle) for all trace modules and redraws the legend.',
28+
'*markerSize* is like *style*, but propagate axis-range changes due to scatter `marker.size`',
2829
'*colorbars* only redraws colorbars.'
2930
].join(' ')
3031
};

Diff for: src/plot_api/plot_api.js

+48-18
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ exports.plot = function(gd, data, layout, config) {
269269
Lib.error(msg);
270270
} else {
271271
Lib.log(msg + ' Clearing graph and plotting again.');
272-
Plots.cleanPlot([], {}, gd._fullData, fullLayout, gd.calcdata);
272+
Plots.cleanPlot([], {}, gd._fullData, fullLayout);
273273
Plots.supplyDefaults(gd);
274274
fullLayout = gd._fullLayout;
275275
Plots.doCalcdata(gd);
@@ -614,7 +614,7 @@ exports.newPlot = function(gd, data, layout, config) {
614614
gd = Lib.getGraphDiv(gd);
615615

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

619619
Plots.purge(gd);
620620
return exports.plot(gd, data, layout, config);
@@ -1344,8 +1344,21 @@ exports.restyle = function restyle(gd, astr, val, _traces) {
13441344
} else {
13451345
seq.push(Plots.previousPromises);
13461346

1347+
// maybe only call Plots.supplyDataDefaults in the splom case,
1348+
// to skip over long and slow axes defaults
13471349
Plots.supplyDefaults(gd);
13481350

1351+
if(flags.markerSize) {
1352+
Plots.doCalcdata(gd);
1353+
addAxRangeSequence(seq);
1354+
1355+
// TODO
1356+
// if all axes have autorange:false, then
1357+
// proceed to subroutines.doTraceStyle(),
1358+
// otherwise we must go through addAxRangeSequence,
1359+
// which in general must redraws 'all' axes
1360+
}
1361+
13491362
if(flags.style) seq.push(subroutines.doTraceStyle);
13501363
if(flags.colorbars) seq.push(subroutines.doColorBars);
13511364

@@ -1595,8 +1608,10 @@ function _restyle(gd, aobj, traces) {
15951608
else {
15961609
if(valObject) {
15971610
// must redo calcdata when restyling array values of arrayOk attributes
1598-
if(valObject.arrayOk && (
1599-
Lib.isArrayOrTypedArray(newVal) || Lib.isArrayOrTypedArray(oldVal))
1611+
// ... but no need to this for regl-based traces
1612+
if(valObject.arrayOk &&
1613+
!Registry.traceIs(contFull, 'regl') &&
1614+
(Lib.isArrayOrTypedArray(newVal) || Lib.isArrayOrTypedArray(oldVal))
16001615
) {
16011616
flags.calc = true;
16021617
}
@@ -1724,15 +1739,11 @@ exports.relayout = function relayout(gd, astr, val) {
17241739
seq.push(subroutines.layoutReplot);
17251740
}
17261741
else if(Object.keys(aobj).length) {
1727-
Plots.supplyDefaults(gd);
1742+
axRangeSupplyDefaultsByPass(gd, flags, specs) || Plots.supplyDefaults(gd);
17281743

17291744
if(flags.legend) seq.push(subroutines.doLegend);
17301745
if(flags.layoutstyle) seq.push(subroutines.layoutStyles);
1731-
1732-
if(flags.axrange) {
1733-
addAxRangeSequence(seq, specs.rangesAltered);
1734-
}
1735-
1746+
if(flags.axrange) addAxRangeSequence(seq, specs.rangesAltered);
17361747
if(flags.ticks) seq.push(subroutines.doTicksRelayout);
17371748
if(flags.modebar) seq.push(subroutines.doModeBar);
17381749
if(flags.camera) seq.push(subroutines.doCamera);
@@ -1756,13 +1767,35 @@ exports.relayout = function relayout(gd, astr, val) {
17561767
});
17571768
};
17581769

1770+
// Optimization mostly for large splom traces where
1771+
// Plots.supplyDefaults can take > 100ms
1772+
function axRangeSupplyDefaultsByPass(gd, flags, specs) {
1773+
var k;
1774+
1775+
if(!flags.axrange) return false;
1776+
1777+
for(k in flags) {
1778+
if(k !== 'axrange' && flags[k]) return false;
1779+
}
1780+
1781+
for(k in specs.rangesAltered) {
1782+
var axName = Axes.id2name(k);
1783+
var axIn = gd.layout[axName];
1784+
var axOut = gd._fullLayout[axName];
1785+
axOut.autorange = axIn.autorange;
1786+
axOut.range = axIn.range.slice();
1787+
axOut.cleanRange();
1788+
}
1789+
return true;
1790+
}
1791+
17591792
function addAxRangeSequence(seq, rangesAltered) {
17601793
// N.B. leave as sequence of subroutines (for now) instead of
17611794
// subroutine of its own so that finalDraw always gets
17621795
// executed after drawData
17631796
var doTicks = rangesAltered ?
1764-
function(gd) { return subroutines.doTicksRelayout(gd, rangesAltered); } :
1765-
subroutines.doTicksRelayout;
1797+
function(gd) { return Axes.doTicks(gd, Object.keys(rangesAltered), true); } :
1798+
function(gd) { return Axes.doTicks(gd, 'redraw'); };
17661799

17671800
seq.push(
17681801
subroutines.doAutoRangeAndConstraints,
@@ -2179,15 +2212,13 @@ exports.update = function update(gd, traceUpdate, layoutUpdate, _traces) {
21792212
}
21802213
else {
21812214
seq.push(Plots.previousPromises);
2182-
Plots.supplyDefaults(gd);
2215+
axRangeSupplyDefaultsByPass(gd, relayoutFlags, relayoutSpecs) || Plots.supplyDefaults(gd);
21832216

21842217
if(restyleFlags.style) seq.push(subroutines.doTraceStyle);
21852218
if(restyleFlags.colorbars) seq.push(subroutines.doColorBars);
21862219
if(relayoutFlags.legend) seq.push(subroutines.doLegend);
21872220
if(relayoutFlags.layoutstyle) seq.push(subroutines.layoutStyles);
2188-
if(relayoutFlags.axrange) {
2189-
addAxRangeSequence(seq, relayoutSpecs.rangesAltered);
2190-
}
2221+
if(relayoutFlags.axrange) addAxRangeSequence(seq, relayoutSpecs.rangesAltered);
21912222
if(relayoutFlags.ticks) seq.push(subroutines.doTicksRelayout);
21922223
if(relayoutFlags.modebar) seq.push(subroutines.doModeBar);
21932224
if(relayoutFlags.camera) seq.push(subroutines.doCamera);
@@ -3191,10 +3222,9 @@ exports.purge = function purge(gd) {
31913222

31923223
var fullLayout = gd._fullLayout || {};
31933224
var fullData = gd._fullData || [];
3194-
var calcdata = gd.calcdata || [];
31953225

31963226
// remove gl contexts
3197-
Plots.cleanPlot([], {}, fullData, fullLayout, calcdata);
3227+
Plots.cleanPlot([], {}, fullData, fullLayout);
31983228

31993229
// purge properties
32003230
Plots.purge(gd);

0 commit comments

Comments
 (0)