1use super::{
4 Plot, PlotError, PlotItemStyle, plot_spec_with_style, validate_data_lengths,
5 with_plot_str_or_empty,
6};
7use crate::{ItemFlags, LineFlags, Marker, sys};
8
9pub struct LinePlot<'a> {
11 label: &'a str,
12 x_data: &'a [f64],
13 y_data: &'a [f64],
14 style: PlotItemStyle,
15 flags: LineFlags,
16 item_flags: ItemFlags,
17 offset: i32,
18 stride: i32,
19}
20
21impl<'a> super::PlotItemStyled for LinePlot<'a> {
22 fn style_mut(&mut self) -> &mut PlotItemStyle {
23 &mut self.style
24 }
25}
26
27impl<'a> LinePlot<'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 flags: LineFlags::NONE,
36 item_flags: ItemFlags::NONE,
37 offset: 0,
38 stride: std::mem::size_of::<f64>() as i32,
39 }
40 }
41
42 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
44 self.style = style;
45 self
46 }
47
48 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
50 self.style = self.style.with_line_color(color);
51 self
52 }
53
54 pub fn with_line_weight(mut self, weight: f32) -> Self {
56 self.style = self.style.with_line_weight(weight);
57 self
58 }
59
60 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
62 self.style = self.style.with_fill_color(color);
63 self
64 }
65
66 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
68 self.style = self.style.with_fill_alpha(alpha);
69 self
70 }
71
72 pub fn with_marker(mut self, marker: Marker) -> Self {
74 self.style = self.style.with_marker(marker);
75 self
76 }
77
78 pub fn with_marker_size(mut self, size: f32) -> Self {
80 self.style = self.style.with_marker_size(size);
81 self
82 }
83
84 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
86 self.style = self.style.with_marker_line_color(color);
87 self
88 }
89
90 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
92 self.style = self.style.with_marker_fill_color(color);
93 self
94 }
95
96 pub fn with_flags(mut self, flags: LineFlags) -> Self {
98 self.flags = flags;
99 self
100 }
101
102 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
104 self.item_flags = flags;
105 self
106 }
107
108 pub fn with_offset(mut self, offset: i32) -> Self {
110 self.offset = offset;
111 self
112 }
113
114 pub fn with_stride(mut self, stride: i32) -> Self {
116 self.stride = stride;
117 self
118 }
119
120 pub fn validate(&self) -> Result<(), PlotError> {
122 validate_data_lengths(self.x_data, self.y_data)
123 }
124}
125
126impl<'a> Plot for LinePlot<'a> {
127 fn plot(&self) {
128 if self.validate().is_err() {
129 return; }
131 let Ok(count) = i32::try_from(self.x_data.len()) else {
132 return;
133 };
134
135 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
136 let spec = plot_spec_with_style(
137 self.style,
138 self.flags.bits() | self.item_flags.bits(),
139 self.offset,
140 self.stride,
141 );
142 sys::ImPlot_PlotLine_doublePtrdoublePtr(
143 label_ptr,
144 self.x_data.as_ptr(),
145 self.y_data.as_ptr(),
146 count,
147 spec,
148 );
149 })
150 }
151
152 fn label(&self) -> &str {
153 self.label
154 }
155}
156
157pub struct SimpleLinePlot<'a> {
159 label: &'a str,
160 values: &'a [f64],
161 style: PlotItemStyle,
162 flags: LineFlags,
163 item_flags: ItemFlags,
164 x_scale: f64,
165 x_start: f64,
166}
167
168impl<'a> super::PlotItemStyled for SimpleLinePlot<'a> {
169 fn style_mut(&mut self) -> &mut PlotItemStyle {
170 &mut self.style
171 }
172}
173
174impl<'a> SimpleLinePlot<'a> {
175 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
177 Self {
178 label,
179 values,
180 style: PlotItemStyle::default(),
181 flags: LineFlags::NONE,
182 item_flags: ItemFlags::NONE,
183 x_scale: 1.0,
184 x_start: 0.0,
185 }
186 }
187
188 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
190 self.style = style;
191 self
192 }
193
194 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
196 self.style = self.style.with_line_color(color);
197 self
198 }
199
200 pub fn with_line_weight(mut self, weight: f32) -> Self {
202 self.style = self.style.with_line_weight(weight);
203 self
204 }
205
206 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
208 self.style = self.style.with_fill_color(color);
209 self
210 }
211
212 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
214 self.style = self.style.with_fill_alpha(alpha);
215 self
216 }
217
218 pub fn with_marker(mut self, marker: Marker) -> Self {
220 self.style = self.style.with_marker(marker);
221 self
222 }
223
224 pub fn with_marker_size(mut self, size: f32) -> Self {
226 self.style = self.style.with_marker_size(size);
227 self
228 }
229
230 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
232 self.style = self.style.with_marker_line_color(color);
233 self
234 }
235
236 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
238 self.style = self.style.with_marker_fill_color(color);
239 self
240 }
241
242 pub fn with_flags(mut self, flags: LineFlags) -> Self {
244 self.flags = flags;
245 self
246 }
247
248 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
250 self.item_flags = flags;
251 self
252 }
253
254 pub fn with_x_scale(mut self, scale: f64) -> Self {
256 self.x_scale = scale;
257 self
258 }
259
260 pub fn with_x_start(mut self, start: f64) -> Self {
262 self.x_start = start;
263 self
264 }
265}
266
267impl<'a> Plot for SimpleLinePlot<'a> {
268 fn plot(&self) {
269 if self.values.is_empty() {
270 return;
271 }
272 let Ok(count) = i32::try_from(self.values.len()) else {
273 return;
274 };
275
276 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
277 let spec = plot_spec_with_style(
278 self.style,
279 self.flags.bits() | self.item_flags.bits(),
280 0,
281 std::mem::size_of::<f64>() as i32,
282 );
283 sys::ImPlot_PlotLine_doublePtrInt(
284 label_ptr,
285 self.values.as_ptr(),
286 count,
287 self.x_scale,
288 self.x_start,
289 spec,
290 );
291 })
292 }
293
294 fn label(&self) -> &str {
295 self.label
296 }
297}
298
299impl<'ui> crate::PlotUi<'ui> {
301 pub fn line_plot(&self, label: &str, x_data: &[f64], y_data: &[f64]) -> Result<(), PlotError> {
303 let plot = LinePlot::new(label, x_data, y_data);
304 plot.validate()?;
305 plot.plot();
306 Ok(())
307 }
308
309 pub fn simple_line_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
311 if values.is_empty() {
312 return Err(PlotError::EmptyData);
313 }
314 let plot = SimpleLinePlot::new(label, values);
315 plot.plot();
316 Ok(())
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323
324 #[test]
325 fn test_line_plot_creation() {
326 let x_data = [1.0, 2.0, 3.0, 4.0];
327 let y_data = [1.0, 4.0, 2.0, 3.0];
328
329 let plot = LinePlot::new("test", &x_data, &y_data);
330 assert_eq!(plot.label(), "test");
331 assert!(plot.validate().is_ok());
332 }
333
334 #[test]
335 fn test_line_plot_validation() {
336 let x_data = [1.0, 2.0, 3.0];
337 let y_data = [1.0, 4.0]; let plot = LinePlot::new("test", &x_data, &y_data);
340 assert!(plot.validate().is_err());
341 }
342
343 #[test]
344 fn test_simple_line_plot() {
345 let values = [1.0, 2.0, 3.0, 4.0];
346 let plot = SimpleLinePlot::new("test", &values)
347 .with_flags(LineFlags::LOOP)
348 .with_item_flags(ItemFlags::NO_LEGEND);
349 assert_eq!(plot.label(), "test");
350 assert_eq!(plot.flags.bits(), LineFlags::LOOP.bits());
351 assert_eq!(plot.item_flags, ItemFlags::NO_LEGEND);
352 }
353
354 #[test]
355 fn test_line_plot_style_builders() {
356 let x_data = [1.0, 2.0, 3.0, 4.0];
357 let y_data = [1.0, 4.0, 2.0, 3.0];
358
359 let plot = LinePlot::new("styled", &x_data, &y_data)
360 .with_line_color([0.1, 0.2, 0.3, 0.4])
361 .with_line_weight(2.5)
362 .with_fill_color([0.4, 0.3, 0.2, 0.1])
363 .with_fill_alpha(0.6)
364 .with_marker(Marker::Circle)
365 .with_marker_size(7.0)
366 .with_marker_line_color([0.9, 0.8, 0.7, 0.6])
367 .with_marker_fill_color([0.6, 0.7, 0.8, 0.9]);
368
369 assert_eq!(
370 plot.style.line_color,
371 Some(sys::ImVec4_c {
372 x: 0.1,
373 y: 0.2,
374 z: 0.3,
375 w: 0.4,
376 })
377 );
378 assert_eq!(plot.style.line_weight, Some(2.5));
379 assert_eq!(
380 plot.style.fill_color,
381 Some(sys::ImVec4_c {
382 x: 0.4,
383 y: 0.3,
384 z: 0.2,
385 w: 0.1,
386 })
387 );
388 assert_eq!(plot.style.fill_alpha, Some(0.6));
389 assert_eq!(plot.style.marker, Some(Marker::Circle as sys::ImPlotMarker));
390 assert_eq!(plot.style.marker_size, Some(7.0));
391 assert_eq!(
392 plot.style.marker_line_color,
393 Some(sys::ImVec4_c {
394 x: 0.9,
395 y: 0.8,
396 z: 0.7,
397 w: 0.6,
398 })
399 );
400 assert_eq!(
401 plot.style.marker_fill_color,
402 Some(sys::ImVec4_c {
403 x: 0.6,
404 y: 0.7,
405 z: 0.8,
406 w: 0.9,
407 })
408 );
409 }
410}