GnuplotEx.Channel (gnuplot_ex v0.5.0)
Phoenix Channel for real-time plot streaming.
Enables pushing rendered plots to connected clients via WebSocket. Includes built-in rate limiting for backpressure control.
Setup
Add the channel to your socket:
defmodule MyAppWeb.UserSocket do use Phoenix.Socket
channel "gnuplot:*", GnuplotEx.Channel
# ... socket implementation end
Start the RateLimiter in your supervision tree (or let GnuplotEx.Application do it):
children = [ GnuplotEx.Channel.RateLimiter ]
Client Messages
"render"- Request a plot render:{plot_id, plot_spec, format}"subscribe"- Subscribe to plot updates:{plot_ids: [...]}"unsubscribe"- Unsubscribe from updates:{plot_ids: [...]}
Server Messages
"plot:update"- Pushed plot update{plot_id, format, data, timestamp}"plot:rendered"- Response to render request{plot_id, format, data, render_time_ms}"plot:error"- Render error{plot_id, reason, message}"plot:rate_limited"- Backpressure signal{plot_id, retry_after_ms}
Example: Server-side streaming
# Push a pre-rendered plot to all subscribers
GnuplotEx.Channel.push_plot("dashboard", "sensor-1", svg_data, :svg)
# Render and stream a plot
plot = GnuplotEx.scatter(data) |> GnuplotEx.title("Live Data")
GnuplotEx.Channel.stream_plot("dashboard", "cpu-usage", plot, :svg)Example: Client-side (JavaScript)
let channel = socket.channel("gnuplot:dashboard", {})
channel.on("plot:update", ({plot_id, data, format}) => {
document.getElementById(plot_id).innerHTML = data
})
channel.join()
// Request a specific render
channel.push("render", {plot_id: "chart1", format: "svg"})
Summary
Functions
Handle render request from client.
Join a gnuplot topic.
Push a pre-rendered plot to all subscribers on a topic.
Stream multiple plots in parallel.
Render a plot and stream it to subscribers.
Functions
Handle render request from client.
Expects: %{"plot_id" => id, "format" => fmt, "spec" => plot_spec}
The plot_spec should be a serializable representation of the plot. For security, this only supports pre-registered plot builders.
Join a gnuplot topic.
Topics follow the pattern gnuplot:<namespace> where namespace
can be any string identifier (e.g., "dashboard", "user:123").
Push a pre-rendered plot to all subscribers on a topic.
This is the most efficient way to stream plots when you've already rendered the output.
Parameters
topic- The gnuplot topic (e.g., "dashboard")plot_id- Unique identifier for this plotdata- The rendered plot data (SVG string, PNG binary, etc.)format- The format atom (:svg, :png, etc.)
Example
svg = GnuplotEx.render(plot, :svg)
GnuplotEx.Channel.push_plot("dashboard", "sensor-1", svg, :svg)
@spec stream_many(String.t(), [{String.t(), GnuplotEx.Plot.t()}], atom(), keyword()) :: :ok
Stream multiple plots in parallel.
Renders all plots concurrently and pushes each as it completes.
Example
plots = [
{"cpu", cpu_plot},
{"memory", mem_plot},
{"disk", disk_plot}
]
GnuplotEx.Channel.stream_many("dashboard", plots, :svg)
@spec stream_plot(String.t(), String.t(), GnuplotEx.Plot.t(), atom(), keyword()) :: :ok | {:error, term()}
Render a plot and stream it to subscribers.
Combines rendering and pushing in one call. Uses async rendering to avoid blocking the caller.
Parameters
topic- The gnuplot topicplot_id- Unique identifier for this plotplot- AGnuplotEx.Plotstructformat- Output format (:svg, :png, etc.)opts- Render options
Options
:timeout- Render timeout in ms (default: 30_000)- All other options passed to
GnuplotEx.render/3
Example
plot = GnuplotEx.scatter(sensor_data) |> GnuplotEx.title("Live Sensors")
GnuplotEx.Channel.stream_plot("dashboard", "sensors", plot, :svg)