use super::{PlotData, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_slice};
use crate::{BarGroupsFlags, ItemFlags, sys};
pub struct BarGroupsPlot<'a> {
label_ids: Vec<&'a str>,
values: &'a [f64],
style: PlotItemStyle,
item_count: usize,
group_count: usize,
group_size: f64,
shift: f64,
flags: BarGroupsFlags,
item_flags: ItemFlags,
}
impl<'a> super::PlotItemStyled for BarGroupsPlot<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> BarGroupsPlot<'a> {
pub fn new(
label_ids: Vec<&'a str>,
values: &'a [f64],
item_count: usize,
group_count: usize,
) -> Self {
Self {
label_ids,
values,
style: PlotItemStyle::default(),
item_count,
group_count,
group_size: 0.67,
shift: 0.0,
flags: BarGroupsFlags::NONE,
item_flags: ItemFlags::NONE,
}
}
pub fn with_group_size(mut self, group_size: f64) -> Self {
self.group_size = group_size;
self
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn with_shift(mut self, shift: f64) -> Self {
self.shift = shift;
self
}
pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
self.flags = flags;
self
}
pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
self.item_flags = flags;
self
}
pub fn horizontal(mut self) -> Self {
self.flags |= BarGroupsFlags::HORIZONTAL;
self
}
pub fn stacked(mut self) -> Self {
self.flags |= BarGroupsFlags::STACKED;
self
}
pub fn validate(&self) -> Result<(), PlotError> {
if self.label_ids.len() != self.item_count {
return Err(PlotError::InvalidData(format!(
"Label count ({}) must match item count ({})",
self.label_ids.len(),
self.item_count
)));
}
let expected_values = self.item_count * self.group_count;
if self.values.len() != expected_values {
return Err(PlotError::InvalidData(format!(
"Values length ({}) must equal item_count * group_count ({})",
self.values.len(),
expected_values
)));
}
if self.item_count == 0 || self.group_count == 0 {
return Err(PlotError::EmptyData);
}
Ok(())
}
pub fn plot(self) {
with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
let spec = plot_spec_with_style(
self.style,
self.flags.bits() | self.item_flags.bits(),
0,
crate::IMPLOT_AUTO,
);
sys::ImPlot_PlotBarGroups_doublePtr(
label_ptrs.as_ptr(),
self.values.as_ptr(),
self.item_count as i32,
self.group_count as i32,
self.group_size,
self.shift,
spec,
);
})
}
}
impl<'a> PlotData for BarGroupsPlot<'a> {
fn label(&self) -> &str {
"BarGroups" }
fn data_len(&self) -> usize {
self.values.len()
}
}
pub struct BarGroupsPlotF32<'a> {
label_ids: Vec<&'a str>,
values: &'a [f32],
style: PlotItemStyle,
item_count: usize,
group_count: usize,
group_size: f64,
shift: f64,
flags: BarGroupsFlags,
item_flags: ItemFlags,
}
impl<'a> super::PlotItemStyled for BarGroupsPlotF32<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> BarGroupsPlotF32<'a> {
pub fn new(
label_ids: Vec<&'a str>,
values: &'a [f32],
item_count: usize,
group_count: usize,
) -> Self {
Self {
label_ids,
values,
style: PlotItemStyle::default(),
item_count,
group_count,
group_size: 0.67,
shift: 0.0,
flags: BarGroupsFlags::NONE,
item_flags: ItemFlags::NONE,
}
}
pub fn with_group_size(mut self, group_size: f64) -> Self {
self.group_size = group_size;
self
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn with_shift(mut self, shift: f64) -> Self {
self.shift = shift;
self
}
pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
self.flags = flags;
self
}
pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
self.item_flags = flags;
self
}
pub fn horizontal(mut self) -> Self {
self.flags |= BarGroupsFlags::HORIZONTAL;
self
}
pub fn stacked(mut self) -> Self {
self.flags |= BarGroupsFlags::STACKED;
self
}
pub fn validate(&self) -> Result<(), PlotError> {
if self.label_ids.len() != self.item_count {
return Err(PlotError::InvalidData(format!(
"Label count ({}) must match item count ({})",
self.label_ids.len(),
self.item_count
)));
}
let expected_values = self.item_count * self.group_count;
if self.values.len() != expected_values {
return Err(PlotError::InvalidData(format!(
"Values length ({}) must equal item_count * group_count ({})",
self.values.len(),
expected_values
)));
}
if self.item_count == 0 || self.group_count == 0 {
return Err(PlotError::EmptyData);
}
Ok(())
}
pub fn plot(self) {
with_plot_str_slice(&self.label_ids, |label_ptrs| unsafe {
let spec = plot_spec_with_style(
self.style,
self.flags.bits() | self.item_flags.bits(),
0,
crate::IMPLOT_AUTO,
);
sys::ImPlot_PlotBarGroups_FloatPtr(
label_ptrs.as_ptr(),
self.values.as_ptr(),
self.item_count as i32,
self.group_count as i32,
self.group_size,
self.shift,
spec,
);
})
}
}
impl<'a> PlotData for BarGroupsPlotF32<'a> {
fn label(&self) -> &str {
"BarGroups" }
fn data_len(&self) -> usize {
self.values.len()
}
}
pub struct SimpleBarGroupsPlot<'a> {
labels: Vec<&'a str>,
data: Vec<Vec<f64>>,
style: PlotItemStyle,
group_size: f64,
flags: BarGroupsFlags,
item_flags: ItemFlags,
}
impl<'a> super::PlotItemStyled for SimpleBarGroupsPlot<'a> {
fn style_mut(&mut self) -> &mut PlotItemStyle {
&mut self.style
}
}
impl<'a> SimpleBarGroupsPlot<'a> {
pub fn new(labels: Vec<&'a str>, data: Vec<Vec<f64>>) -> Self {
Self {
labels,
data,
style: PlotItemStyle::default(),
group_size: 0.67,
flags: BarGroupsFlags::NONE,
item_flags: ItemFlags::NONE,
}
}
pub fn with_style(mut self, style: PlotItemStyle) -> Self {
self.style = style;
self
}
pub fn with_group_size(mut self, group_size: f64) -> Self {
self.group_size = group_size;
self
}
pub fn with_flags(mut self, flags: BarGroupsFlags) -> Self {
self.flags = flags;
self
}
pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
self.item_flags = flags;
self
}
pub fn horizontal(mut self) -> Self {
self.flags |= BarGroupsFlags::HORIZONTAL;
self
}
pub fn stacked(mut self) -> Self {
self.flags |= BarGroupsFlags::STACKED;
self
}
pub fn plot(self) {
if self.data.is_empty() || self.labels.is_empty() {
return;
}
let item_count = self.data.len();
let group_count = self.data[0].len();
let mut flattened_data = Vec::with_capacity(item_count * group_count);
for group_idx in 0..group_count {
for item_idx in 0..item_count {
if group_idx < self.data[item_idx].len() {
flattened_data.push(self.data[item_idx][group_idx]);
} else {
flattened_data.push(0.0); }
}
}
let plot = BarGroupsPlot::new(self.labels, &flattened_data, item_count, group_count)
.with_style(self.style)
.with_group_size(self.group_size)
.with_flags(self.flags)
.with_item_flags(self.item_flags);
plot.plot();
}
}