1use super::{PlotData, PlotError, PlotItemStyle, plot_spec_with_style, 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 style: PlotItemStyle,
11 item_count: usize,
12 group_count: usize,
13 group_size: f64,
14 shift: f64,
15 flags: BarGroupsFlags,
16 item_flags: ItemFlags,
17}
18
19impl<'a> super::PlotItemStyled for BarGroupsPlot<'a> {
20 fn style_mut(&mut self) -> &mut PlotItemStyle {
21 &mut self.style
22 }
23}
24
25impl<'a> BarGroupsPlot<'a> {
26 pub fn new(
34 label_ids: Vec<&'a str>,
35 values: &'a [f64],
36 item_count: usize,
37 group_count: usize,
38 ) -> Self {
39 Self {
40 label_ids,
41 values,
42 style: PlotItemStyle::default(),
43 item_count,
44 group_count,
45 group_size: 0.67,
46 shift: 0.0,
47 flags: BarGroupsFlags::NONE,
48 item_flags: ItemFlags::NONE,
49 }
50 }
51
52 pub fn with_group_size(mut self, group_size: f64) -> Self {
54 self.group_size = group_size;
55 self
56 }
57
58 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
60 self.style = style;
61 self
62 }
63
64 pub fn with_shift(mut self, shift: f64) -> Self {
66 self.shift = shift;
67 self
68 }
69
70 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
72 self.flags = flags;
73 self
74 }
75
76 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
78 self.item_flags = flags;
79 self
80 }
81
82 pub fn horizontal(mut self) -> Self {
84 self.flags |= BarGroupsFlags::HORIZONTAL;
85 self
86 }
87
88 pub fn stacked(mut self) -> Self {
90 self.flags |= BarGroupsFlags::STACKED;
91 self
92 }
93
94 pub fn validate(&self) -> Result<(), PlotError> {
96 if self.label_ids.len() != self.item_count {
97 return Err(PlotError::InvalidData(format!(
98 "Label count ({}) must match item count ({})",
99 self.label_ids.len(),
100 self.item_count
101 )));
102 }
103
104 let expected_values = self.item_count * self.group_count;
105 if self.values.len() != expected_values {
106 return Err(PlotError::InvalidData(format!(
107 "Values length ({}) must equal item_count * group_count ({})",
108 self.values.len(),
109 expected_values
110 )));
111 }
112
113 if self.item_count == 0 || self.group_count == 0 {
114 return Err(PlotError::EmptyData);
115 }
116
117 Ok(())
118 }
119
120 pub fn plot(self) {
122 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
123 let spec = plot_spec_with_style(
124 self.style,
125 self.flags.bits() | self.item_flags.bits(),
126 0,
127 crate::IMPLOT_AUTO,
128 );
129 sys::ImPlot_PlotBarGroups_doublePtr(
130 label_ptrs.as_ptr(),
131 self.values.as_ptr(),
132 self.item_count as i32,
133 self.group_count as i32,
134 self.group_size,
135 self.shift,
136 spec,
137 );
138 })
139 }
140}
141
142impl<'a> PlotData for BarGroupsPlot<'a> {
143 fn label(&self) -> &str {
144 "BarGroups" }
146
147 fn data_len(&self) -> usize {
148 self.values.len()
149 }
150}
151
152pub struct BarGroupsPlotF32<'a> {
154 label_ids: Vec<&'a str>,
155 values: &'a [f32],
156 style: PlotItemStyle,
157 item_count: usize,
158 group_count: usize,
159 group_size: f64,
160 shift: f64,
161 flags: BarGroupsFlags,
162 item_flags: ItemFlags,
163}
164
165impl<'a> super::PlotItemStyled for BarGroupsPlotF32<'a> {
166 fn style_mut(&mut self) -> &mut PlotItemStyle {
167 &mut self.style
168 }
169}
170
171impl<'a> BarGroupsPlotF32<'a> {
172 pub fn new(
174 label_ids: Vec<&'a str>,
175 values: &'a [f32],
176 item_count: usize,
177 group_count: usize,
178 ) -> Self {
179 Self {
180 label_ids,
181 values,
182 style: PlotItemStyle::default(),
183 item_count,
184 group_count,
185 group_size: 0.67,
186 shift: 0.0,
187 flags: BarGroupsFlags::NONE,
188 item_flags: ItemFlags::NONE,
189 }
190 }
191
192 pub fn with_group_size(mut self, group_size: f64) -> Self {
194 self.group_size = group_size;
195 self
196 }
197
198 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
200 self.style = style;
201 self
202 }
203
204 pub fn with_shift(mut self, shift: f64) -> Self {
206 self.shift = shift;
207 self
208 }
209
210 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
212 self.flags = flags;
213 self
214 }
215
216 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
218 self.item_flags = flags;
219 self
220 }
221
222 pub fn horizontal(mut self) -> Self {
224 self.flags |= BarGroupsFlags::HORIZONTAL;
225 self
226 }
227
228 pub fn stacked(mut self) -> Self {
230 self.flags |= BarGroupsFlags::STACKED;
231 self
232 }
233
234 pub fn validate(&self) -> Result<(), PlotError> {
236 if self.label_ids.len() != self.item_count {
237 return Err(PlotError::InvalidData(format!(
238 "Label count ({}) must match item count ({})",
239 self.label_ids.len(),
240 self.item_count
241 )));
242 }
243
244 let expected_values = self.item_count * self.group_count;
245 if self.values.len() != expected_values {
246 return Err(PlotError::InvalidData(format!(
247 "Values length ({}) must equal item_count * group_count ({})",
248 self.values.len(),
249 expected_values
250 )));
251 }
252
253 if self.item_count == 0 || self.group_count == 0 {
254 return Err(PlotError::EmptyData);
255 }
256
257 Ok(())
258 }
259
260 pub fn plot(self) {
262 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
263 let spec = plot_spec_with_style(
264 self.style,
265 self.flags.bits() | self.item_flags.bits(),
266 0,
267 crate::IMPLOT_AUTO,
268 );
269 sys::ImPlot_PlotBarGroups_FloatPtr(
270 label_ptrs.as_ptr(),
271 self.values.as_ptr(),
272 self.item_count as i32,
273 self.group_count as i32,
274 self.group_size,
275 self.shift,
276 spec,
277 );
278 })
279 }
280}
281
282impl<'a> PlotData for BarGroupsPlotF32<'a> {
283 fn label(&self) -> &str {
284 "BarGroups" }
286
287 fn data_len(&self) -> usize {
288 self.values.len()
289 }
290}
291
292pub struct SimpleBarGroupsPlot<'a> {
294 labels: Vec<&'a str>,
295 data: Vec<Vec<f64>>,
296 style: PlotItemStyle,
297 group_size: f64,
298 flags: BarGroupsFlags,
299 item_flags: ItemFlags,
300}
301
302impl<'a> super::PlotItemStyled for SimpleBarGroupsPlot<'a> {
303 fn style_mut(&mut self) -> &mut PlotItemStyle {
304 &mut self.style
305 }
306}
307
308impl<'a> SimpleBarGroupsPlot<'a> {
309 pub fn new(labels: Vec<&'a str>, data: Vec<Vec<f64>>) -> Self {
315 Self {
316 labels,
317 data,
318 style: PlotItemStyle::default(),
319 group_size: 0.67,
320 flags: BarGroupsFlags::NONE,
321 item_flags: ItemFlags::NONE,
322 }
323 }
324
325 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
327 self.style = style;
328 self
329 }
330
331 pub fn with_group_size(mut self, group_size: f64) -> Self {
333 self.group_size = group_size;
334 self
335 }
336
337 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
339 self.flags = flags;
340 self
341 }
342
343 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
345 self.item_flags = flags;
346 self
347 }
348
349 pub fn horizontal(mut self) -> Self {
351 self.flags |= BarGroupsFlags::HORIZONTAL;
352 self
353 }
354
355 pub fn stacked(mut self) -> Self {
357 self.flags |= BarGroupsFlags::STACKED;
358 self
359 }
360
361 pub fn plot(self) {
363 if self.data.is_empty() || self.labels.is_empty() {
364 return;
365 }
366
367 let item_count = self.data.len();
368 let group_count = self.data[0].len();
369
370 let mut flattened_data = Vec::with_capacity(item_count * group_count);
372 for group_idx in 0..group_count {
373 for item_idx in 0..item_count {
374 if group_idx < self.data[item_idx].len() {
375 flattened_data.push(self.data[item_idx][group_idx]);
376 } else {
377 flattened_data.push(0.0); }
379 }
380 }
381
382 let plot = BarGroupsPlot::new(self.labels, &flattened_data, item_count, group_count)
383 .with_style(self.style)
384 .with_group_size(self.group_size)
385 .with_flags(self.flags)
386 .with_item_flags(self.item_flags);
387
388 plot.plot();
389 }
390}