leeoniya / uPlot

📈 A small, fast chart for time series, lines, areas, ohlc & bars
MIT License
8.83k stars 385 forks source link

Question: Showing gaps for missing data when using Float32arrays as data #974

Closed AdilRabbani closed 4 months ago

AdilRabbani commented 4 months ago

Hi :) First of all, really thanks for such a performant time series charting library. I am porting the existing code I had for which I was using another charting library and the difference was really noticeable when I switched to uplot. I am dealing with large amounts of data i.e series containing 300k or even millions of data points and for this purpose my dataset is in the form of Float32arrays so for the x values as well as the incoming y values, all are received as Float32arrays. The data can also have gaps and in places where there is supposed to be no value (gap), the value there is NaN. One very simple array would look like:

[1, 2, 3, NaN, NaN, 4, 5, NaN, 6....]

I went through the demo example for showing gaps but it does not use Float32arrays and as far as I know, in order to show a gap on the plotted series, the array should contain nulls in places of gaps. The problem with Float32arrays is that it cannot have null values. So my question: Can I use NaNs to show gaps in my plotted series? If so, then how? If this is currently not possible, what would be the best workaround currently that will still help to be as performant as possible? Thanks in advance. Pardon me if this has already been mentioned somewhere.

PS. I was also thinking of maybe contributing to the library. At least I have some demo examples in mind which might be helpful for everyone who tries to use uplot. :)

leeoniya commented 4 months ago

there's currently no way to treat NaNs as gaps. i think adding Number.isNaN() testing to each value in addition to the existing == null check will make things slower by quite a bit for all use cases.

probably easiest to convert to normal array with nulls.

let len = 300_000;
let arr = new Float32Array(len);

for (let i = 0; i < len; i++) {
  arr[i] = i % 100 === 0 ? NaN : Math.random() * 1000;
}

console.time('a');
let a = Array(len);
for (let i = 0; i < len; i++) {
  a[i] = Number.isNaN(arr[i]) ? null : arr[i];
}
console.timeEnd('a');

it takes < 10ms for 300k values on my machine:

image

AdilRabbani commented 4 months ago

Thanks for the quick reply. I'll go with this approach then 👍