-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
When I search around for plotting libraries for a large number of data points, people are talking 50k, I'm talking 10M. I made a simple React demo that generates 10 random sinusoids of 1M points each. 10 * 100k works fine, but 10 * 1M becomes unusable.
var numpoints = 1e6;
var time: number[] = [];
for (let i=0; i<numpoints; i++) {
time.push(i);
}
var traces: object[] = [];
for (let i=0; i<10; i++) {
let points: number[] = [];
let freq = Math.random()/1000;
for (let j=0; j<numpoints; j++) {
points.push(Math.sin(j*freq));
}
traces.push({
x: time,
y: points,
type: 'scatter',
mode: 'lines',
yaxis: `y${i+1}`,
xaxis: `x${i+1}`,
})
}
// ...
<Plot
data={traces}
layout={ {
width: 2000,
height: 1000,
grid: {rows:5, columns: 2, pattern: "independent"},
title: 'A Fancy Plot'} }
/>
I did a bit of profiling, and there are two issues. The first on is relatively simple, and the comment already describes what needs to be done to make hovering over the plot not lag because it's looping over every single data point.
plotly.js/src/components/fx/helpers.js
Lines 59 to 62 in 623fcd1
// apply the distance function to each data point | |
// this is the longest loop... if this bogs down, we may need | |
// to create pre-sorted data (by x or y), not sure how to | |
// do this for 'closest' |
The second issue seems to be just the drawing of the plot itself after a drag or zoom action. It spends all its time in plot
, plotOne
and linePoints
.
What's interesting is that even if you zoom in, where it would only have to draw a small subset of the line, it's still just as slow.
plotly.js/src/traces/scatter/line_points.js
Line 346 in 623fcd1
// loop over ALL points in this trace |
So it seems like both problems could be solved with some sort of index to avoid looping over all the datapoints. Some suggestions to jumpstart the discussion:
- For the common case of a monotonous x axis, implement a simple binary/interpolation search (monotonicity could be detected or specified)
- Store points in a quadtree, to allow fast spatial indexing for any type of data. (such as https://github.com/plotly/point-cluster )
- Automatic downsampling. If I have 10M points, when zoomed out all the detail is lost anyway, but I still want to be able to zoom in and inspect it.
- Offload operations to a webworker. At some point you're going to need to do a thing 10M times, but don't freeze the UI to do it.
If I end up using Plotly in production I'd be happy to try and contribute towards this, but for now just some suggestions to see how the maintainers feel about the issue and what their preferred approach would be.