Skip to content

Conversation

@etpinard
Copy link
Contributor

@etpinard
Copy link
Contributor Author

@scjody is this PR still worth merging?

@scjody
Copy link

scjody commented Feb 19, 2018

We need something like this before we can close https://github.com/plotly/streambed/issues/9865. Right now image requests are being delayed unnecessarily due to server restarts, and we need to run 12 servers at all times (whereas we should be able to scale down to 3 off-peak).

I think it's worth waiting until you've had the chance to analyze some more server-breaking plots though, since this work is based on only one. I expect to have time to collect some more next week by modifying the load_test tool in https://github.com/plotly/plotly.js/tree/imageserver-testing-hacks to send requests sequentially and check the health of the imageserver immediately afterwards. (Note that it needs to be run against one server, not against a cluster.)

@etpinard
Copy link
Contributor Author

Thanks for the info @scjody 👌

@etpinard
Copy link
Contributor Author

etpinard commented Mar 8, 2018

Copy link

@scjody scjody left a comment

Choose a reason for hiding this comment

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

This looks good to me. I feel like someone with more plotly.js experience like @alexcjohnson should review it too.

💃

function maxPtsPerTraceType (type) {
switch (type) {
case 'scattergl':
case 'splom':
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not that we really have this info yet, but I'd have thought splom would need to be limited quite a bit lower, perhaps the same as parcoords provisionally but potentially even lower.

function findMaxArrayLength (cont) {
const lengths = Object.keys(cont)
.filter(k => Array.isArray(cont[k]))
.map(k => cont[k].length)
Copy link
Collaborator

Choose a reason for hiding this comment

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

2D arrays?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh right. We can get a better estimate for those. Thanks for noticing 👍

case 'histogram2dcontour':
case 'box':
case 'violin':
return 1e5
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can these really only handle 1e5? They're not actually displaying every point, I'd have thought we could bump up to 1e6 perhaps.

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 was thinking of box and violin for (box)points turned on. We could make a special case for those I guess.

Copy link
Collaborator

@alexcjohnson alexcjohnson Mar 8, 2018

Choose a reason for hiding this comment

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

Ah good call - most of the time outliers are a tiny fraction of total points, but not always... and certainly not if ...points='all'

if (Array.isArray(trace.dimensions)) {
return trace.dimensions
.map(findMaxArrayLength)
.reduce((a, v) => a + v)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nicely done

// cap the number of point per trace type
if (numberOfPtsPerTraceType[type] > maxPtsPerTraceType(type)) {
return true
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm imagining someone trying to hang our servers, sending in one trace of each type, each just under our limit... do we want to do something like:

budget += estimateDataLength(trace) / maxPtsPerTraceType(type);
if(budget > 1) return true;

.filter(k => Array.isArray(cont[k]))
.map(k => cont[k].length)

return Math.max(...lengths)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Better fall back to 0 if there are no arrays - otherwise the user could start with an empty trace (Math.max() = -Infinity) and every trace after that would be ignored.

- dive into 2d arrays to estimate their lengths
- bump box, violin, histogram and histogram2d max pt threshold to 1e6,
  and add special case for box and violin with sample points displayed
- use budget so that multiple traces close to threshold won't hang exporter
- make traces w/o array don't mess up count
@etpinard
Copy link
Contributor Author

etpinard commented Mar 9, 2018

@alexcjohnson thanks for the feedback! I think all your comments have been addressed in 884afdf


return Math.max(...lengths)
const lengths = arrays.map(arr => {
const innerArrays = arr.filter(Array.isArray)
Copy link
Collaborator

Choose a reason for hiding this comment

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

isn't this going to be super slow for big 1D arrays? Most if not all of our modules that support 1D or 2D differentiate just based on the first element.

Copy link
Contributor Author

@etpinard etpinard Mar 9, 2018

Choose a reason for hiding this comment

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

good call -> done in 851b803

if (
type === 'box' &&
trace.boxpoints === 'all' &&
len > 5e4
Copy link
Collaborator

Choose a reason for hiding this comment

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

In principle I guess the special cases should get included in the budget as well - otherwise you could include 199 x 5e4-point box traces...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea -> 0372d82

}
})

return arrays.length ? Math.max(...lengths) : 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

🐄 not that it matters, but Math.max(0, ...lengths) works too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤠 -> 851b803

@alexcjohnson
Copy link
Collaborator

Great, thanks! Still concerned about splom but we'll see once it exists 😄
💃

@etpinard
Copy link
Contributor Author

etpinard commented Mar 9, 2018

Still concerned about splom but we'll see once it exists

I have a good feeling splom with handle 1e7 points in less than 15 seconds. Aim high 🚀

@etpinard etpinard merged commit 948030a into master Mar 9, 2018
@etpinard etpinard deleted the will-figure-hang branch March 9, 2018 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants