dear_implot/plots/
bar_groups.rs1use super::{PlotData, PlotError, with_plot_str_slice};
4use crate::BarGroupsFlags;
5use crate::sys;
6
7pub struct BarGroupsPlot<'a> {
9 label_ids: Vec<&'a str>,
10 values: &'a [f64],
11 item_count: usize,
12 group_count: usize,
13 group_size: f64,
14 shift: f64,
15 flags: BarGroupsFlags,
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 }
41 }
42
43 pub fn with_group_size(mut self, group_size: f64) -> Self {
45 self.group_size = group_size;
46 self
47 }
48
49 pub fn with_shift(mut self, shift: f64) -> Self {
51 self.shift = shift;
52 self
53 }
54
55 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
57 self.flags = flags;
58 self
59 }
60
61 pub fn horizontal(mut self) -> Self {
63 self.flags |= BarGroupsFlags::HORIZONTAL;
64 self
65 }
66
67 pub fn stacked(mut self) -> Self {
69 self.flags |= BarGroupsFlags::STACKED;
70 self
71 }
72
73 pub fn validate(&self) -> Result<(), PlotError> {
75 if self.label_ids.len() != self.item_count {
76 return Err(PlotError::InvalidData(format!(
77 "Label count ({}) must match item count ({})",
78 self.label_ids.len(),
79 self.item_count
80 )));
81 }
82
83 let expected_values = self.item_count * self.group_count;
84 if self.values.len() != expected_values {
85 return Err(PlotError::InvalidData(format!(
86 "Values length ({}) must equal item_count * group_count ({})",
87 self.values.len(),
88 expected_values
89 )));
90 }
91
92 if self.item_count == 0 || self.group_count == 0 {
93 return Err(PlotError::EmptyData);
94 }
95
96 Ok(())
97 }
98
99 pub fn plot(self) {
101 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
102 sys::ImPlot_PlotBarGroups_doublePtr(
103 label_ptrs.as_ptr(),
104 self.values.as_ptr(),
105 self.item_count as i32,
106 self.group_count as i32,
107 self.group_size,
108 self.shift,
109 self.flags.bits() as i32,
110 );
111 })
112 }
113}
114
115impl<'a> PlotData for BarGroupsPlot<'a> {
116 fn label(&self) -> &str {
117 "BarGroups" }
119
120 fn data_len(&self) -> usize {
121 self.values.len()
122 }
123}
124
125pub struct BarGroupsPlotF32<'a> {
127 label_ids: Vec<&'a str>,
128 values: &'a [f32],
129 item_count: usize,
130 group_count: usize,
131 group_size: f64,
132 shift: f64,
133 flags: BarGroupsFlags,
134}
135
136impl<'a> BarGroupsPlotF32<'a> {
137 pub fn new(
139 label_ids: Vec<&'a str>,
140 values: &'a [f32],
141 item_count: usize,
142 group_count: usize,
143 ) -> Self {
144 Self {
145 label_ids,
146 values,
147 item_count,
148 group_count,
149 group_size: 0.67,
150 shift: 0.0,
151 flags: BarGroupsFlags::NONE,
152 }
153 }
154
155 pub fn with_group_size(mut self, group_size: f64) -> Self {
157 self.group_size = group_size;
158 self
159 }
160
161 pub fn with_shift(mut self, shift: f64) -> Self {
163 self.shift = shift;
164 self
165 }
166
167 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
169 self.flags = flags;
170 self
171 }
172
173 pub fn horizontal(mut self) -> Self {
175 self.flags |= BarGroupsFlags::HORIZONTAL;
176 self
177 }
178
179 pub fn stacked(mut self) -> Self {
181 self.flags |= BarGroupsFlags::STACKED;
182 self
183 }
184
185 pub fn validate(&self) -> Result<(), PlotError> {
187 if self.label_ids.len() != self.item_count {
188 return Err(PlotError::InvalidData(format!(
189 "Label count ({}) must match item count ({})",
190 self.label_ids.len(),
191 self.item_count
192 )));
193 }
194
195 let expected_values = self.item_count * self.group_count;
196 if self.values.len() != expected_values {
197 return Err(PlotError::InvalidData(format!(
198 "Values length ({}) must equal item_count * group_count ({})",
199 self.values.len(),
200 expected_values
201 )));
202 }
203
204 if self.item_count == 0 || self.group_count == 0 {
205 return Err(PlotError::EmptyData);
206 }
207
208 Ok(())
209 }
210
211 pub fn plot(self) {
213 with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
214 sys::ImPlot_PlotBarGroups_FloatPtr(
215 label_ptrs.as_ptr(),
216 self.values.as_ptr(),
217 self.item_count as i32,
218 self.group_count as i32,
219 self.group_size,
220 self.shift,
221 self.flags.bits() as i32,
222 );
223 })
224 }
225}
226
227impl<'a> PlotData for BarGroupsPlotF32<'a> {
228 fn label(&self) -> &str {
229 "BarGroups" }
231
232 fn data_len(&self) -> usize {
233 self.values.len()
234 }
235}
236
237pub struct SimpleBarGroupsPlot<'a> {
239 labels: Vec<&'a str>,
240 data: Vec<Vec<f64>>,
241 group_size: f64,
242 flags: BarGroupsFlags,
243}
244
245impl<'a> SimpleBarGroupsPlot<'a> {
246 pub fn new(labels: Vec<&'a str>, data: Vec<Vec<f64>>) -> Self {
252 Self {
253 labels,
254 data,
255 group_size: 0.67,
256 flags: BarGroupsFlags::NONE,
257 }
258 }
259
260 pub fn with_group_size(mut self, group_size: f64) -> Self {
262 self.group_size = group_size;
263 self
264 }
265
266 pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
268 self.flags = flags;
269 self
270 }
271
272 pub fn horizontal(mut self) -> Self {
274 self.flags |= BarGroupsFlags::HORIZONTAL;
275 self
276 }
277
278 pub fn stacked(mut self) -> Self {
280 self.flags |= BarGroupsFlags::STACKED;
281 self
282 }
283
284 pub fn plot(self) {
286 if self.data.is_empty() || self.labels.is_empty() {
287 return;
288 }
289
290 let item_count = self.data.len();
291 let group_count = self.data[0].len();
292
293 let mut flattened_data = Vec::with_capacity(item_count * group_count);
295 for group_idx in 0..group_count {
296 for item_idx in 0..item_count {
297 if group_idx < self.data[item_idx].len() {
298 flattened_data.push(self.data[item_idx][group_idx]);
299 } else {
300 flattened_data.push(0.0); }
302 }
303 }
304
305 let plot = BarGroupsPlot::new(self.labels, &flattened_data, item_count, group_count)
306 .with_group_size(self.group_size)
307 .with_flags(self.flags);
308
309 plot.plot();
310 }
311}