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, plot_ui: &crate::PlotUi<'_>) {
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 let _guard = plot_ui.bind();
94 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
95 let spec = plot_spec_with_style(
96 self.style,
97 self.flags.bits() | self.item_flags.bits(),
98 self.layout,
99 );
100 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
101 label_ptr,
102 self.x_data.as_ptr(),
103 self.y_data.as_ptr(),
104 count,
105 self.y_ref,
106 spec,
107 );
108 })
109 }
110
111 fn label(&self) -> &str {
112 self.label
113 }
114}
115
116pub struct ShadedBetweenPlot<'a> {
118 label: &'a str,
119 x_data: &'a [f64],
120 y1_data: &'a [f64],
121 y2_data: &'a [f64],
122 style: PlotItemStyle,
123 flags: ShadedFlags,
124 item_flags: ItemFlags,
125 layout: PlotDataLayout,
126}
127
128impl<'a> super::PlotItemStyled for ShadedBetweenPlot<'a> {
129 fn style_mut(&mut self) -> &mut PlotItemStyle {
130 &mut self.style
131 }
132}
133
134impl<'a> ShadedBetweenPlot<'a> {
135 pub fn new(label: &'a str, x_data: &'a [f64], y1_data: &'a [f64], y2_data: &'a [f64]) -> Self {
137 Self {
138 label,
139 x_data,
140 y1_data,
141 y2_data,
142 style: PlotItemStyle::default(),
143 flags: ShadedFlags::NONE,
144 item_flags: ItemFlags::NONE,
145 layout: PlotDataLayout::DEFAULT,
146 }
147 }
148
149 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
151 self.flags = flags;
152 self
153 }
154
155 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
157 self.item_flags = flags;
158 self
159 }
160
161 pub fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
163 self.layout = layout;
164 self
165 }
166
167 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
169 self.layout = self.layout.with_offset(offset);
170 self
171 }
172
173 pub fn with_stride(mut self, stride: PlotDataStride) -> Self {
175 self.layout = self.layout.with_stride(stride);
176 self
177 }
178
179 pub fn validate(&self) -> Result<(), PlotError> {
181 validate_data_lengths(self.x_data, self.y1_data)?;
182 validate_data_lengths(self.x_data, self.y2_data)?;
183 Ok(())
184 }
185}
186
187impl<'a> Plot for ShadedBetweenPlot<'a> {
188 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
189 if self.validate().is_err() {
190 return;
191 }
192 let Ok(count) = i32::try_from(self.x_data.len()) else {
193 return;
194 };
195
196 let _guard = plot_ui.bind();
197 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
198 let spec = plot_spec_with_style(
199 self.style,
200 self.flags.bits() | self.item_flags.bits(),
201 self.layout,
202 );
203 sys::ImPlot_PlotShaded_doublePtrdoublePtrdoublePtr(
204 label_ptr,
205 self.x_data.as_ptr(),
206 self.y1_data.as_ptr(),
207 self.y2_data.as_ptr(),
208 count,
209 spec,
210 );
211 })
212 }
213
214 fn label(&self) -> &str {
215 self.label
216 }
217}
218
219pub struct SimpleShadedPlot<'a> {
221 label: &'a str,
222 values: &'a [f64],
223 style: PlotItemStyle,
224 y_ref: f64,
225 flags: ShadedFlags,
226 item_flags: ItemFlags,
227 x_scale: f64,
228 x_start: f64,
229}
230
231impl<'a> super::PlotItemStyled for SimpleShadedPlot<'a> {
232 fn style_mut(&mut self) -> &mut PlotItemStyle {
233 &mut self.style
234 }
235}
236
237impl<'a> SimpleShadedPlot<'a> {
238 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
240 Self {
241 label,
242 values,
243 style: PlotItemStyle::default(),
244 y_ref: 0.0,
245 flags: ShadedFlags::NONE,
246 item_flags: ItemFlags::NONE,
247 x_scale: 1.0,
248 x_start: 0.0,
249 }
250 }
251
252 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
254 self.y_ref = y_ref;
255 self
256 }
257
258 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
260 self.flags = flags;
261 self
262 }
263
264 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
266 self.item_flags = flags;
267 self
268 }
269
270 pub fn with_x_scale(mut self, scale: f64) -> Self {
272 self.x_scale = scale;
273 self
274 }
275
276 pub fn with_x_start(mut self, start: f64) -> Self {
278 self.x_start = start;
279 self
280 }
281}
282
283impl<'a> Plot for SimpleShadedPlot<'a> {
284 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
285 if self.values.is_empty() {
286 return;
287 }
288 let Ok(count) = i32::try_from(self.values.len()) else {
289 return;
290 };
291
292 let _guard = plot_ui.bind();
293 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
294 let spec = plot_spec_with_style(
295 self.style,
296 self.flags.bits() | self.item_flags.bits(),
297 PlotDataLayout::DEFAULT,
298 );
299 sys::ImPlot_PlotShaded_doublePtrInt(
300 label_ptr,
301 self.values.as_ptr(),
302 count,
303 self.y_ref,
304 self.x_scale,
305 self.x_start,
306 spec,
307 );
308 })
309 }
310
311 fn label(&self) -> &str {
312 self.label
313 }
314}
315
316impl<'ui> crate::PlotUi<'ui> {
318 pub fn shaded_plot(
320 &self,
321 label: &str,
322 x_data: &[f64],
323 y_data: &[f64],
324 ) -> Result<(), PlotError> {
325 let plot = ShadedPlot::new(label, x_data, y_data);
326 plot.validate()?;
327 plot.plot(self);
328 Ok(())
329 }
330
331 pub fn shaded_plot_with_ref(
333 &self,
334 label: &str,
335 x_data: &[f64],
336 y_data: &[f64],
337 y_ref: f64,
338 ) -> Result<(), PlotError> {
339 let plot = ShadedPlot::new(label, x_data, y_data).with_y_ref(y_ref);
340 plot.validate()?;
341 plot.plot(self);
342 Ok(())
343 }
344
345 pub fn shaded_between_plot(
347 &self,
348 label: &str,
349 x_data: &[f64],
350 y1_data: &[f64],
351 y2_data: &[f64],
352 ) -> Result<(), PlotError> {
353 let plot = ShadedBetweenPlot::new(label, x_data, y1_data, y2_data);
354 plot.validate()?;
355 plot.plot(self);
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 plot.plot(self);
366 Ok(())
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn test_shaded_plot_creation() {
376 let x_data = [1.0, 2.0, 3.0, 4.0];
377 let y_data = [1.0, 4.0, 2.0, 3.0];
378
379 let plot = ShadedPlot::new("test", &x_data, &y_data);
380 assert_eq!(plot.label(), "test");
381 assert!(plot.validate().is_ok());
382 }
383
384 #[test]
385 fn test_shaded_plot_validation() {
386 let x_data = [1.0, 2.0, 3.0];
387 let y_data = [1.0, 4.0]; let plot = ShadedPlot::new("test", &x_data, &y_data);
390 assert!(plot.validate().is_err());
391 }
392
393 #[test]
394 fn test_shaded_between_plot() {
395 let x_data = [1.0, 2.0, 3.0, 4.0];
396 let y1_data = [1.0, 2.0, 3.0, 4.0];
397 let y2_data = [2.0, 3.0, 4.0, 5.0];
398
399 let plot = ShadedBetweenPlot::new("test", &x_data, &y1_data, &y2_data);
400 assert_eq!(plot.label(), "test");
401 assert!(plot.validate().is_ok());
402 }
403
404 #[test]
405 fn test_simple_shaded_plot_flags() {
406 let values = [1.0, 2.0, 3.0, 4.0];
407 let plot = SimpleShadedPlot::new("test", &values).with_item_flags(ItemFlags::NO_FIT);
408 assert_eq!(plot.label(), "test");
409 assert_eq!(plot.item_flags, ItemFlags::NO_FIT);
410 }
411}