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, 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 layout: PlotDataLayout,
18}
19
20impl<'a> super::PlotItemStyled for LinePlot<'a> {
21 fn style_mut(&mut self) -> &mut PlotItemStyle {
22 &mut self.style
23 }
24}
25
26impl<'a> LinePlot<'a> {
27 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
29 Self {
30 label,
31 x_data,
32 y_data,
33 style: PlotItemStyle::default(),
34 flags: LineFlags::NONE,
35 item_flags: ItemFlags::NONE,
36 layout: PlotDataLayout::DEFAULT,
37 }
38 }
39
40 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
42 self.style = style;
43 self
44 }
45
46 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
48 self.style = self.style.with_line_color(color);
49 self
50 }
51
52 pub fn with_line_weight(mut self, weight: f32) -> Self {
54 self.style = self.style.with_line_weight(weight);
55 self
56 }
57
58 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
60 self.style = self.style.with_fill_color(color);
61 self
62 }
63
64 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
66 self.style = self.style.with_fill_alpha(alpha);
67 self
68 }
69
70 pub fn with_marker(mut self, marker: Marker) -> Self {
72 self.style = self.style.with_marker(marker);
73 self
74 }
75
76 pub fn with_marker_size(mut self, size: f32) -> Self {
78 self.style = self.style.with_marker_size(size);
79 self
80 }
81
82 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
84 self.style = self.style.with_marker_line_color(color);
85 self
86 }
87
88 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
90 self.style = self.style.with_marker_fill_color(color);
91 self
92 }
93
94 pub fn with_flags(mut self, flags: LineFlags) -> Self {
96 self.flags = flags;
97 self
98 }
99
100 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
102 self.item_flags = flags;
103 self
104 }
105
106 pub unsafe fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
113 self.layout = layout;
114 self
115 }
116
117 pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
119 self.layout = self.layout.with_offset(offset);
120 self
121 }
122
123 pub unsafe fn with_stride(mut self, stride: PlotDataStride) -> Self {
130 self.layout = self.layout.with_stride(stride);
131 self
132 }
133
134 pub fn validate(&self) -> Result<(), PlotError> {
136 validate_data_lengths(self.x_data, self.y_data)
137 }
138}
139
140impl<'a> Plot for LinePlot<'a> {
141 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
142 if self.validate().is_err() {
143 return; }
145 let Ok(count) = i32::try_from(self.x_data.len()) else {
146 return;
147 };
148
149 plot_ui.with_bound_context(|| {
150 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
151 let spec = plot_spec_with_style(
152 self.style,
153 self.flags.bits() | self.item_flags.bits(),
154 self.layout,
155 );
156 sys::ImPlot_PlotLine_doublePtrdoublePtr(
157 label_ptr,
158 self.x_data.as_ptr(),
159 self.y_data.as_ptr(),
160 count,
161 spec,
162 );
163 })
164 })
165 }
166
167 fn label(&self) -> &str {
168 self.label
169 }
170}
171
172pub struct SimpleLinePlot<'a> {
174 label: &'a str,
175 values: &'a [f64],
176 style: PlotItemStyle,
177 flags: LineFlags,
178 item_flags: ItemFlags,
179 x_scale: f64,
180 x_start: f64,
181}
182
183impl<'a> super::PlotItemStyled for SimpleLinePlot<'a> {
184 fn style_mut(&mut self) -> &mut PlotItemStyle {
185 &mut self.style
186 }
187}
188
189impl<'a> SimpleLinePlot<'a> {
190 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
192 Self {
193 label,
194 values,
195 style: PlotItemStyle::default(),
196 flags: LineFlags::NONE,
197 item_flags: ItemFlags::NONE,
198 x_scale: 1.0,
199 x_start: 0.0,
200 }
201 }
202
203 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
205 self.style = style;
206 self
207 }
208
209 pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
211 self.style = self.style.with_line_color(color);
212 self
213 }
214
215 pub fn with_line_weight(mut self, weight: f32) -> Self {
217 self.style = self.style.with_line_weight(weight);
218 self
219 }
220
221 pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
223 self.style = self.style.with_fill_color(color);
224 self
225 }
226
227 pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
229 self.style = self.style.with_fill_alpha(alpha);
230 self
231 }
232
233 pub fn with_marker(mut self, marker: Marker) -> Self {
235 self.style = self.style.with_marker(marker);
236 self
237 }
238
239 pub fn with_marker_size(mut self, size: f32) -> Self {
241 self.style = self.style.with_marker_size(size);
242 self
243 }
244
245 pub fn with_marker_line_color(mut self, color: [f32; 4]) -> Self {
247 self.style = self.style.with_marker_line_color(color);
248 self
249 }
250
251 pub fn with_marker_fill_color(mut self, color: [f32; 4]) -> Self {
253 self.style = self.style.with_marker_fill_color(color);
254 self
255 }
256
257 pub fn with_flags(mut self, flags: LineFlags) -> Self {
259 self.flags = flags;
260 self
261 }
262
263 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
265 self.item_flags = flags;
266 self
267 }
268
269 pub fn with_x_scale(mut self, scale: f64) -> Self {
271 self.x_scale = scale;
272 self
273 }
274
275 pub fn with_x_start(mut self, start: f64) -> Self {
277 self.x_start = start;
278 self
279 }
280}
281
282impl<'a> Plot for SimpleLinePlot<'a> {
283 fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
284 if self.values.is_empty() {
285 return;
286 }
287 let Ok(count) = i32::try_from(self.values.len()) else {
288 return;
289 };
290
291 plot_ui.with_bound_context(|| {
292 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
293 let spec = plot_spec_with_style(
294 self.style,
295 self.flags.bits() | self.item_flags.bits(),
296 PlotDataLayout::DEFAULT,
297 );
298 sys::ImPlot_PlotLine_doublePtrInt(
299 label_ptr,
300 self.values.as_ptr(),
301 count,
302 self.x_scale,
303 self.x_start,
304 spec,
305 );
306 })
307 })
308 }
309
310 fn label(&self) -> &str {
311 self.label
312 }
313}
314
315impl<'ui> crate::PlotUi<'ui> {
317 pub fn line_plot(&self, label: &str, x_data: &[f64], y_data: &[f64]) -> Result<(), PlotError> {
319 let plot = LinePlot::new(label, x_data, y_data);
320 plot.validate()?;
321 plot.plot(self);
322 Ok(())
323 }
324
325 pub fn simple_line_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
327 if values.is_empty() {
328 return Err(PlotError::EmptyData);
329 }
330 let plot = SimpleLinePlot::new(label, values);
331 plot.plot(self);
332 Ok(())
333 }
334}
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339
340 #[test]
341 fn test_line_plot_creation() {
342 let x_data = [1.0, 2.0, 3.0, 4.0];
343 let y_data = [1.0, 4.0, 2.0, 3.0];
344
345 let plot = LinePlot::new("test", &x_data, &y_data);
346 assert_eq!(plot.label(), "test");
347 assert!(plot.validate().is_ok());
348 }
349
350 #[test]
351 fn test_line_plot_validation() {
352 let x_data = [1.0, 2.0, 3.0];
353 let y_data = [1.0, 4.0]; let plot = LinePlot::new("test", &x_data, &y_data);
356 assert!(plot.validate().is_err());
357 }
358
359 #[test]
360 fn test_simple_line_plot() {
361 let values = [1.0, 2.0, 3.0, 4.0];
362 let plot = SimpleLinePlot::new("test", &values)
363 .with_flags(LineFlags::LOOP)
364 .with_item_flags(ItemFlags::NO_LEGEND);
365 assert_eq!(plot.label(), "test");
366 assert_eq!(plot.flags.bits(), LineFlags::LOOP.bits());
367 assert_eq!(plot.item_flags, ItemFlags::NO_LEGEND);
368 }
369
370 #[test]
371 fn test_line_plot_style_builders() {
372 let x_data = [1.0, 2.0, 3.0, 4.0];
373 let y_data = [1.0, 4.0, 2.0, 3.0];
374
375 let plot = LinePlot::new("styled", &x_data, &y_data)
376 .with_line_color([0.1, 0.2, 0.3, 0.4])
377 .with_line_weight(2.5)
378 .with_fill_color([0.4, 0.3, 0.2, 0.1])
379 .with_fill_alpha(0.6)
380 .with_marker(Marker::Circle)
381 .with_marker_size(7.0)
382 .with_marker_line_color([0.9, 0.8, 0.7, 0.6])
383 .with_marker_fill_color([0.6, 0.7, 0.8, 0.9]);
384
385 assert_eq!(
386 plot.style.line_color,
387 Some(sys::ImVec4_c {
388 x: 0.1,
389 y: 0.2,
390 z: 0.3,
391 w: 0.4,
392 })
393 );
394 assert_eq!(plot.style.line_weight, Some(2.5));
395 assert_eq!(
396 plot.style.fill_color,
397 Some(sys::ImVec4_c {
398 x: 0.4,
399 y: 0.3,
400 z: 0.2,
401 w: 0.1,
402 })
403 );
404 assert_eq!(plot.style.fill_alpha, Some(0.6));
405 assert_eq!(plot.style.marker, Some(Marker::Circle as sys::ImPlotMarker));
406 assert_eq!(plot.style.marker_size, Some(7.0));
407 assert_eq!(
408 plot.style.marker_line_color,
409 Some(sys::ImVec4_c {
410 x: 0.9,
411 y: 0.8,
412 z: 0.7,
413 w: 0.6,
414 })
415 );
416 assert_eq!(
417 plot.style.marker_fill_color,
418 Some(sys::ImVec4_c {
419 x: 0.6,
420 y: 0.7,
421 z: 0.8,
422 w: 0.9,
423 })
424 );
425 }
426}