1use crate::utils;
2use plotters::prelude::*;
3
4pub struct Bbox {
6 xmin: f64,
7 xmax: f64,
8 ymin: f64,
9 ymax: f64,
10}
11
12impl Bbox {
13 fn new(x: &[f64], y: &[f64]) -> Self {
14 let xmin: f64 = x.iter().cloned().fold(f64::NAN, |m, v| v.min(m));
15 let xmax: f64 = x.iter().cloned().fold(f64::NAN, |m, v| v.max(m));
16 let ymin: f64 = y.iter().cloned().fold(f64::NAN, |m, v| v.min(m));
17 let ymax: f64 = y.iter().cloned().fold(f64::NAN, |m, v| v.max(m));
18 Bbox {
19 xmin,
20 xmax,
21 ymin,
22 ymax,
23 }
24 }
25}
26
27pub fn xy(x: &[f64], y: &[f64], path: &str) -> Result<(), Box<dyn std::error::Error>> {
29 let bbox = Bbox::new(x, y);
30 let xy: Vec<(f64, f64)> = x.iter().cloned().zip(y.iter().cloned()).collect();
31 let root = BitMapBackend::new(path, (640, 480)).into_drawing_area();
32 root.fill(&WHITE)?;
33 root.margin(10, 10, 10, 10);
34 let mut chart = ChartBuilder::on(&root)
35 .x_label_area_size(40)
37 .y_label_area_size(60)
38 .build_cartesian_2d(bbox.xmin..bbox.xmax, bbox.ymin..bbox.ymax)?;
39 chart
40 .configure_mesh()
41 .y_label_formatter(&|x| format!("{:.2}", x))
44 .x_label_formatter(&|x| format!("{:.2}", x))
45 .draw()?;
48 chart.draw_series(xy.iter().map(|x| Circle::new((x.0, x.1), 2, BLUE.filled())))?;
49
50 Ok(())
51}
52
53pub fn comp_cdf(a: &[f64], b: &[f64], title: &str) -> Result<(), Box<dyn std::error::Error>> {
55 let a = utils::cdf(a);
56 let b = utils::cdf(b);
57 let mut ab = a.clone();
58 let mut c = b.clone();
59 ab.append(&mut c);
60
61 let ymin = ab.iter().map(|xi| xi.1).fold(0.0, f64::min);
62 let ymax = ab.iter().map(|xi| xi.1).fold(0.0, f64::max);
63 let xmin = ab.iter().map(|xi| xi.0).fold(0.0, f64::min);
64 let xmax = ab.iter().map(|xi| xi.0).fold(0.0, f64::max);
65 let root = BitMapBackend::new(title, (640, 480)).into_drawing_area();
66 root.fill(&WHITE)?;
67 root.margin(10, 10, 10, 10);
68 let mut chart = ChartBuilder::on(&root)
70 .x_label_area_size(40)
74 .y_label_area_size(60)
75 .build_cartesian_2d(xmin..xmax, ymin..ymax)?;
77
78 chart
80 .configure_mesh()
81 .x_labels(5)
83 .y_labels(5)
84 .y_label_formatter(&|x| format!("{:.2}", x))
86 .x_label_formatter(&|x| format!("{:.2}", x))
87 .x_desc("Value")
88 .y_desc("CDF")
89 .draw()?;
90
91 chart
93 .draw_series(LineSeries::new(a.clone(), &BLACK))?
94 .label("synthetic")
95 .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
96 chart.draw_series(PointSeries::of_element(a, 2, &BLUE, &|c, s, st| {
98 return EmptyElement::at(c) + Circle::new((0, 0), s, st.filled()); }))?;
102
103 chart
104 .draw_series(LineSeries::new(b.clone(), &BLACK))?
105 .label("observed")
106 .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &GREEN));
107 chart.draw_series(PointSeries::of_element(b, 2, &GREEN, &|c, s, st| {
108 return EmptyElement::at(c) + Circle::new((0, 0), s, st.filled()); }))?;
112 chart
113 .configure_series_labels()
114 .background_style(WHITE.filled())
115 .draw()?;
116 Ok(())
117}
118
119pub fn scatter(x: &[f64], y: &[f64], title: &str) -> Result<(), Box<dyn std::error::Error>> {
121 let xy: Vec<(f64, f64)> = x.iter().cloned().zip(y.iter().cloned()).collect();
122
123 let ymin = xy.iter().map(|xi| xi.1).fold(1.0, f64::min);
124 let ymax = xy.iter().map(|xi| xi.1).fold(0.0, f64::max);
125 let xmin = xy.iter().map(|xi| xi.0).fold(1.0, f64::min);
126 let xmax = xy.iter().map(|xi| xi.0).fold(0.0, f64::max);
127 let root = BitMapBackend::new(title, (640, 480)).into_drawing_area();
128 root.fill(&WHITE)?;
129 root.margin(10, 10, 10, 10);
130 let mut chart = ChartBuilder::on(&root)
131 .x_label_area_size(40)
132 .y_label_area_size(60)
133 .build_cartesian_2d(xmin..xmax, ymin..ymax)?;
134
135 chart
136 .configure_mesh()
137 .x_labels(5)
138 .y_labels(5)
139 .y_label_formatter(&|x| format!("{:.2}", x))
140 .x_label_formatter(&|x| format!("{:.2}", x))
141 .x_desc("Rate")
142 .y_desc("Fit")
143 .draw()?;
144 chart.draw_series(xy.iter().map(|x| Circle::new((x.0, x.1), 2, BLUE.filled())))?;
145
146 Ok(())
147}
148
149pub fn whisker_for_facies(
151 df: &plotters::data::Quartiles,
152 ff: &plotters::data::Quartiles,
153 fg: &plotters::data::Quartiles,
154 title: &str,
155) -> Result<(), Box<dyn std::error::Error>> {
156 let values_range = plotters::data::fitting_range(
157 df.values()
158 .iter()
159 .chain(ff.values().iter().chain(fg.values().iter())),
160 );
161
162 let facies_axis = ["debris flows", "fines", "gravels"];
163 let root = BitMapBackend::new(title, (640, 480)).into_drawing_area();
164 root.fill(&WHITE)?;
165 root.margin(10, 10, 10, 10);
166 let mut chart = ChartBuilder::on(&root)
168 .x_label_area_size(40)
172 .y_label_area_size(60)
173 .build_cartesian_2d(facies_axis[..].into_segmented(), values_range)?;
175
176 chart
178 .configure_mesh()
179 .y_labels(5)
181 .y_label_formatter(&|x| format!("{:.2}", x))
183 .x_desc("Facies")
184 .y_desc("Transit Time")
185 .draw()?;
186
187 chart.draw_series(vec![
190 Boxplot::new_vertical(SegmentValue::CenterOf(&"debris flows"), df),
191 Boxplot::new_vertical(SegmentValue::CenterOf(&"fines"), ff),
192 Boxplot::new_vertical(SegmentValue::CenterOf(&"gravels"), fg),
193 ])?;
194
195 chart
196 .configure_series_labels()
197 .background_style(WHITE.filled())
198 .draw()?;
199 Ok(())
200}