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

SVG trace on selection perf #2583

Merged
merged 12 commits into from
May 1, 2018
Merged

SVG trace on selection perf #2583

merged 12 commits into from
May 1, 2018

Conversation

etpinard
Copy link
Contributor

resolves #2459

There's still plenty of room for improvements (for example via #2548), but this PR gets scatter selection perf back to a level comparable to before the persistent selection PR (in #2135). Unfortunately, this means adding yet another method on the trace module objects. I hope @alexcjohnson won't mind. In brief, the new styleOnSelect methods only update DOM styles corresponding the selected and unselected attributes and thus by-passes much of the regular style DOM updates.

In numbers from the start to end of the selecting throttle using this codepen from #2459, before this PR we had ~300-400ms: and after: ~40-60ms

In gifs:

before

peek 2018-04-27 10-19

after

peek 2018-04-27 10-20

... that bypasses DOM style things selection doesn't affect.
    This speeds up on-selection perf and brings in back
    to a level comparably to before the persistent selection PR.
@@ -404,18 +404,20 @@ function updateSelectedState(gd, searchTraces, eventData) {
var len = items.length;
var item0 = items[0];
var trace0 = item0.cd[0].trace;
var _module = item0._module;
var fn = _module.styleOnSelect || _module.style;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like styleOnSelect, very nice solution!

But please call it something more descriptive than fn here - styleSelection?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure thing 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done in 0e91c6e

Drawing.selectedPointStyle(s.selectAll('path'), trace, gd);
Drawing.selectedPointStyle(s.selectAll('text'), trace, gd);
} else {
stylePoints(s, trace, gd);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need this else? I don't see a corresponding case in the previous code...

BTW, I'm hesitant to suggest this after the .select().select() data-mangling mess, but does it work to do Drawing.selectedPointStyle(s.selectAll('path,text'), trace, gd)? Is that any faster?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah oops, this should be Drawing.selectedTextStyle(s.selectAll('text'), trace, gd). I'll add a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do we need this else? I

To get back to the original state after double-click. Drawing.selectedPointStyle and Drawing.selectedTextStyle only handle selected / unselected styling off a "base" state given by stylePoints.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add a test.

added in 01df2d2

- make Drawing.pointStyle know how to apply [un]selected styles,
  so that we don't need to update DOM styles twice when we have
  set `selectedpoints`.
- make Drawing.selected(Point|Text)Style no longer need a base state
  (coming from Drawing.pointStyle) to apply correct styles.
... as on-selection styling now goes a different pathway than
    restyle().
@etpinard
Copy link
Contributor Author

Commit 3776e8f is a little messy, so I'll explain it here:

Previously (i.e. since the persistent selection PR #2135), [un]selected styles were applied to the DOM nodes assuming that the base style had been already applied to DOM nodes. Meaning that to get [un]selected style right, we needed to call Drawing.pointStyles first and then Drawing.selectedPointStyle() + Drawing.selectedTextStyle(). This turned out to be slow especially during selection (i.e. on drag). In other words, before commit 3776e8f, calling Drawing.selected(Point|Text)Style without Drawing.pointStyle lead to bugs.

Now post commit 3776e8f, Drawing.pointStyles knows how to apply [un]selected styles. This means DOM nodes style attributes are updated only once per Plots.style call. This should improve first-render perf for traces with [un]selected attributes.

Moreover, Drawing.selected(Point|Text)Style don't assume a base state anymore. They know how to handle cases where certain [un]selected keys are unset. This means that styleOnSelect (which bypasses Drawing.pointStyle for speed) now does the right thingTM.

};

drawing.singlePointStyle = function(d, sel, trace, markerScale, lineScale, gd) {
drawing.makePointStyleFns = function(trace) {
Copy link
Contributor Author

@etpinard etpinard Apr 30, 2018

Choose a reason for hiding this comment

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

Define trace-wide per-pt functions w/o knowledge of d3 or DOM methods so that non-svg modules (e.g. scattermapbox) can reuse them ♻️

s.each(function(d) {
for(var i = 0; i < seq.length; i++) {
seq[i](d3.select(this), d);
}
Copy link
Collaborator

@alexcjohnson alexcjohnson Apr 30, 2018

Choose a reason for hiding this comment

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

interesting approach with seq - it's not obvious to me that this is meaningfully different from 3 s.each calls inside if(functionExists) blocks, or 3 if(functionExists) blocks inside one s.each, did it make a big difference to do it this way?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

d3's each are a little slower than regular forEach and for-loops. Nothing worth losing sleep over, but we do gains a few ms using this sequence thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

... by gain, I mean lose a few ms and gain performance. 😄

@alexcjohnson
Copy link
Collaborator

Looks great! Thanks for the help understanding 3776e8f

💃

@etpinard etpinard merged commit 2b1713d into master May 1, 2018
@etpinard etpinard deleted the scatter-select-perf branch May 1, 2018 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Regression bug: LASSOing has become significantly slower between 1.31 to 1.32
2 participants