1use super::{Plot, PlotError, plot_spec_from, 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 bins: i32,
12 bar_scale: f64,
13 range: Option<sys::ImPlotRange>,
14 flags: HistogramFlags,
15 item_flags: ItemFlags,
16}
17
18impl<'a> HistogramPlot<'a> {
19 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
21 Self {
22 label,
23 values,
24 bins: BinMethod::Sturges as i32,
25 bar_scale: 1.0,
26 range: None, flags: HistogramFlags::NONE,
28 item_flags: ItemFlags::NONE,
29 }
30 }
31
32 pub fn with_bins(mut self, bins: i32) -> Self {
39 self.bins = bins;
40 self
41 }
42
43 pub fn with_bar_scale(mut self, scale: f64) -> Self {
45 self.bar_scale = scale;
46 self
47 }
48
49 pub fn with_range(mut self, min: f64, max: f64) -> Self {
52 self.range = Some(sys::ImPlotRange { Min: min, Max: max });
53 self
54 }
55
56 pub fn with_range_struct(mut self, range: sys::ImPlotRange) -> Self {
58 self.range = Some(range);
59 self
60 }
61
62 pub fn with_flags(mut self, flags: HistogramFlags) -> Self {
64 self.flags = flags;
65 self
66 }
67
68 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
70 self.item_flags = flags;
71 self
72 }
73
74 pub fn horizontal(mut self) -> Self {
76 self.flags |= HistogramFlags::HORIZONTAL;
77 self
78 }
79
80 pub fn cumulative(mut self) -> Self {
82 self.flags |= HistogramFlags::CUMULATIVE;
83 self
84 }
85
86 pub fn density(mut self) -> Self {
88 self.flags |= HistogramFlags::DENSITY;
89 self
90 }
91
92 pub fn no_outliers(mut self) -> Self {
94 self.flags |= HistogramFlags::NO_OUTLIERS;
95 self
96 }
97
98 pub fn validate(&self) -> Result<(), PlotError> {
100 if self.values.is_empty() {
101 return Err(PlotError::EmptyData);
102 }
103 Ok(())
104 }
105}
106
107impl<'a> Plot for HistogramPlot<'a> {
108 fn plot(&self) {
109 if self.validate().is_err() {
110 return;
111 }
112 let Ok(count) = i32::try_from(self.values.len()) else {
113 return;
114 };
115
116 let range = if let Some(range) = &self.range {
117 *range
118 } else {
119 sys::ImPlotRange { Min: 0.0, Max: 0.0 }
120 };
121
122 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
123 let spec = plot_spec_from(
124 self.flags.bits() | self.item_flags.bits(),
125 0,
126 crate::IMPLOT_AUTO,
127 );
128 sys::ImPlot_PlotHistogram_doublePtr(
129 label_ptr,
130 self.values.as_ptr(),
131 count,
132 self.bins,
133 self.bar_scale,
134 range,
135 spec,
136 );
137 })
138 }
139
140 fn label(&self) -> &str {
141 self.label
142 }
143}
144
145pub struct Histogram2DPlot<'a> {
147 label: &'a str,
148 x_values: &'a [f64],
149 y_values: &'a [f64],
150 x_bins: i32,
151 y_bins: i32,
152 range: Option<sys::ImPlotRect>,
153 flags: HistogramFlags,
154 item_flags: ItemFlags,
155}
156
157impl<'a> Histogram2DPlot<'a> {
158 pub fn new(label: &'a str, x_values: &'a [f64], y_values: &'a [f64]) -> Self {
160 Self {
161 label,
162 x_values,
163 y_values,
164 x_bins: BinMethod::Sturges as i32,
165 y_bins: BinMethod::Sturges as i32,
166 range: None, flags: HistogramFlags::NONE,
168 item_flags: ItemFlags::NONE,
169 }
170 }
171
172 pub fn with_bins(mut self, x_bins: i32, y_bins: i32) -> Self {
174 self.x_bins = x_bins;
175 self.y_bins = y_bins;
176 self
177 }
178
179 pub fn with_range(mut self, x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
181 self.range = Some(sys::ImPlotRect {
182 X: sys::ImPlotRange {
183 Min: x_min,
184 Max: x_max,
185 },
186 Y: sys::ImPlotRange {
187 Min: y_min,
188 Max: y_max,
189 },
190 });
191 self
192 }
193
194 pub fn with_range_struct(mut self, range: sys::ImPlotRect) -> Self {
196 self.range = Some(range);
197 self
198 }
199
200 pub fn with_flags(mut self, flags: HistogramFlags) -> Self {
202 self.flags = flags;
203 self
204 }
205
206 pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
208 self.item_flags = flags;
209 self
210 }
211
212 pub fn density(mut self) -> Self {
214 self.flags |= HistogramFlags::DENSITY;
215 self
216 }
217
218 pub fn no_outliers(mut self) -> Self {
220 self.flags |= HistogramFlags::NO_OUTLIERS;
221 self
222 }
223
224 pub fn column_major(mut self) -> Self {
226 self.flags |= HistogramFlags::COL_MAJOR;
227 self
228 }
229
230 pub fn validate(&self) -> Result<(), PlotError> {
232 super::validate_data_lengths(self.x_values, self.y_values)
233 }
234}
235
236impl<'a> Plot for Histogram2DPlot<'a> {
237 fn plot(&self) {
238 if self.validate().is_err() {
239 return;
240 }
241 let Ok(count) = i32::try_from(self.x_values.len()) else {
242 return;
243 };
244
245 let range = if let Some(range) = &self.range {
246 *range
247 } else {
248 sys::ImPlotRect {
249 X: sys::ImPlotRange { Min: 0.0, Max: 0.0 },
250 Y: sys::ImPlotRange { Min: 0.0, Max: 0.0 },
251 }
252 };
253
254 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
255 let spec = plot_spec_from(
256 self.flags.bits() | self.item_flags.bits(),
257 0,
258 crate::IMPLOT_AUTO,
259 );
260 sys::ImPlot_PlotHistogram2D_doublePtr(
261 label_ptr,
262 self.x_values.as_ptr(),
263 self.y_values.as_ptr(),
264 count,
265 self.x_bins,
266 self.y_bins,
267 range,
268 spec,
269 );
270 })
271 }
272
273 fn label(&self) -> &str {
274 self.label
275 }
276}
277
278impl<'ui> crate::PlotUi<'ui> {
280 pub fn histogram_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
282 let plot = HistogramPlot::new(label, values);
283 plot.validate()?;
284 plot.plot();
285 Ok(())
286 }
287
288 pub fn histogram_plot_with_bins(
290 &self,
291 label: &str,
292 values: &[f64],
293 bins: i32,
294 ) -> Result<(), PlotError> {
295 let plot = HistogramPlot::new(label, values).with_bins(bins);
296 plot.validate()?;
297 plot.plot();
298 Ok(())
299 }
300
301 pub fn histogram_2d_plot(
303 &self,
304 label: &str,
305 x_values: &[f64],
306 y_values: &[f64],
307 ) -> Result<(), PlotError> {
308 let plot = Histogram2DPlot::new(label, x_values, y_values);
309 plot.validate()?;
310 plot.plot();
311 Ok(())
312 }
313
314 pub fn histogram_2d_plot_with_bins(
316 &self,
317 label: &str,
318 x_values: &[f64],
319 y_values: &[f64],
320 x_bins: i32,
321 y_bins: i32,
322 ) -> Result<(), PlotError> {
323 let plot = Histogram2DPlot::new(label, x_values, y_values).with_bins(x_bins, y_bins);
324 plot.validate()?;
325 plot.plot();
326 Ok(())
327 }
328}