1use super::{Plot, PlotError, PlotItemStyle, plot_spec_with_style, with_plot_str_or_empty};
4use crate::sys;
5use crate::{BinMethod, HistogramFlags, ItemFlags};
6
7pub struct HistogramPlot<'a> {
9 label: &'a str,
10 values: &'a [f64],
11 style: PlotItemStyle,
12 bins: i32,
13 bar_scale: f64,
14 range: Option<sys::ImPlotRange>,
15 flags: HistogramFlags,
16 item_flags: ItemFlags,
17}
18
19impl<'a> super::PlotItemStyled for HistogramPlot<'a> {
20 fn style_mut(&mut self) -> &mut PlotItemStyle {
21 &mut self.style
22 }
23}
24
25impl<'a> HistogramPlot<'a> {
26 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
28 Self {
29 label,
30 values,
31 style: PlotItemStyle::default(),
32 bins: BinMethod::Sturges as i32,
33 bar_scale: 1.0,
34 range: None, flags: HistogramFlags::NONE,
36 item_flags: ItemFlags::NONE,
37 }
38 }
39
40 pub fn with_bins(mut self, bins: i32) -> Self {
47 self.bins = bins;
48 self
49 }
50
51 pub fn with_bar_scale(mut self, scale: f64) -> Self {
53 self.bar_scale = scale;
54 self
55 }
56
57 pub fn with_range(mut self, min: f64, max: f64) -> Self {
60 self.range = Some(sys::ImPlotRange { Min: min, Max: max });
61 self
62 }
63
64 pub fn with_range_struct(mut self, range: sys::ImPlotRange) -> Self {
66 self.range = Some(range);
67 self
68 }
69
70 pub fn with_flags(mut self, flags: HistogramFlags) -> 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 |= HistogramFlags::HORIZONTAL;
85 self
86 }
87
88 pub fn cumulative(mut self) -> Self {
90 self.flags |= HistogramFlags::CUMULATIVE;
91 self
92 }
93
94 pub fn density(mut self) -> Self {
96 self.flags |= HistogramFlags::DENSITY;
97 self
98 }
99
100 pub fn no_outliers(mut self) -> Self {
102 self.flags |= HistogramFlags::NO_OUTLIERS;
103 self
104 }
105
106 pub fn validate(&self) -> Result<(), PlotError> {
108 if self.values.is_empty() {
109 return Err(PlotError::EmptyData);
110 }
111 Ok(())
112 }
113}
114
115impl<'a> Plot for HistogramPlot<'a> {
116 fn plot(&self) {
117 if self.validate().is_err() {
118 return;
119 }
120 let Ok(count) = i32::try_from(self.values.len()) else {
121 return;
122 };
123
124 let range = if let Some(range) = &self.range {
125 *range
126 } else {
127 sys::ImPlotRange { Min: 0.0, Max: 0.0 }
128 };
129
130 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
131 let spec = plot_spec_with_style(
132 self.style,
133 self.flags.bits() | self.item_flags.bits(),
134 0,
135 crate::IMPLOT_AUTO,
136 );
137 sys::ImPlot_PlotHistogram_doublePtr(
138 label_ptr,
139 self.values.as_ptr(),
140 count,
141 self.bins,
142 self.bar_scale,
143 range,
144 spec,
145 );
146 })
147 }
148
149 fn label(&self) -> &str {
150 self.label
151 }
152}
153
154pub struct Histogram2DPlot<'a> {
156 label: &'a str,
157 x_values: &'a [f64],
158 y_values: &'a [f64],
159 style: PlotItemStyle,
160 x_bins: i32,
161 y_bins: i32,
162 range: Option<sys::ImPlotRect>,
163 flags: HistogramFlags,
164 item_flags: ItemFlags,
165}
166
167impl<'a> super::PlotItemStyled for Histogram2DPlot<'a> {
168 fn style_mut(&mut self) -> &mut PlotItemStyle {
169 &mut self.style
170 }
171}
172
173impl<'a> Histogram2DPlot<'a> {
174 pub fn new(label: &'a str, x_values: &'a [f64], y_values: &'a [f64]) -> Self {
176 Self {
177 label,
178 x_values,
179 y_values,
180 style: PlotItemStyle::default(),
181 x_bins: BinMethod::Sturges as i32,
182 y_bins: BinMethod::Sturges as i32,
183 range: None, flags: HistogramFlags::NONE,
185 item_flags: ItemFlags::NONE,
186 }
187 }
188
189 pub fn with_bins(mut self, x_bins: i32, y_bins: i32) -> Self {
191 self.x_bins = x_bins;
192 self.y_bins = y_bins;
193 self
194 }
195
196 pub fn with_range(mut self, x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
198 self.range = Some(sys::ImPlotRect {
199 X: sys::ImPlotRange {
200 Min: x_min,
201 Max: x_max,
202 },
203 Y: sys::ImPlotRange {
204 Min: y_min,
205 Max: y_max,
206 },
207 });
208 self
209 }
210
211 pub fn with_range_struct(mut self, range: sys::ImPlotRect) -> Self {
213 self.range = Some(range);
214 self
215 }
216
217 pub fn with_flags(mut self, flags: HistogramFlags) -> Self {
219 self.flags = flags;
220 self
221 }
222
223 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
225 self.item_flags = flags;
226 self
227 }
228
229 pub fn density(mut self) -> Self {
231 self.flags |= HistogramFlags::DENSITY;
232 self
233 }
234
235 pub fn no_outliers(mut self) -> Self {
237 self.flags |= HistogramFlags::NO_OUTLIERS;
238 self
239 }
240
241 pub fn column_major(mut self) -> Self {
243 self.flags |= HistogramFlags::COL_MAJOR;
244 self
245 }
246
247 pub fn validate(&self) -> Result<(), PlotError> {
249 super::validate_data_lengths(self.x_values, self.y_values)
250 }
251}
252
253impl<'a> Plot for Histogram2DPlot<'a> {
254 fn plot(&self) {
255 if self.validate().is_err() {
256 return;
257 }
258 let Ok(count) = i32::try_from(self.x_values.len()) else {
259 return;
260 };
261
262 let range = if let Some(range) = &self.range {
263 *range
264 } else {
265 sys::ImPlotRect {
266 X: sys::ImPlotRange { Min: 0.0, Max: 0.0 },
267 Y: sys::ImPlotRange { Min: 0.0, Max: 0.0 },
268 }
269 };
270
271 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
272 let spec = plot_spec_with_style(
273 self.style,
274 self.flags.bits() | self.item_flags.bits(),
275 0,
276 crate::IMPLOT_AUTO,
277 );
278 sys::ImPlot_PlotHistogram2D_doublePtr(
279 label_ptr,
280 self.x_values.as_ptr(),
281 self.y_values.as_ptr(),
282 count,
283 self.x_bins,
284 self.y_bins,
285 range,
286 spec,
287 );
288 })
289 }
290
291 fn label(&self) -> &str {
292 self.label
293 }
294}
295
296impl<'ui> crate::PlotUi<'ui> {
298 pub fn histogram_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
300 let plot = HistogramPlot::new(label, values);
301 plot.validate()?;
302 plot.plot();
303 Ok(())
304 }
305
306 pub fn histogram_plot_with_bins(
308 &self,
309 label: &str,
310 values: &[f64],
311 bins: i32,
312 ) -> Result<(), PlotError> {
313 let plot = HistogramPlot::new(label, values).with_bins(bins);
314 plot.validate()?;
315 plot.plot();
316 Ok(())
317 }
318
319 pub fn histogram_2d_plot(
321 &self,
322 label: &str,
323 x_values: &[f64],
324 y_values: &[f64],
325 ) -> Result<(), PlotError> {
326 let plot = Histogram2DPlot::new(label, x_values, y_values);
327 plot.validate()?;
328 plot.plot();
329 Ok(())
330 }
331
332 pub fn histogram_2d_plot_with_bins(
334 &self,
335 label: &str,
336 x_values: &[f64],
337 y_values: &[f64],
338 x_bins: i32,
339 y_bins: i32,
340 ) -> Result<(), PlotError> {
341 let plot = Histogram2DPlot::new(label, x_values, y_values).with_bins(x_bins, y_bins);
342 plot.validate()?;
343 plot.plot();
344 Ok(())
345 }
346}