1use super::{
4 PlotData, PlotDataLayout, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_slice,
5};
6use crate::{BarGroupsFlags, ItemFlags, sys};
7
8pub struct BarGroupsPlot<'a> {
10 label_ids: Vec<&'a str>,
11 values: &'a [f64],
12 style: PlotItemStyle,
13 item_count: usize,
14 group_count: usize,
15 group_size: f64,
16 shift: f64,
17 flags: BarGroupsFlags,
18 item_flags: ItemFlags,
19}
20
21impl<'a> super::PlotItemStyled for BarGroupsPlot<'a> {
22 fn style_mut(&mut self) -> &mut PlotItemStyle {
23 &mut self.style
24 }
25}
26
27impl<'a> BarGroupsPlot<'a> {
28 pub fn new(
36 label_ids: Vec<&'a str>,
37 values: &'a [f64],
38 item_count: usize,
39 group_count: usize,
40 ) -> Self {
41 Self {
42 label_ids,
43 values,
44 style: PlotItemStyle::default(),
45 item_count,
46 group_count,
47 group_size: 0.67,
48 shift: 0.0,
49 flags: BarGroupsFlags::NONE,
50 item_flags: ItemFlags::NONE,
51 }
52 }
53
54 pub fn with_group_size(mut self, group_size: f64) -> Self {
56 self.group_size = group_size;
57 self
58 }
59
60 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
62 self.style = style;
63 self
64 }
65
66 pub fn with_shift(mut self, shift: f64) -> Self {
68 self.shift = shift;
69 self
70 }
71
72 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
74 self.flags = flags;
75 self
76 }
77
78 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
80 self.item_flags = flags;
81 self
82 }
83
84 pub fn horizontal(mut self) -> Self {
86 self.flags |= BarGroupsFlags::HORIZONTAL;
87 self
88 }
89
90 pub fn stacked(mut self) -> Self {
92 self.flags |= BarGroupsFlags::STACKED;
93 self
94 }
95
96 pub fn validate(&self) -> Result<(), PlotError> {
98 if self.label_ids.len() != self.item_count {
99 return Err(PlotError::InvalidData(format!(
100 "Label count ({}) must match item count ({})",
101 self.label_ids.len(),
102 self.item_count
103 )));
104 }
105
106 let expected_values = self.item_count * self.group_count;
107 if self.values.len() != expected_values {
108 return Err(PlotError::InvalidData(format!(
109 "Values length ({}) must equal item_count * group_count ({})",
110 self.values.len(),
111 expected_values
112 )));
113 }
114
115 if self.item_count == 0 || self.group_count == 0 {
116 return Err(PlotError::EmptyData);
117 }
118
119 Ok(())
120 }
121
122 pub fn plot(self) {
124 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
125 let spec = plot_spec_with_style(
126 self.style,
127 self.flags.bits() | self.item_flags.bits(),
128 PlotDataLayout::DEFAULT,
129 );
130 sys::ImPlot_PlotBarGroups_doublePtr(
131 label_ptrs.as_ptr(),
132 self.values.as_ptr(),
133 self.item_count as i32,
134 self.group_count as i32,
135 self.group_size,
136 self.shift,
137 spec,
138 );
139 })
140 }
141}
142
143impl<'a> PlotData for BarGroupsPlot<'a> {
144 fn label(&self) -> &str {
145 "BarGroups" }
147
148 fn data_len(&self) -> usize {
149 self.values.len()
150 }
151}
152
153pub struct BarGroupsPlotF32<'a> {
155 label_ids: Vec<&'a str>,
156 values: &'a [f32],
157 style: PlotItemStyle,
158 item_count: usize,
159 group_count: usize,
160 group_size: f64,
161 shift: f64,
162 flags: BarGroupsFlags,
163 item_flags: ItemFlags,
164}
165
166impl<'a> super::PlotItemStyled for BarGroupsPlotF32<'a> {
167 fn style_mut(&mut self) -> &mut PlotItemStyle {
168 &mut self.style
169 }
170}
171
172impl<'a> BarGroupsPlotF32<'a> {
173 pub fn new(
175 label_ids: Vec<&'a str>,
176 values: &'a [f32],
177 item_count: usize,
178 group_count: usize,
179 ) -> Self {
180 Self {
181 label_ids,
182 values,
183 style: PlotItemStyle::default(),
184 item_count,
185 group_count,
186 group_size: 0.67,
187 shift: 0.0,
188 flags: BarGroupsFlags::NONE,
189 item_flags: ItemFlags::NONE,
190 }
191 }
192
193 pub fn with_group_size(mut self, group_size: f64) -> Self {
195 self.group_size = group_size;
196 self
197 }
198
199 pub fn with_style(mut self, style: PlotItemStyle) -> Self {
201 self.style = style;
202 self
203 }
204
205 pub fn with_shift(mut self, shift: f64) -> Self {
207 self.shift = shift;
208 self
209 }
210
211 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
213 self.flags = flags;
214 self
215 }
216
217 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
219 self.item_flags = flags;
220 self
221 }
222
223 pub fn horizontal(mut self) -> Self {
225 self.flags |= BarGroupsFlags::HORIZONTAL;
226 self
227 }
228
229 pub fn stacked(mut self) -> Self {
231 self.flags |= BarGroupsFlags::STACKED;
232 self
233 }
234
235 pub fn validate(&self) -> Result<(), PlotError> {
237 if self.label_ids.len() != self.item_count {
238 return Err(PlotError::InvalidData(format!(
239 "Label count ({}) must match item count ({})",
240 self.label_ids.len(),
241 self.item_count
242 )));
243 }
244
245 let expected_values = self.item_count * self.group_count;
246 if self.values.len() != expected_values {
247 return Err(PlotError::InvalidData(format!(
248 "Values length ({}) must equal item_count * group_count ({})",
249 self.values.len(),
250 expected_values
251 )));
252 }
253
254 if self.item_count == 0 || self.group_count == 0 {
255 return Err(PlotError::EmptyData);
256 }
257
258 Ok(())
259 }
260
261 pub fn plot(self) {
263 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
264 let spec = plot_spec_with_style(
265 self.style,
266 self.flags.bits() | self.item_flags.bits(),
267 PlotDataLayout::DEFAULT,
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}