GnuplotEx.LiveView.Streaming (gnuplot_ex v0.5.0)
Streaming helpers for real-time plot updates in LiveView.
Provides utilities for:
- Non-blocking async rendering with
prepare_async/3 - Debounced plot streams with
new_stream/2andpush_stream/3 - Rate-limited updates
Async Rendering
For plots that take time to render, use async rendering to avoid blocking the socket:
def mount(_params, _session, socket) do
socket =
socket
|> assign(:plot, build_plot())
|> prepare_async(:plot, :plot_result)
{:ok, socket}
end
def render(assigns) do
~H"""
<.live_gnuplot_async result={@plot_result}>
<:loading><.spinner /></:loading>
</.live_gnuplot_async>
"""
endDebounced Streams
For high-frequency updates (e.g., sensor data), use debounced streams to limit render frequency:
def mount(_params, _session, socket) do
socket =
socket
|> new_stream(:sensor_plots, debounce: 100)
{:ok, socket}
end
def handle_info({:sensor_data, data}, socket) do
plot = GnuplotEx.scatter(data)
{:noreply, push_stream(socket, :sensor_plots, "sensor-1", plot)}
end
Summary
Functions
Render a plot and broadcast to channel subscribers.
Handle the debounce timer message.
Create a new debounced stream for plot updates.
Prepare an async rendering task for a plot.
Push a plot update to a stream with debouncing.
Functions
@spec broadcast_plot(String.t(), String.t(), GnuplotEx.Plot.t(), atom(), keyword()) :: :ok | {:error, term()}
Render a plot and broadcast to channel subscribers.
Combines rendering with channel broadcasting for real-time updates.
Example
# In a GenServer or process monitoring data:
def handle_info({:data, data}, state) do
plot = GnuplotEx.scatter(data)
:ok = broadcast_plot("dashboard", "sensor-1", plot, :svg)
{:noreply, state}
end
@spec handle_debounce(Phoenix.LiveView.Socket.t(), atom(), String.t()) :: Phoenix.LiveView.Socket.t()
Handle the debounce timer message.
Add this to your handle_info/2:
def handle_info({:gnuplot_debounce, stream_name, plot_id}, socket) do
{:noreply, GnuplotEx.LiveView.Streaming.handle_debounce(socket, stream_name, plot_id)}
end
@spec new_stream(Phoenix.LiveView.Socket.t(), atom(), keyword()) :: Phoenix.LiveView.Socket.t()
Create a new debounced stream for plot updates.
Streams batch rapid updates to reduce render frequency while keeping the UI responsive.
Options
:debounce- Minimum ms between updates (default:50):format- Output format (default::svg)
Example
socket
|> new_stream(:charts, debounce: 100)
@spec prepare_async(Phoenix.LiveView.Socket.t(), atom(), atom(), keyword()) :: Phoenix.LiveView.Socket.t()
Prepare an async rendering task for a plot.
This sets up a LiveView async assign that renders the plot in a background task, allowing the socket to continue processing.
Parameters
socket- The LiveView socketplot_key- The key where the plot is stored in assignsresult_key- The key to store the async resultopts- Options
Options
:format- Output format (default::svg):width- Plot width (default:800):height- Plot height (default:600)
Example
socket
|> assign(:plot, my_plot)
|> prepare_async(:plot, :plot_result)
@spec push_stream(Phoenix.LiveView.Socket.t(), atom(), String.t(), GnuplotEx.Plot.t()) :: Phoenix.LiveView.Socket.t()
Push a plot update to a stream with debouncing.
If updates arrive faster than the debounce interval, only the latest plot will be rendered. This prevents overwhelming the renderer during rapid data updates.
Example
# In handle_info
def handle_info({:data, data}, socket) do
plot = GnuplotEx.scatter(data)
{:noreply, push_stream(socket, :charts, "my-chart", plot)}
end