1use super::{Plot, PlotError, safe_cstring};
4use crate::sys;
5use crate::{BinMethod, HistogramFlags};
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}
16
17impl<'a> HistogramPlot<'a> {
18 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
20 Self {
21 label,
22 values,
23 bins: BinMethod::Sturges as i32,
24 bar_scale: 1.0,
25 range: None, flags: HistogramFlags::NONE,
27 }
28 }
29
30 pub fn with_bins(mut self, bins: i32) -> Self {
37 self.bins = bins;
38 self
39 }
40
41 pub fn with_bar_scale(mut self, scale: f64) -> Self {
43 self.bar_scale = scale;
44 self
45 }
46
47 pub fn with_range(mut self, min: f64, max: f64) -> Self {
50 self.range = Some(sys::ImPlotRange { Min: min, Max: max });
51 self
52 }
53
54 pub fn with_range_struct(mut self, range: sys::ImPlotRange) -> Self {
56 self.range = Some(range);
57 self
58 }
59
60 pub fn with_flags(mut self, flags: HistogramFlags) -> Self {
62 self.flags = flags;
63 self
64 }
65
66 pub fn horizontal(mut self) -> Self {
68 self.flags |= HistogramFlags::HORIZONTAL;
69 self
70 }
71
72 pub fn cumulative(mut self) -> Self {
74 self.flags |= HistogramFlags::CUMULATIVE;
75 self
76 }
77
78 pub fn density(mut self) -> Self {
80 self.flags |= HistogramFlags::DENSITY;
81 self
82 }
83
84 pub fn no_outliers(mut self) -> Self {
86 self.flags |= HistogramFlags::NO_OUTLIERS;
87 self
88 }
89
90 pub fn validate(&self) -> Result<(), PlotError> {
92 if self.values.is_empty() {
93 return Err(PlotError::EmptyData);
94 }
95 Ok(())
96 }
97}
98
99impl<'a> Plot for HistogramPlot<'a> {
100 fn plot(&self) {
101 if self.validate().is_err() {
102 return;
103 }
104
105 let label_cstr = safe_cstring(self.label);
106
107 let range = if let Some(range) = &self.range {
108 *range
109 } else {
110 sys::ImPlotRange { Min: 0.0, Max: 0.0 }
111 };
112
113 unsafe {
114 sys::ImPlot_PlotHistogram_doublePtr(
115 label_cstr.as_ptr(),
116 self.values.as_ptr(),
117 self.values.len() as i32,
118 self.bins,
119 self.bar_scale,
120 range,
121 self.flags.bits() as i32,
122 );
123 }
124 }
125
126 fn label(&self) -> &str {
127 self.label
128 }
129}
130
131pub struct Histogram2DPlot<'a> {
133 label: &'a str,
134 x_values: &'a [f64],
135 y_values: &'a [f64],
136 x_bins: i32,
137 y_bins: i32,
138 range: Option<sys::ImPlotRect>,
139 flags: HistogramFlags,
140}
141
142impl<'a> Histogram2DPlot<'a> {
143 pub fn new(label: &'a str, x_values: &'a [f64], y_values: &'a [f64]) -> Self {
145 Self {
146 label,
147 x_values,
148 y_values,
149 x_bins: BinMethod::Sturges as i32,
150 y_bins: BinMethod::Sturges as i32,
151 range: None, flags: HistogramFlags::NONE,
153 }
154 }
155
156 pub fn with_bins(mut self, x_bins: i32, y_bins: i32) -> Self {
158 self.x_bins = x_bins;
159 self.y_bins = y_bins;
160 self
161 }
162
163 pub fn with_range(mut self, x_min: f64, x_max: f64, y_min: f64, y_max: f64) -> Self {
165 self.range = Some(sys::ImPlotRect {
166 X: sys::ImPlotRange {
167 Min: x_min,
168 Max: x_max,
169 },
170 Y: sys::ImPlotRange {
171 Min: y_min,
172 Max: y_max,
173 },
174 });
175 self
176 }
177
178 pub fn with_range_struct(mut self, range: sys::ImPlotRect) -> Self {
180 self.range = Some(range);
181 self
182 }
183
184 pub fn with_flags(mut self, flags: HistogramFlags) -> Self {
186 self.flags = flags;
187 self
188 }
189
190 pub fn density(mut self) -> Self {
192 self.flags |= HistogramFlags::DENSITY;
193 self
194 }
195
196 pub fn no_outliers(mut self) -> Self {
198 self.flags |= HistogramFlags::NO_OUTLIERS;
199 self
200 }
201
202 pub fn column_major(mut self) -> Self {
204 self.flags |= HistogramFlags::COL_MAJOR;
205 self
206 }
207
208 pub fn validate(&self) -> Result<(), PlotError> {
210 super::validate_data_lengths(self.x_values, self.y_values)
211 }
212}
213
214impl<'a> Plot for Histogram2DPlot<'a> {
215 fn plot(&self) {
216 if self.validate().is_err() {
217 return;
218 }
219
220 let label_cstr = safe_cstring(self.label);
221
222 let range = if let Some(range) = &self.range {
223 *range
224 } else {
225 sys::ImPlotRect {
226 X: sys::ImPlotRange { Min: 0.0, Max: 0.0 },
227 Y: sys::ImPlotRange { Min: 0.0, Max: 0.0 },
228 }
229 };
230
231 unsafe {
232 sys::ImPlot_PlotHistogram2D_doublePtr(
233 label_cstr.as_ptr(),
234 self.x_values.as_ptr(),
235 self.y_values.as_ptr(),
236 self.x_values.len() as i32,
237 self.x_bins,
238 self.y_bins,
239 range,
240 self.flags.bits() as i32,
241 );
242 }
243 }
244
245 fn label(&self) -> &str {
246 self.label
247 }
248}
249
250impl<'ui> crate::PlotUi<'ui> {
252 pub fn histogram_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
254 let plot = HistogramPlot::new(label, values);
255 plot.validate()?;
256 plot.plot();
257 Ok(())
258 }
259
260 pub fn histogram_plot_with_bins(
262 &self,
263 label: &str,
264 values: &[f64],
265 bins: i32,
266 ) -> Result<(), PlotError> {
267 let plot = HistogramPlot::new(label, values).with_bins(bins);
268 plot.validate()?;
269 plot.plot();
270 Ok(())
271 }
272
273 pub fn histogram_2d_plot(
275 &self,
276 label: &str,
277 x_values: &[f64],
278 y_values: &[f64],
279 ) -> Result<(), PlotError> {
280 let plot = Histogram2DPlot::new(label, x_values, y_values);
281 plot.validate()?;
282 plot.plot();
283 Ok(())
284 }
285
286 pub fn histogram_2d_plot_with_bins(
288 &self,
289 label: &str,
290 x_values: &[f64],
291 y_values: &[f64],
292 x_bins: i32,
293 y_bins: i32,
294 ) -> Result<(), PlotError> {
295 let plot = Histogram2DPlot::new(label, x_values, y_values).with_bins(x_bins, y_bins);
296 plot.validate()?;
297 plot.plot();
298 Ok(())
299 }
300}