sim_lib_view_math/
plot.rs1use sim_kernel::{Expr, Symbol};
7use sim_lib_scene::{data_map, node, sym};
8
9use crate::num::{number, point};
10
11pub const PLOT_LENS: &str = "view:math-plot";
13
14pub fn series(name: &str, points: &[(f64, f64)]) -> Expr {
16 data_map(vec![
17 ("name", Expr::Symbol(Symbol::new(name))),
18 (
19 "points",
20 Expr::List(points.iter().map(|(x, y)| point(*x, *y)).collect()),
21 ),
22 ])
23}
24
25pub fn plot_view(name: &str, points: &[(f64, f64)]) -> Expr {
27 multi_plot_view(&[(name.to_owned(), points.to_vec())])
28}
29
30pub fn multi_plot_view(series_list: &[(String, Vec<(f64, f64)>)]) -> Expr {
32 let bounds = bounds_of(series_list);
33 let series = series_list
34 .iter()
35 .map(|(name, points)| {
36 data_map(vec![
39 ("name", Expr::Symbol(Symbol::new(name.as_str()))),
40 ("style", sym("line")),
41 (
42 "points",
43 Expr::List(points.iter().map(|(x, y)| point(*x, *y)).collect()),
44 ),
45 ])
46 })
47 .collect();
48 node(
49 "plot",
50 vec![
51 (
52 "axes",
53 data_map(vec![
54 ("x", axis(bounds.0, bounds.1)),
55 ("y", axis(bounds.2, bounds.3)),
56 ]),
57 ),
58 ("series", Expr::List(series)),
59 ],
60 )
61}
62
63pub fn response_plot_view(
65 lens: &str,
66 role: &str,
67 series_list: &[(String, Vec<(f64, f64)>)],
68) -> Expr {
69 let mut plot = multi_plot_view(series_list);
70 if let Expr::Map(entries) = &mut plot {
71 entries.push((sym("lens"), Expr::Symbol(Symbol::new(lens))));
72 entries.push((sym("role"), sym(role)));
73 }
74 plot
75}
76
77fn axis(min: f64, max: f64) -> Expr {
78 data_map(vec![("min", number(min)), ("max", number(max))])
79}
80
81fn bounds_of(series_list: &[(String, Vec<(f64, f64)>)]) -> (f64, f64, f64, f64) {
82 let mut bounds: Option<(f64, f64, f64, f64)> = None;
83 for (_, points) in series_list {
84 for (x, y) in points {
85 bounds = Some(match bounds {
86 Some((min_x, max_x, min_y, max_y)) => {
87 (min_x.min(*x), max_x.max(*x), min_y.min(*y), max_y.max(*y))
88 }
89 None => (*x, *x, *y, *y),
90 });
91 }
92 }
93 bounds.unwrap_or((0.0, 1.0, 0.0, 1.0))
94}