1use super::{
4 Plot, PlotDataLayout, PlotDataOffset, PlotDataStride, PlotError, PlotItemStyle,
5 plot_spec_with_style, validate_data_lengths, with_plot_str_or_empty,
6};
7use crate::{ItemFlags, ShadedFlags, sys};
8
9pub struct ShadedPlot<'a> {
11 label: &'a str,
12 x_data: &'a [f64],
13 y_data: &'a [f64],
14 style: PlotItemStyle,
15 y_ref: f64,
16 flags: ShadedFlags,
17 item_flags: ItemFlags,
18 layout: PlotDataLayout,
19}
20
21impl<'a> super::PlotItemStyled for ShadedPlot<'a> {
22 fn style_mut(&mut self) -> &mut PlotItemStyle {
23 &mut self.style
24 }
25}
26
27impl<'a> ShadedPlot<'a> {
28 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
30 Self {
31 label,
32 x_data,
33 y_data,
34 style: PlotItemStyle::default(),
35 y_ref: 0.0, flags: ShadedFlags::NONE,
37 item_flags: ItemFlags::NONE,
38 layout: PlotDataLayout::DEFAULT,
39 }
40 }
41
42 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
45 self.y_ref = y_ref;
46 self
47 }
48
49 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
51 self.flags = flags;
52 self
53 }
54
55 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
57 self.item_flags = flags;
58 self
59 }
60
61 pub fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
63 self.layout = layout;
64 self
65 }
66
67 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
69 self.layout = self.layout.with_offset(offset);
70 self
71 }
72
73 pub fn with_stride(mut self, stride: PlotDataStride) -> Self {
75 self.layout = self.layout.with_stride(stride);
76 self
77 }
78
79 pub fn validate(&self) -> Result<(), PlotError> {
81 validate_data_lengths(self.x_data, self.y_data)
82 }
83}
84
85impl<'a> Plot for ShadedPlot<'a> {
86 fn plot(&self) {
87 if self.validate().is_err() {
88 return;
89 }
90 let Ok(count) = i32::try_from(self.x_data.len()) else {
91 return;
92 };
93 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
94 let spec = plot_spec_with_style(
95 self.style,
96 self.flags.bits() | self.item_flags.bits(),
97 self.layout,
98 );
99 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
100 label_ptr,
101 self.x_data.as_ptr(),
102 self.y_data.as_ptr(),
103 count,
104 self.y_ref,
105 spec,
106 );
107 })
108 }
109
110 fn label(&self) -> &str {
111 self.label
112 }
113}
114
115pub struct ShadedBetweenPlot<'a> {
117 label: &'a str,
118 x_data: &'a [f64],
119 y1_data: &'a [f64],
120 y2_data: &'a [f64],
121 style: PlotItemStyle,
122 flags: ShadedFlags,
123 item_flags: ItemFlags,
124 layout: PlotDataLayout,
125}
126
127impl<'a> super::PlotItemStyled for ShadedBetweenPlot<'a> {
128 fn style_mut(&mut self) -> &mut PlotItemStyle {
129 &mut self.style
130 }
131}
132
133impl<'a> ShadedBetweenPlot<'a> {
134 pub fn new(label: &'a str, x_data: &'a [f64], y1_data: &'a [f64], y2_data: &'a [f64]) -> Self {
136 Self {
137 label,
138 x_data,
139 y1_data,
140 y2_data,
141 style: PlotItemStyle::default(),
142 flags: ShadedFlags::NONE,
143 item_flags: ItemFlags::NONE,
144 layout: PlotDataLayout::DEFAULT,
145 }
146 }
147
148 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
150 self.flags = flags;
151 self
152 }
153
154 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
156 self.item_flags = flags;
157 self
158 }
159
160 pub fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
162 self.layout = layout;
163 self
164 }
165
166 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
168 self.layout = self.layout.with_offset(offset);
169 self
170 }
171
172 pub fn with_stride(mut self, stride: PlotDataStride) -> Self {
174 self.layout = self.layout.with_stride(stride);
175 self
176 }
177
178 pub fn validate(&self) -> Result<(), PlotError> {
180 validate_data_lengths(self.x_data, self.y1_data)?;
181 validate_data_lengths(self.x_data, self.y2_data)?;
182 Ok(())
183 }
184}
185
186impl<'a> Plot for ShadedBetweenPlot<'a> {
187 fn plot(&self) {
188 if self.validate().is_err() {
189 return;
190 }
191 let Ok(count) = i32::try_from(self.x_data.len()) else {
192 return;
193 };
194
195 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
196 let spec = plot_spec_with_style(
197 self.style,
198 self.flags.bits() | self.item_flags.bits(),
199 self.layout,
200 );
201 sys::ImPlot_PlotShaded_doublePtrdoublePtrdoublePtr(
202 label_ptr,
203 self.x_data.as_ptr(),
204 self.y1_data.as_ptr(),
205 self.y2_data.as_ptr(),
206 count,
207 spec,
208 );
209 })
210 }
211
212 fn label(&self) -> &str {
213 self.label
214 }
215}
216
217pub struct SimpleShadedPlot<'a> {
219 label: &'a str,
220 values: &'a [f64],
221 style: PlotItemStyle,
222 y_ref: f64,
223 flags: ShadedFlags,
224 item_flags: ItemFlags,
225 x_scale: f64,
226 x_start: f64,
227}
228
229impl<'a> super::PlotItemStyled for SimpleShadedPlot<'a> {
230 fn style_mut(&mut self) -> &mut PlotItemStyle {
231 &mut self.style
232 }
233}
234
235impl<'a> SimpleShadedPlot<'a> {
236 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
238 Self {
239 label,
240 values,
241 style: PlotItemStyle::default(),
242 y_ref: 0.0,
243 flags: ShadedFlags::NONE,
244 item_flags: ItemFlags::NONE,
245 x_scale: 1.0,
246 x_start: 0.0,
247 }
248 }
249
250 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
252 self.y_ref = y_ref;
253 self
254 }
255
256 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
258 self.flags = flags;
259 self
260 }
261
262 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
264 self.item_flags = flags;
265 self
266 }
267
268 pub fn with_x_scale(mut self, scale: f64) -> Self {
270 self.x_scale = scale;
271 self
272 }
273
274 pub fn with_x_start(mut self, start: f64) -> Self {
276 self.x_start = start;
277 self
278 }
279}
280
281impl<'a> Plot for SimpleShadedPlot<'a> {
282 fn plot(&self) {
283 if self.values.is_empty() {
284 return;
285 }
286 let Ok(count) = i32::try_from(self.values.len()) else {
287 return;
288 };
289
290 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
291 let spec = plot_spec_with_style(
292 self.style,
293 self.flags.bits() | self.item_flags.bits(),
294 PlotDataLayout::DEFAULT,
295 );
296 sys::ImPlot_PlotShaded_doublePtrInt(
297 label_ptr,
298 self.values.as_ptr(),
299 count,
300 self.y_ref,
301 self.x_scale,
302 self.x_start,
303 spec,
304 );
305 })
306 }
307
308 fn label(&self) -> &str {
309 self.label
310 }
311}
312
313impl<'ui> crate::PlotUi<'ui> {
315 pub fn shaded_plot(
317 &self,
318 label: &str,
319 x_data: &[f64],
320 y_data: &[f64],
321 ) -> Result<(), PlotError> {
322 let plot = ShadedPlot::new(label, x_data, y_data);
323 plot.validate()?;
324 self.bind();
325 plot.plot();
326 Ok(())
327 }
328
329 pub fn shaded_plot_with_ref(
331 &self,
332 label: &str,
333 x_data: &[f64],
334 y_data: &[f64],
335 y_ref: f64,
336 ) -> Result<(), PlotError> {
337 let plot = ShadedPlot::new(label, x_data, y_data).with_y_ref(y_ref);
338 plot.validate()?;
339 self.bind();
340 plot.plot();
341 Ok(())
342 }
343
344 pub fn shaded_between_plot(
346 &self,
347 label: &str,
348 x_data: &[f64],
349 y1_data: &[f64],
350 y2_data: &[f64],
351 ) -> Result<(), PlotError> {
352 let plot = ShadedBetweenPlot::new(label, x_data, y1_data, y2_data);
353 plot.validate()?;
354 self.bind();
355 plot.plot();
356 Ok(())
357 }
358
359 pub fn simple_shaded_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
361 if values.is_empty() {
362 return Err(PlotError::EmptyData);
363 }
364 let plot = SimpleShadedPlot::new(label, values);
365 self.bind();
366 plot.plot();
367 Ok(())
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374
375 #[test]
376 fn test_shaded_plot_creation() {
377 let x_data = [1.0, 2.0, 3.0, 4.0];
378 let y_data = [1.0, 4.0, 2.0, 3.0];
379
380 let plot = ShadedPlot::new("test", &x_data, &y_data);
381 assert_eq!(plot.label(), "test");
382 assert!(plot.validate().is_ok());
383 }
384
385 #[test]
386 fn test_shaded_plot_validation() {
387 let x_data = [1.0, 2.0, 3.0];
388 let y_data = [1.0, 4.0]; let plot = ShadedPlot::new("test", &x_data, &y_data);
391 assert!(plot.validate().is_err());
392 }
393
394 #[test]
395 fn test_shaded_between_plot() {
396 let x_data = [1.0, 2.0, 3.0, 4.0];
397 let y1_data = [1.0, 2.0, 3.0, 4.0];
398 let y2_data = [2.0, 3.0, 4.0, 5.0];
399
400 let plot = ShadedBetweenPlot::new("test", &x_data, &y1_data, &y2_data);
401 assert_eq!(plot.label(), "test");
402 assert!(plot.validate().is_ok());
403 }
404
405 #[test]
406 fn test_simple_shaded_plot_flags() {
407 let values = [1.0, 2.0, 3.0, 4.0];
408 let plot = SimpleShadedPlot::new("test", &values).with_item_flags(ItemFlags::NO_FIT);
409 assert_eq!(plot.label(), "test");
410 assert_eq!(plot.item_flags, ItemFlags::NO_FIT);
411 }
412}