1use super::{Plot, PlotError, plot_spec_from, validate_data_lengths, with_plot_str_or_empty};
4use crate::{ErrorBarsFlags, ItemFlags, sys};
5
6pub struct ErrorBarsPlot<'a> {
8 label: &'a str,
9 x_data: &'a [f64],
10 y_data: &'a [f64],
11 err_data: &'a [f64],
12 flags: ErrorBarsFlags,
13 item_flags: ItemFlags,
14 offset: i32,
15 stride: i32,
16}
17
18impl<'a> ErrorBarsPlot<'a> {
19 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64], err_data: &'a [f64]) -> Self {
27 Self {
28 label,
29 x_data,
30 y_data,
31 err_data,
32 flags: ErrorBarsFlags::NONE,
33 item_flags: ItemFlags::NONE,
34 offset: 0,
35 stride: std::mem::size_of::<f64>() as i32,
36 }
37 }
38
39 pub fn with_flags(mut self, flags: ErrorBarsFlags) -> Self {
41 self.flags = flags;
42 self
43 }
44
45 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
47 self.item_flags = flags;
48 self
49 }
50
51 pub fn with_offset(mut self, offset: i32) -> Self {
53 self.offset = offset;
54 self
55 }
56
57 pub fn with_stride(mut self, stride: i32) -> Self {
59 self.stride = stride;
60 self
61 }
62
63 pub fn horizontal(self) -> Self {
65 self
68 }
69
70 pub fn validate(&self) -> Result<(), PlotError> {
72 validate_data_lengths(self.x_data, self.y_data)?;
73 validate_data_lengths(self.x_data, self.err_data)?;
74
75 if self.err_data.iter().any(|&err| err < 0.0) {
77 return Err(PlotError::InvalidData(
78 "Error values cannot be negative".to_string(),
79 ));
80 }
81
82 Ok(())
83 }
84}
85
86impl<'a> Plot for ErrorBarsPlot<'a> {
87 fn plot(&self) {
88 if self.validate().is_err() {
89 return;
90 }
91 let Ok(count) = i32::try_from(self.x_data.len()) else {
92 return;
93 };
94 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
95 let spec = plot_spec_from(
96 self.flags.bits() | self.item_flags.bits(),
97 self.offset,
98 self.stride,
99 );
100 sys::ImPlot_PlotErrorBars_doublePtrdoublePtrdoublePtrInt(
101 label_ptr,
102 self.x_data.as_ptr(),
103 self.y_data.as_ptr(),
104 self.err_data.as_ptr(),
105 count,
106 spec,
107 );
108 })
109 }
110
111 fn label(&self) -> &str {
112 self.label
113 }
114}
115
116pub struct AsymmetricErrorBarsPlot<'a> {
118 label: &'a str,
119 x_data: &'a [f64],
120 y_data: &'a [f64],
121 err_neg: &'a [f64],
122 err_pos: &'a [f64],
123 flags: ErrorBarsFlags,
124 item_flags: ItemFlags,
125}
126
127impl<'a> AsymmetricErrorBarsPlot<'a> {
128 pub fn new(
137 label: &'a str,
138 x_data: &'a [f64],
139 y_data: &'a [f64],
140 err_neg: &'a [f64],
141 err_pos: &'a [f64],
142 ) -> Self {
143 Self {
144 label,
145 x_data,
146 y_data,
147 err_neg,
148 err_pos,
149 flags: ErrorBarsFlags::NONE,
150 item_flags: ItemFlags::NONE,
151 }
152 }
153
154 pub fn with_flags(mut self, flags: ErrorBarsFlags) -> Self {
156 self.flags = flags;
157 self
158 }
159
160 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
162 self.item_flags = flags;
163 self
164 }
165
166 pub fn validate(&self) -> Result<(), PlotError> {
168 validate_data_lengths(self.x_data, self.y_data)?;
169 validate_data_lengths(self.x_data, self.err_neg)?;
170 validate_data_lengths(self.x_data, self.err_pos)?;
171
172 if self.err_neg.iter().any(|&err| err < 0.0) || self.err_pos.iter().any(|&err| err < 0.0) {
174 return Err(PlotError::InvalidData(
175 "Error values cannot be negative".to_string(),
176 ));
177 }
178
179 Ok(())
180 }
181}
182
183impl<'a> Plot for AsymmetricErrorBarsPlot<'a> {
184 fn plot(&self) {
185 if self.validate().is_err() {
186 return;
187 }
188 let Ok(count) = i32::try_from(self.x_data.len()) else {
189 return;
190 };
191 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
192 let spec = plot_spec_from(
193 self.flags.bits() | self.item_flags.bits(),
194 0,
195 std::mem::size_of::<f64>() as i32,
196 );
197 sys::ImPlot_PlotErrorBars_doublePtrdoublePtrdoublePtrdoublePtr(
198 label_ptr,
199 self.x_data.as_ptr(),
200 self.y_data.as_ptr(),
201 self.err_neg.as_ptr(),
202 self.err_pos.as_ptr(),
203 count,
204 spec,
205 );
206 })
207 }
208
209 fn label(&self) -> &str {
210 self.label
211 }
212}
213
214pub struct SimpleErrorBarsPlot<'a> {
216 label: &'a str,
217 values: &'a [f64],
218 errors: &'a [f64],
219 x_scale: f64,
220 x_start: f64,
221}
222
223impl<'a> SimpleErrorBarsPlot<'a> {
224 pub fn new(label: &'a str, values: &'a [f64], errors: &'a [f64]) -> Self {
226 Self {
227 label,
228 values,
229 errors,
230 x_scale: 1.0,
231 x_start: 0.0,
232 }
233 }
234
235 pub fn with_x_scale(mut self, scale: f64) -> Self {
237 self.x_scale = scale;
238 self
239 }
240
241 pub fn with_x_start(mut self, start: f64) -> Self {
243 self.x_start = start;
244 self
245 }
246
247 pub fn validate(&self) -> Result<(), PlotError> {
249 validate_data_lengths(self.values, self.errors)?;
250
251 if self.errors.iter().any(|&err| err < 0.0) {
252 return Err(PlotError::InvalidData(
253 "Error values cannot be negative".to_string(),
254 ));
255 }
256
257 Ok(())
258 }
259}
260
261impl<'a> Plot for SimpleErrorBarsPlot<'a> {
262 fn plot(&self) {
263 if self.validate().is_err() {
264 return;
265 }
266 let Ok(count) = i32::try_from(self.values.len()) else {
267 return;
268 };
269
270 let x_data: Vec<f64> = (0..self.values.len())
272 .map(|i| self.x_start + i as f64 * self.x_scale)
273 .collect();
274
275 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
276 let spec = plot_spec_from(0, 0, std::mem::size_of::<f64>() as i32);
277 sys::ImPlot_PlotErrorBars_doublePtrdoublePtrdoublePtrInt(
278 label_ptr,
279 x_data.as_ptr(),
280 self.values.as_ptr(),
281 self.errors.as_ptr(),
282 count,
283 spec,
284 );
285 })
286 }
287
288 fn label(&self) -> &str {
289 self.label
290 }
291}
292
293impl<'ui> crate::PlotUi<'ui> {
295 pub fn error_bars_plot(
297 &self,
298 label: &str,
299 x_data: &[f64],
300 y_data: &[f64],
301 err_data: &[f64],
302 ) -> Result<(), PlotError> {
303 let plot = ErrorBarsPlot::new(label, x_data, y_data, err_data);
304 plot.validate()?;
305 plot.plot();
306 Ok(())
307 }
308
309 pub fn asymmetric_error_bars_plot(
311 &self,
312 label: &str,
313 x_data: &[f64],
314 y_data: &[f64],
315 err_neg: &[f64],
316 err_pos: &[f64],
317 ) -> Result<(), PlotError> {
318 let plot = AsymmetricErrorBarsPlot::new(label, x_data, y_data, err_neg, err_pos);
319 plot.validate()?;
320 plot.plot();
321 Ok(())
322 }
323
324 pub fn simple_error_bars_plot(
326 &self,
327 label: &str,
328 values: &[f64],
329 errors: &[f64],
330 ) -> Result<(), PlotError> {
331 let plot = SimpleErrorBarsPlot::new(label, values, errors);
332 plot.validate()?;
333 plot.plot();
334 Ok(())
335 }
336}