dear_implot/plots/
scatter.rs1use super::{Plot, PlotError, safe_cstring, validate_data_lengths};
4use crate::{ScatterFlags, sys};
5
6pub struct ScatterPlot<'a> {
8 label: &'a str,
9 x_data: &'a [f64],
10 y_data: &'a [f64],
11 flags: ScatterFlags,
12 offset: i32,
13 stride: i32,
14}
15
16impl<'a> ScatterPlot<'a> {
17 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
19 Self {
20 label,
21 x_data,
22 y_data,
23 flags: ScatterFlags::NONE,
24 offset: 0,
25 stride: std::mem::size_of::<f64>() as i32,
26 }
27 }
28
29 pub fn with_flags(mut self, flags: ScatterFlags) -> Self {
31 self.flags = flags;
32 self
33 }
34
35 pub fn with_offset(mut self, offset: i32) -> Self {
37 self.offset = offset;
38 self
39 }
40
41 pub fn with_stride(mut self, stride: i32) -> Self {
43 self.stride = stride;
44 self
45 }
46
47 pub fn validate(&self) -> Result<(), PlotError> {
49 validate_data_lengths(self.x_data, self.y_data)
50 }
51}
52
53impl<'a> Plot for ScatterPlot<'a> {
54 fn plot(&self) {
55 if self.validate().is_err() {
56 return; }
58
59 let label_cstr = safe_cstring(self.label);
60
61 unsafe {
62 sys::ImPlot_PlotScatter_doublePtrdoublePtr(
63 label_cstr.as_ptr(),
64 self.x_data.as_ptr(),
65 self.y_data.as_ptr(),
66 self.x_data.len() as i32,
67 self.flags.bits() as i32,
68 self.offset,
69 self.stride,
70 );
71 }
72 }
73
74 fn label(&self) -> &str {
75 self.label
76 }
77}
78
79pub struct SimpleScatterPlot<'a> {
81 label: &'a str,
82 values: &'a [f64],
83 x_scale: f64,
84 x_start: f64,
85}
86
87impl<'a> SimpleScatterPlot<'a> {
88 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
90 Self {
91 label,
92 values,
93 x_scale: 1.0,
94 x_start: 0.0,
95 }
96 }
97
98 pub fn with_x_scale(mut self, scale: f64) -> Self {
100 self.x_scale = scale;
101 self
102 }
103
104 pub fn with_x_start(mut self, start: f64) -> Self {
106 self.x_start = start;
107 self
108 }
109}
110
111impl<'a> Plot for SimpleScatterPlot<'a> {
112 fn plot(&self) {
113 if self.values.is_empty() {
114 return;
115 }
116
117 let label_cstr = safe_cstring(self.label);
118
119 let x_data: Vec<f64> = (0..self.values.len())
121 .map(|i| self.x_start + i as f64 * self.x_scale)
122 .collect();
123
124 unsafe {
125 sys::ImPlot_PlotScatter_doublePtrdoublePtr(
126 label_cstr.as_ptr(),
127 x_data.as_ptr(),
128 self.values.as_ptr(),
129 self.values.len() as i32,
130 0,
131 0,
132 std::mem::size_of::<f64>() as i32,
133 );
134 }
135 }
136
137 fn label(&self) -> &str {
138 self.label
139 }
140}
141
142impl<'ui> crate::PlotUi<'ui> {
144 pub fn scatter_plot(
146 &self,
147 label: &str,
148 x_data: &[f64],
149 y_data: &[f64],
150 ) -> Result<(), PlotError> {
151 let plot = ScatterPlot::new(label, x_data, y_data);
152 plot.validate()?;
153 plot.plot();
154 Ok(())
155 }
156
157 pub fn simple_scatter_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
159 if values.is_empty() {
160 return Err(PlotError::EmptyData);
161 }
162 let plot = SimpleScatterPlot::new(label, values);
163 plot.plot();
164 Ok(())
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn test_scatter_plot_creation() {
174 let x_data = [1.0, 2.0, 3.0, 4.0];
175 let y_data = [1.0, 4.0, 2.0, 3.0];
176
177 let plot = ScatterPlot::new("test", &x_data, &y_data);
178 assert_eq!(plot.label(), "test");
179 assert!(plot.validate().is_ok());
180 }
181
182 #[test]
183 fn test_scatter_plot_validation() {
184 let x_data = [1.0, 2.0, 3.0];
185 let y_data = [1.0, 4.0]; let plot = ScatterPlot::new("test", &x_data, &y_data);
188 assert!(plot.validate().is_err());
189 }
190
191 #[test]
192 fn test_simple_scatter_plot() {
193 let values = [1.0, 2.0, 3.0, 4.0];
194 let plot = SimpleScatterPlot::new("test", &values);
195 assert_eq!(plot.label(), "test");
196 }
197}