feral-dot-io / leptos-chartistry

Chartistry is an extensible charting library for Leptos

Home Page:https://feral-dot-io.github.io/leptos-chartistry/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Stream in values support

EstebanBorai opened this issue · comments

Hi @feral-dot-io!

Thanks so much for creating this crate! While checking out the examples available here:

https://feral-dot-io.github.io/leptos-chartistry/examples.html

I was wondering if it's possible to support a continuously updated chart? So I can have a window from a set of values rendered in the chart while data is being streamed-in?

Thanks in advance!

I'm glad you like Chartistry!

I agree this is a missing example. I have done a little bit of exploration on this in the past and I wasn't sure on the best answer so I left it out. Here are my thoughts on this...

The problem comes down to lines being drawn with an SVG <path d="..."> meaning the lines get drawn and rendered as a whole. This puts limits on what can be offered for fine-grained reactivity as it looks like Leptos updates on a per HTML attribute basis. Or at least, this is what the browser console suggests. So Chart's data= being a signal of Vec<T> is a reflection of this.

This kind of makes sense as the browser would be redrawing the whole line when you add a point and shuffle another off the other end. I have some ideas that could improve things but they would likely just come down to benchmarking browser implementations.

I've noticed that when (through the power of Leptos) just the lines are updated, performance is fairly good. Have you given it a go yet? Did you run into problems? Here are a bunch of ideas that should help:

  • Ensure the chart layout doesn't change with things like TickLabels::with_min_chars. If you change the layout then the dimensions of everything has to change so it must be avoided at all costs.
  • If the layout doesn't change, try to make sure the internals like the values of tick labels don't change. For this, setting a data range on the X and Y axis would work.
  • Limit to 1,000 data points or fewer. Too many and you're doing a lot of work. Sampling would be a nice feature here.
  • Avoid line markers. These are extra per-point nodes.
  • Collecting updates. If you batch updates to a 10-100ms window instead of updating on every new point received then you lower the number of updates.

With these in place it should reduce updates to just "redraw the lines" which is where you want things to be. I've found Firefox's performance profiler to be good at measuring what's happening.

Hi @feral-dot-io! Thanks so much for the quick prompt!

Yeah, I have been trying different approaches so far, but the one that worked well for me
was actually pretty straightforward:

Given that I have a continuous data stream where every item is a Vec<Data> where Data is a struct containing different measurements, what I found as a solution was moving the chart values once a certain amount of intervals were available.

Hope this sketch is of help:

Screenshot 2024-03-10 at 2 19 25 PM

So whenever an item is pulled from the stream:

  1. The new item is appended to the dataset
  2. The very first item from the database is popped
  3. Dataset is updated in state, causing the chart to update

The downside from this approach is related to performance, given that Im resetting the Vec<Data> in the RwSignal, it might be repainting the whole chart.

That sounds about right!

If you enable debug on your chart it will print debug statements to your browser console so you can see when components re-render. That should give an idea of when things are re-rendering. Ideally you'd see no re-renders -- this is fine-grained reactivity in action.

If you do then it's probably a good idea to look at why. Sharing your call and a screenshot might be a good start.

Otherwise I've spotted that there's no debug call on lines so you won't see feedback on that. I also found create_owning_memo released a few weeks ago that fits your usecase quite well.

Also, do you mind sharing what approaches you've taken? What did you start with? What did you try?

A general idea of what you ran into would be helpful so I can adjust the docs accordingly. I'm thinking about switching the site to an mdbook.

Also, do you mind sharing what approaches you've taken? What did you start with? What did you try?

A general idea of what you ran into would be helpful so I can adjust the docs accordingly. I'm thinking about switching the site to an mdbook.

Hi @feral-dot-io!

Yeah! Im planning to bring up a repro repository! I will let you know when ready!