1use super::{PlotData, PlotError, plot_spec_from, with_plot_str_slice};
4use crate::{BarGroupsFlags, ItemFlags, sys};
5
6pub struct BarGroupsPlot<'a> {
8 label_ids: Vec<&'a str>,
9 values: &'a [f64],
10 item_count: usize,
11 group_count: usize,
12 group_size: f64,
13 shift: f64,
14 flags: BarGroupsFlags,
15 item_flags: ItemFlags,
16}
17
18impl<'a> BarGroupsPlot<'a> {
19 pub fn new(
27 label_ids: Vec<&'a str>,
28 values: &'a [f64],
29 item_count: usize,
30 group_count: usize,
31 ) -> Self {
32 Self {
33 label_ids,
34 values,
35 item_count,
36 group_count,
37 group_size: 0.67,
38 shift: 0.0,
39 flags: BarGroupsFlags::NONE,
40 item_flags: ItemFlags::NONE,
41 }
42 }
43
44 pub fn with_group_size(mut self, group_size: f64) -> Self {
46 self.group_size = group_size;
47 self
48 }
49
50 pub fn with_shift(mut self, shift: f64) -> Self {
52 self.shift = shift;
53 self
54 }
55
56 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
58 self.flags = flags;
59 self
60 }
61
62 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
64 self.item_flags = flags;
65 self
66 }
67
68 pub fn horizontal(mut self) -> Self {
70 self.flags |= BarGroupsFlags::HORIZONTAL;
71 self
72 }
73
74 pub fn stacked(mut self) -> Self {
76 self.flags |= BarGroupsFlags::STACKED;
77 self
78 }
79
80 pub fn validate(&self) -> Result<(), PlotError> {
82 if self.label_ids.len() != self.item_count {
83 return Err(PlotError::InvalidData(format!(
84 "Label count ({}) must match item count ({})",
85 self.label_ids.len(),
86 self.item_count
87 )));
88 }
89
90 let expected_values = self.item_count * self.group_count;
91 if self.values.len() != expected_values {
92 return Err(PlotError::InvalidData(format!(
93 "Values length ({}) must equal item_count * group_count ({})",
94 self.values.len(),
95 expected_values
96 )));
97 }
98
99 if self.item_count == 0 || self.group_count == 0 {
100 return Err(PlotError::EmptyData);
101 }
102
103 Ok(())
104 }
105
106 pub fn plot(self) {
108 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
109 let spec = plot_spec_from(
110 self.flags.bits() | self.item_flags.bits(),
111 0,
112 crate::IMPLOT_AUTO,
113 );
114 sys::ImPlot_PlotBarGroups_doublePtr(
115 label_ptrs.as_ptr(),
116 self.values.as_ptr(),
117 self.item_count as i32,
118 self.group_count as i32,
119 self.group_size,
120 self.shift,
121 spec,
122 );
123 })
124 }
125}
126
127impl<'a> PlotData for BarGroupsPlot<'a> {
128 fn label(&self) -> &str {
129 "BarGroups" }
131
132 fn data_len(&self) -> usize {
133 self.values.len()
134 }
135}
136
137pub struct BarGroupsPlotF32<'a> {
139 label_ids: Vec<&'a str>,
140 values: &'a [f32],
141 item_count: usize,
142 group_count: usize,
143 group_size: f64,
144 shift: f64,
145 flags: BarGroupsFlags,
146 item_flags: ItemFlags,
147}
148
149impl<'a> BarGroupsPlotF32<'a> {
150 pub fn new(
152 label_ids: Vec<&'a str>,
153 values: &'a [f32],
154 item_count: usize,
155 group_count: usize,
156 ) -> Self {
157 Self {
158 label_ids,
159 values,
160 item_count,
161 group_count,
162 group_size: 0.67,
163 shift: 0.0,
164 flags: BarGroupsFlags::NONE,
165 item_flags: ItemFlags::NONE,
166 }
167 }
168
169 pub fn with_group_size(mut self, group_size: f64) -> Self {
171 self.group_size = group_size;
172 self
173 }
174
175 pub fn with_shift(mut self, shift: f64) -> Self {
177 self.shift = shift;
178 self
179 }
180
181 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
183 self.flags = flags;
184 self
185 }
186
187 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
189 self.item_flags = flags;
190 self
191 }
192
193 pub fn horizontal(mut self) -> Self {
195 self.flags |= BarGroupsFlags::HORIZONTAL;
196 self
197 }
198
199 pub fn stacked(mut self) -> Self {
201 self.flags |= BarGroupsFlags::STACKED;
202 self
203 }
204
205 pub fn validate(&self) -> Result<(), PlotError> {
207 if self.label_ids.len() != self.item_count {
208 return Err(PlotError::InvalidData(format!(
209 "Label count ({}) must match item count ({})",
210 self.label_ids.len(),
211 self.item_count
212 )));
213 }
214
215 let expected_values = self.item_count * self.group_count;
216 if self.values.len() != expected_values {
217 return Err(PlotError::InvalidData(format!(
218 "Values length ({}) must equal item_count * group_count ({})",
219 self.values.len(),
220 expected_values
221 )));
222 }
223
224 if self.item_count == 0 || self.group_count == 0 {
225 return Err(PlotError::EmptyData);
226 }
227
228 Ok(())
229 }
230
231 pub fn plot(self) {
233 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
234 let spec = plot_spec_from(
235 self.flags.bits() | self.item_flags.bits(),
236 0,
237 crate::IMPLOT_AUTO,
238 );
239 sys::ImPlot_PlotBarGroups_FloatPtr(
240 label_ptrs.as_ptr(),
241 self.values.as_ptr(),
242 self.item_count as i32,
243 self.group_count as i32,
244 self.group_size,
245 self.shift,
246 spec,
247 );
248 })
249 }
250}
251
252impl<'a> PlotData for BarGroupsPlotF32<'a> {
253 fn label(&self) -> &str {
254 "BarGroups" }
256
257 fn data_len(&self) -> usize {
258 self.values.len()
259 }
260}
261
262pub struct SimpleBarGroupsPlot<'a> {
264 labels: Vec<&'a str>,
265 data: Vec<Vec<f64>>,
266 group_size: f64,
267 flags: BarGroupsFlags,
268}
269
270impl<'a> SimpleBarGroupsPlot<'a> {
271 pub fn new(labels: Vec<&'a str>, data: Vec<Vec<f64>>) -> Self {
277 Self {
278 labels,
279 data,
280 group_size: 0.67,
281 flags: BarGroupsFlags::NONE,
282 }
283 }
284
285 pub fn with_group_size(mut self, group_size: f64) -> Self {
287 self.group_size = group_size;
288 self
289 }
290
291 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
293 self.flags = flags;
294 self
295 }
296
297 pub fn horizontal(mut self) -> Self {
299 self.flags |= BarGroupsFlags::HORIZONTAL;
300 self
301 }
302
303 pub fn stacked(mut self) -> Self {
305 self.flags |= BarGroupsFlags::STACKED;
306 self
307 }
308
309 pub fn plot(self) {
311 if self.data.is_empty() || self.labels.is_empty() {
312 return;
313 }
314
315 let item_count = self.data.len();
316 let group_count = self.data[0].len();
317
318 let mut flattened_data = Vec::with_capacity(item_count * group_count);
320 for group_idx in 0..group_count {
321 for item_idx in 0..item_count {
322 if group_idx < self.data[item_idx].len() {
323 flattened_data.push(self.data[item_idx][group_idx]);
324 } else {
325 flattened_data.push(0.0); }
327 }
328 }
329
330 let plot = BarGroupsPlot::new(self.labels, &flattened_data, item_count, group_count)
331 .with_group_size(self.group_size)
332 .with_flags(self.flags);
333
334 plot.plot();
335 }
336}