Skip to content

Commit 3054cb5

Browse files
committed
Reuse SVG DOM elements for scatter traces
1 parent 0725ea4 commit 3054cb5

File tree

8 files changed

+471
-180
lines changed

8 files changed

+471
-180
lines changed

src/components/errorbars/plot.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,24 @@ module.exports = function plot(traces, plotinfo) {
3434
trace.marker.maxdisplayed > 0
3535
);
3636

37+
var keyFunc;
38+
39+
if(trace.key) {
40+
keyFunc = function(d) { return d.key; };
41+
}
42+
3743
if(!yObj.visible && !xObj.visible) return;
3844

39-
var errorbars = d3.select(this).selectAll('g.errorbar')
40-
.data(Lib.identity);
45+
var selection = d3.select(this).selectAll('g.errorbar');
4146

42-
errorbars.enter().append('g')
47+
var join = selection.data(Lib.identity, keyFunc);
48+
49+
join.enter().append('g')
4350
.classed('errorbar', true);
4451

45-
errorbars.each(function(d) {
52+
join.exit().remove();
53+
54+
join.each(function(d) {
4655
var errorbar = d3.select(this);
4756
var coords = errorCoords(d, xa, ya);
4857

src/plots/cartesian/index.js

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,61 +25,74 @@ exports.attrRegex = constants.attrRegex;
2525

2626
exports.attributes = require('./attributes');
2727

28-
exports.plot = function(gd) {
28+
exports.plot = function(gd, traces) {
29+
var cdSubplot, cd, trace, i, j, k, isFullReplot;
30+
2931
var fullLayout = gd._fullLayout,
3032
subplots = Plots.getSubplotIds(fullLayout, 'cartesian'),
3133
calcdata = gd.calcdata,
3234
modules = fullLayout._modules;
3335

34-
function getCdSubplot(calcdata, subplot) {
35-
var cdSubplot = [];
36-
37-
for(var i = 0; i < calcdata.length; i++) {
38-
var cd = calcdata[i];
39-
var trace = cd[0].trace;
40-
41-
if(trace.xaxis + trace.yaxis === subplot) {
42-
cdSubplot.push(cd);
43-
}
36+
if(!Array.isArray(traces)) {
37+
// If traces is not provided, then it's a complete replot and missing
38+
// traces are removed
39+
isFullReplot = true;
40+
traces = [];
41+
for(i = 0; i < calcdata.length; i++) {
42+
traces.push(i);
4443
}
45-
46-
return cdSubplot;
44+
} else {
45+
// If traces are explicitly specified, then it's a partial replot and
46+
// traces are not removed.
47+
isFullReplot = false;
4748
}
4849

49-
function getCdModule(cdSubplot, _module) {
50-
var cdModule = [];
50+
for(i = 0; i < subplots.length; i++) {
51+
var subplot = subplots[i],
52+
subplotInfo = fullLayout._plots[subplot];
53+
54+
// Get all calcdata for this subplot:
55+
cdSubplot = [];
56+
for(j = 0; j < calcdata.length; j++) {
57+
cd = calcdata[j];
58+
trace = cd[0].trace;
5159

52-
for(var i = 0; i < cdSubplot.length; i++) {
53-
var cd = cdSubplot[i];
54-
var trace = cd[0].trace;
60+
// Skip trace if whitelist provided and it's not whitelisted:
61+
// if (Array.isArray(traces) && traces.indexOf(i) === -1) continue;
5562

56-
if((trace._module === _module) && (trace.visible === true)) {
57-
cdModule.push(cd);
63+
if(trace.xaxis + trace.yaxis === subplot && traces.indexOf(trace.index) !== -1) {
64+
cdSubplot.push(cd);
5865
}
5966
}
6067

61-
return cdModule;
62-
}
63-
64-
for(var i = 0; i < subplots.length; i++) {
65-
var subplot = subplots[i],
66-
subplotInfo = fullLayout._plots[subplot],
67-
cdSubplot = getCdSubplot(calcdata, subplot);
68-
6968
// remove old traces, then redraw everything
70-
// TODO: use enter/exit appropriately in the plot functions
71-
// so we don't need this - should sometimes be a big speedup
72-
if(subplotInfo.plot) subplotInfo.plot.selectAll('g.trace').remove();
69+
// TODO: scatterlayer is manually excluded from this since it knows how
70+
// to update instead of fully removing and redrawing every time. The
71+
// remaining plot traces should also be able to do this. Once implemented,
72+
// we won't need this - which should sometimes be a big speedup.
73+
if(subplotInfo.plot) {
74+
subplotInfo.plot.selectAll('g:not(.scatterlayer)').selectAll('g.trace').remove();
75+
}
7376

74-
for(var j = 0; j < modules.length; j++) {
77+
// Plot all traces for each module at once:
78+
for(j = 0; j < modules.length; j++) {
7579
var _module = modules[j];
7680

7781
// skip over non-cartesian trace modules
7882
if(_module.basePlotModule.name !== 'cartesian') continue;
7983

8084
// plot all traces of this type on this subplot at once
81-
var cdModule = getCdModule(cdSubplot, _module);
82-
_module.plot(gd, subplotInfo, cdModule);
85+
var cdModule = [];
86+
for(k = 0; k < cdSubplot.length; k++) {
87+
cd = cdSubplot[k];
88+
trace = cd[0].trace;
89+
90+
if((trace._module === _module) && (trace.visible === true)) {
91+
cdModule.push(cd);
92+
}
93+
}
94+
95+
_module.plot(gd, subplotInfo, cdModule, isFullReplot);
8396
}
8497
}
8598
};

src/plots/plots.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,12 +582,17 @@ plots.cleanPlot = function(newFullData, newFullLayout, oldFullData, oldFullLayou
582582
if(oldUid === newTrace.uid) continue oldLoop;
583583
}
584584

585-
// clean old heatmap and contour traces
585+
// clean old heatmap, contour, and scatter traces
586+
//
587+
// Note: This is also how scatter traces (cartesian and scatterternary) get
588+
// removed since otherwise the scatter module is not called (and so the join
589+
// doesn't register the removal) if scatter traces disappear entirely.
586590
if(hasPaper) {
587591
oldFullLayout._paper.selectAll(
588592
'.hm' + oldUid +
589593
',.contour' + oldUid +
590-
',#clip' + oldUid
594+
',#clip' + oldUid +
595+
',.trace' + oldUid
591596
).remove();
592597
}
593598

src/traces/scatter/link_traces.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = function linkTraces(gd, plotinfo, cdscatter) {
12+
var cd, trace;
13+
var prevtrace = null;
14+
15+
for(var i = 0; i < cdscatter.length; ++i) {
16+
cd = cdscatter[i];
17+
trace = cd[0].trace;
18+
19+
// Note: The check which ensures all cdscatter here are for the same axis and
20+
// are either cartesian or scatterternary has been removed. This code assumes
21+
// the passed scattertraces have been filtered to the proper plot types and
22+
// the proper subplots.
23+
if(trace.visible === true) {
24+
trace._nexttrace = null;
25+
26+
if(['tonextx', 'tonexty', 'tonext'].indexOf(trace.fill) !== -1) {
27+
trace._prevtrace = prevtrace;
28+
29+
if(prevtrace) {
30+
prevtrace._nexttrace = trace;
31+
}
32+
}
33+
34+
prevtrace = trace;
35+
} else {
36+
trace._prevtrace = trace._nexttrace = null;
37+
}
38+
}
39+
};

0 commit comments

Comments
 (0)