I want to create a toy project that shows a chart of temperature over time and updates every 5 seconds. I feel LiveView is perfect for that use case because there will always be only one piece of data appended on the right side of the chart, and one piece of data deleted on the left.
However, most JS libraries I tried don’t do it this way. They need to take all data and call chart.update rerendering the entire chart. I also need to bypass LiveView with a channel to call that update function.
I wondered if you know any solutions that could use the power of LiveView in full
Maybe you had experience with charts using SVG?
Or had a chart with only HTML divs and CSS?
<div data-chart="<%= Jason.encode(@data) %>" phx-update="ignore" phx-hook="MyChart">
<%# mount js chart inside here %>
</div>
The js hook will be called each time when data-chart is updated and phx-update="ignore" does not prevent the attribute from being updates, but probably only it’s children. So you can use the update callback of the js hook to update the chart with new data.
I’d strongly recommend to stick to svg for graphics. I’ve done some experiments with svgs in liveviews and it works quite well if you know how to handle svg. Only downside is that charts most often aren’t just the svg part, but also quite a lot of interaction like labels, tooltips and such things, which are imho not really a good fit for being handled by liveview, so a proper charting library might still be a good idea.
If you still want to go the route of creating the svg/interaction manually: I’ve tried out the technique of the start of this post with svelte.js – which works kinda similar to liveview, but on the client side. It allows you to add pure client side interactions, while still easily being able to receive updates to data from the liveview. There are some good examples for building charts with the low level pieces of d3 on the svelte website, but it can also do custom svg content.
Finally, if you are happy to homebrew SVG you could take a look at some D3.js samples - I’ve been porting bits and pieces of the scale and axis libraries over to elixir (not too embarrassing but not ready to release yet). If you want to get really deep, search for papers by Hadley Wickham, author of ggplot (an R library providing a nice abstraction for translating data into graphics). I’m trying to build a “charting” library in elixir with ggplot type concepts, learning SVG and layout tricks from D3 (as R code is mighty hard to read with my level of knowledge). It’s happening in fits and starts due to many other commitments. If it ever gets to a reasonable state I’ll let you know - I started on it because I think backend rendered real-time dashboards would be awesome!
Just found chartkick-ex (hex.pm). Have anybody of you tried it with LiveView? I’m thinking to rewrite our client side to LiveView where we have a plenty charts (all realtime measured data)…
Putting out SVG is pretty much what my PlotEx library linked above does. Apply a few css rules and you can style it however it suits you. Using it with LiveView readily enables live updating! Just plug it in and go.
I’m using a 1 second :tick timer in my LiveView which just takes a new data stream and puts it in an assigns. It’s pretty decent speed for having essentially no optimizations. It runs fine on a raspberry pi embedded, but I haven’t checked the per-user memory usage but I suspect it’s competitive with a JS solution as it doesn’t have to serialize the data and have JS regenerate everything.
I’d like to have time to expand on the api and add more graph types. Elixir Streams make it trivial to say take time series data over days and only show every X’th item. Still if anyone is interested I’d love feedback on how to clean up the API or support more graph types. See the SVG Output module.
I have one getting close - missing doco, decent colour palette handling and hex project packaging, but has scatter plot, bar charts (stacked & grouped), basic Gantt chart and reasonable primitives for building new plot types. Not as strong as @elcritch’s PlotEx in terms of performance and liveview bindings (works well in liveview, but less efficient rendering).
It also has a basic event model on the bar chart so you can click on bars and figure out in liveview what’s been clicked.
If anyone is keen to take an early look, I can make time over the next 24hrs to break it out into a new, public github repo.
Edit: @elcritch - more than happy to collaborate on this.
@redrapids – I consider this library stable for live stream plot updating, but it lacks a lot of basic plotting niceties you’d find in a full featured library. Still it works well for it’s intended use case of quickly including live updating graphs for small volume dashboards, especially on embedded devices. My belief is that LiveView will be a goto for making small bespoke dashboard for internal company uses and/or embedded devices. I’m keeping it updated with LiveView as well. I am not aware of anyone else actually using it however.
@mindok – that sounds great! ExPlot is certainly “I have one problem to solve, here it is”. It leaves color palettes and similar up to the user via CSS.
I’d be up for collaborating, though my time is pretty limited to produce much code currently. I’d be interested in checking out your beta. Are you on the Elixir slack channel for DM’ing (I’m @elcritch on both slack and github)? Not sure how you’re handling your data scaling, but PlotEx is broken up into two pieces so in theory you could use the data-processing part for scaling scatter plot / line chart data and build SVG (or even Canvas) portions on top. I tried to pay attention to the use of Streams and striding to ensure that memory usage doesn’t explode. There’s also a fair bit of detail in handling datetime and numeric axis generation in a pleasing manner but that’s all in the “base” api not presentation / SVG side.
I am on slack, but very intermittently - I deliberately haven’t set it up on my main dev laptop. I hear you on the axes / scaling - I read a lot of D3 code - between D3 & ggplot the approach is to make it as nice-looking as possible with minimal effort for the user.
I haven’t paid that much attention to memory usage (other than) so it would be good to hear your approach.
Here’s a couple of screenshots to give you an idea
Sorry to revive an old thread, but I think this may be useful for others. I was looking at doing charts in LiveView this past week. I really wanted charts to be rendered with JS rather than SVG, due to the interactive element.
I found the Chartkick library, but it didn’t work with LiveView (at least for me) due to how it expects script tags to run. I was able to pretty quickly modify chartkick.ex to work with LiveView though.
I was unsure how to get rid of the raw requirement with Chartkick.ex, but tbh I didn’t spend more than a few minutes thinking about that.
These charts will update if the data source updates, but does so by destroying and re-allocating the chart. That probably isn’t the most efficient thing, but my use case is static 30-day charts.
Hey, did you ever finish porting/releasing this? As a fan of D3.js it would be a very helpful lib to have in Elixir! And it would save me from having to do some annoying mathematical calculations (this is the real reason I’m asking )