pub fn run_liveplot(
rx: Receiver<PlotCommand>,
cfg: LivePlotConfig,
) -> Result<()>Expand description
Launch the LivePlot application in a native window.
This is the main entry point for standalone use. It:
- Constructs a
LivePlotAppwith the given command channel and any controllers extracted fromcfg. - Applies the configuration (axis units, hotkeys, responsive thresholds, …).
- Opens a native window and enters the eframe event loop.
The call blocks until the window is closed.
Examples found in repository?
examples/sine.rs (line 42)
16fn main() -> eframe::Result<()> {
17 // Create multi-trace plot channel (we use a single trace labeled "signal")
18 let (sink, rx) = channel_plot();
19 let trace = sink.create_trace("signal", Some("Test Sine"));
20
21 // Producer: 1 kHz sample rate, 3 Hz sine
22 std::thread::spawn(move || {
23 const FS_HZ: f64 = 1000.0; // 1 kHz sampling rate
24 const F_HZ: f64 = 3.0; // 3 Hz sine wave
25 let dt = Duration::from_millis(1);
26 let mut n: u64 = 0;
27 loop {
28 let t = n as f64 / FS_HZ;
29 let val = (2.0 * std::f64::consts::PI * F_HZ * t).sin();
30 let t_s = SystemTime::now()
31 .duration_since(UNIX_EPOCH)
32 .map(|d| d.as_secs_f64())
33 .unwrap_or(0.0);
34 // Ignore error if the UI closed (receiver dropped)
35 let _ = sink.send_point(&trace, PlotPoint { x: t_s, y: val });
36 n = n.wrapping_add(1);
37 std::thread::sleep(dt);
38 }
39 });
40
41 // Run the UI until closed
42 run_liveplot(rx, LivePlotConfig::default())
43}More examples
examples/fixed_data.rs (line 69)
41fn main() -> eframe::Result<()> {
42 // Create the plot channel: we will create traces and push their data via `PlotSink`.
43 let (sink, rx) = channel_plot();
44
45 // Prepare fixed waves and convert to PlotPoint vectors
46 let (sine_v, cosine_v) = make_fixed_waves();
47 let sine_points: Vec<PlotPoint> = sine_v
48 .into_iter()
49 .map(|p| PlotPoint { x: p[0], y: p[1] })
50 .collect();
51 let cosine_points: Vec<PlotPoint> = cosine_v
52 .into_iter()
53 .map(|p| PlotPoint { x: p[0], y: p[1] })
54 .collect();
55
56 // Register traces and set full data via sink
57 let sine_t = sink.create_trace("sine", Some("Sine"));
58 let cos_t = sink.create_trace("cosine", Some("Cosine"));
59 let _ = sink.set_data(&sine_t, sine_points);
60 let _ = sink.set_data(&cos_t, cosine_points);
61
62 // Build configuration via LivePlotConfig instead of mutating the internal app fields
63 let mut cfg = LivePlotConfig::default();
64 cfg.time_window_secs = 10.0;
65 cfg.max_points = 10_000;
66 cfg.features.legend = true;
67
68 // Show the UI using the channel receiver and the config
69 run_liveplot(rx, cfg)
70}examples/sine_cosine.rs (line 45)
16fn main() -> eframe::Result<()> {
17 // Create multi-trace plot channel
18 let (sink, rx) = channel_plot();
19 let tr_sine = sink.create_trace("sine", None);
20 let tr_cos = sink.create_trace("cosine", None);
21
22 // Producer: 1 kHz sample rate, 3 Hz sine and cosine
23 std::thread::spawn(move || {
24 const FS_HZ: f64 = 1000.0; // 1 kHz sampling rate
25 const F_HZ: f64 = 3.0; // 3 Hz
26 let dt = Duration::from_millis(1);
27 let mut n: u64 = 0;
28 loop {
29 let t = n as f64 / FS_HZ;
30 let s_val = (2.0 * std::f64::consts::PI * F_HZ * t).sin();
31 let c_val = (2.0 * std::f64::consts::PI * F_HZ * t).cos();
32 let t_s = SystemTime::now()
33 .duration_since(UNIX_EPOCH)
34 .map(|d| d.as_secs_f64())
35 .unwrap_or(0.0);
36 // Ignore error if the UI closed (receiver dropped)
37 let _ = sink.send_point(&tr_sine, PlotPoint { x: t_s, y: s_val });
38 let _ = sink.send_point(&tr_cos, PlotPoint { x: t_s, y: c_val });
39 n = n.wrapping_add(1);
40 std::thread::sleep(dt);
41 }
42 });
43
44 // Run the UI until closed (default: FFT hidden). Uses the unified multi-trace engine.
45 run_liveplot(rx, LivePlotConfig::default())
46}examples/set_toggle.rs (line 75)
33fn main() {
34 // channel for PlotCommand messages
35 let (tx, rx) = mpsc::channel::<PlotCommand>();
36
37 // Producer thread: send commands while UI runs on the main thread
38 let producer = thread::spawn(move || {
39 // register trace id 1
40 let _ = tx.send(PlotCommand::RegisterTrace {
41 id: 1,
42 name: "toggle".into(),
43 info: Some("sine/cosine toggle".into()),
44 });
45
46 let _start = Instant::now();
47 let mut t0 = 0.0_f64;
48 // pre-generate one period of samples at 100 Hz
49 let n = 200usize;
50 let dt = 0.01_f64;
51 let mut is_sine = true;
52
53 loop {
54 // Build waveform and use SetData to overwrite the trace
55 let pts = make_wave(is_sine, t0, n, dt);
56 if mpsc::Sender::send(
57 &tx,
58 PlotCommand::SetData {
59 trace_id: 1,
60 points: pts,
61 },
62 )
63 .is_err()
64 {
65 break; // UI likely closed
66 }
67 // toggle every 2 seconds
68 thread::sleep(Duration::from_secs(2));
69 t0 += 2.0;
70 is_sine = !is_sine;
71 }
72 });
73
74 // Run UI on the main thread (required by winit/eframe)
75 if let Err(e) = run_liveplot(rx, LivePlotConfig::default()) {
76 eprintln!("UI error: {e}");
77 }
78
79 // Ensure producer exits
80 let _ = producer.join();
81}examples/events_simple.rs (line 62)
19fn main() -> eframe::Result<()> {
20 // Create the event controller and subscribe to click-related events.
21 let event_ctrl = EventController::new();
22 let rx = event_ctrl.subscribe(EventFilter::only(
23 EventKind::CLICK | EventKind::DOUBLE_CLICK,
24 ));
25
26 // Print received events on a background thread.
27 std::thread::spawn(move || {
28 while let Ok(evt) = rx.recv() {
29 println!("[event] kind={}", evt.kinds);
30 if let Some(click) = &evt.click {
31 if let Some(pp) = &click.plot_pos {
32 println!(" plot position: ({:.4}, {:.4})", pp.x, pp.y);
33 }
34 if let Some(sp) = &click.screen_pos {
35 println!(" screen position: ({:.1}, {:.1})", sp.x, sp.y);
36 }
37 }
38 }
39 println!("[event] channel closed");
40 });
41
42 // Set up a simple sine trace so there is something to click on.
43 let (sink, data_rx) = channel_plot();
44 let trace = sink.create_trace("sine", Some("Sine Wave"));
45
46 std::thread::spawn(move || {
47 let dt = Duration::from_millis(1);
48 loop {
49 let t_s = SystemTime::now()
50 .duration_since(UNIX_EPOCH)
51 .map(|d| d.as_secs_f64())
52 .unwrap_or(0.0);
53 let val = (2.0 * std::f64::consts::PI * 2.0 * t_s).sin();
54 let _ = sink.send_point(&trace, PlotPoint { x: t_s, y: val });
55 std::thread::sleep(dt);
56 }
57 });
58
59 let mut cfg = LivePlotConfig::default();
60 cfg.controllers.event = Some(event_ctrl);
61
62 run_liveplot(data_rx, cfg)
63}examples/thresholds_sine.rs (line 75)
20fn main() -> eframe::Result<()> {
21 let (sink, rx) = channel_plot();
22 let trace = sink.create_trace("signal", None);
23
24 // Producer: 1 kHz sample rate, 3 Hz sine
25 std::thread::spawn(move || {
26 const FS_HZ: f64 = 1000.0; // 1 kHz sampling rate
27 const F_HZ: f64 = 3.0; // 3 Hz sine wave
28 let dt = Duration::from_millis(1);
29 let mut n: u64 = 0;
30 loop {
31 let t = n as f64 / FS_HZ;
32 let val = (2.0 * std::f64::consts::PI * F_HZ * t).sin();
33 let t_s = SystemTime::now()
34 .duration_since(UNIX_EPOCH)
35 .map(|d| d.as_secs_f64())
36 .unwrap_or(0.0);
37 let _ = sink.send_point(&trace, PlotPoint { x: t_s, y: val });
38 n = n.wrapping_add(1);
39 std::thread::sleep(dt);
40 }
41 });
42
43 // Build a threshold controller and pre-configure a "> 0.8" threshold on "signal".
44 let thr_ctrl = ThresholdController::new();
45 {
46 // Subscribe to events and print them
47 let rx_evt = thr_ctrl.subscribe();
48 std::thread::spawn(move || {
49 while let Ok(evt) = rx_evt.recv() {
50 eprintln!(
51 "[threshold] {}: {} from {:.3}s for {:.3} ms, area={:.4}",
52 evt.threshold,
53 evt.trace,
54 evt.start_t,
55 evt.duration * 1000.0,
56 evt.area
57 );
58 }
59 });
60 }
61 thr_ctrl.request_add_threshold(ThresholdDef {
62 name: "gt_0_8".into(),
63 target: TraceRef("signal".into()),
64 kind: ThresholdKind::GreaterThan { value: 0.8 },
65 min_duration_s: 0.002,
66 max_events: 100,
67 ..Default::default()
68 });
69
70 // Run the UI with the controller attached via config
71 let mut cfg = LivePlotConfig::default();
72 cfg.title = "LivePlot (thresholds)".into();
73 cfg.native_options = Some(eframe::NativeOptions::default());
74 cfg.controllers.threshold = Some(thr_ctrl);
75 run_liveplot(rx, cfg)
76}