plotly_patched/
histogram.rs

1//! Histogram plot
2
3use crate::common::{Calendar, Dim, ErrorData, HoverInfo, Label, Marker, Orientation, PlotType};
4use crate::Trace;
5use serde::Serialize;
6
7use crate::private;
8use crate::private::copy_iterable_to_vec;
9
10#[cfg(feature = "plotly_ndarray")]
11use ndarray::{Array, Ix1, Ix2};
12#[cfg(feature = "plotly_ndarray")]
13use crate::ndarray::ArrayTraces;
14
15
16#[derive(Serialize, Clone, Debug)]
17pub struct Bins {
18    start: f64,
19    end: f64,
20    size: f64,
21}
22
23impl Bins {
24    pub fn new(start: f64, end: f64, size: f64) -> Bins {
25        Bins { start, end, size }
26    }
27}
28
29#[derive(Serialize, Clone, Debug)]
30pub enum HistFunc {
31    #[serde(rename = "count")]
32    Count,
33    #[serde(rename = "sum")]
34    Sum,
35    #[serde(rename = "avg")]
36    Average,
37    #[serde(rename = "min")]
38    Minimum,
39    #[serde(rename = "max")]
40    Maximum,
41}
42
43#[derive(Serialize, Clone, Debug)]
44pub enum HistNorm {
45    #[serde(rename = "")]
46    Default,
47    #[serde(rename = "percent")]
48    Percent,
49    #[serde(rename = "probability")]
50    Probability,
51    #[serde(rename = "density")]
52    Density,
53    #[serde(rename = "probability density")]
54    ProbabilityDensity,
55}
56
57#[derive(Serialize, Clone, Debug)]
58pub enum HistDirection {
59    #[serde(rename = "increasing")]
60    Increasing,
61    #[serde(rename = "decreasing")]
62    Decreasing,
63}
64
65#[derive(Serialize, Clone, Debug)]
66pub enum CurrentBin {
67    #[serde(rename = "include")]
68    Include,
69    #[serde(rename = "exclude")]
70    Exclude,
71    #[serde(rename = "half")]
72    Half,
73}
74
75#[derive(Serialize, Clone, Debug, Default)]
76pub struct Cumulative {
77    #[serde(skip_serializing_if = "Option::is_none")]
78    enabled: Option<bool>,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    direction: Option<HistDirection>,
81    #[serde(skip_serializing_if = "Option::is_none", rename = "currentbin")]
82    current_bin: Option<CurrentBin>,
83}
84
85impl Cumulative {
86    pub fn new() -> Cumulative {
87        Cumulative {
88            enabled: None,
89            direction: None,
90            current_bin: None,
91        }
92    }
93
94    pub fn enabled(mut self, enabled: bool) -> Cumulative {
95        self.enabled = Some(enabled);
96        self
97    }
98
99    pub fn direction(mut self, direction: HistDirection) -> Cumulative {
100        self.direction = Some(direction);
101        self
102    }
103
104    pub fn current_bin(mut self, current_bin: CurrentBin) -> Cumulative {
105        self.current_bin = Some(current_bin);
106        self
107    }
108}
109
110#[derive(Serialize, Clone, Debug)]
111pub struct Histogram<H>
112where
113    H: Serialize + Clone + Default + 'static,
114{
115    r#type: PlotType,
116    #[serde(skip_serializing_if = "Option::is_none")]
117    name: Option<String>,
118    #[serde(skip_serializing_if = "Option::is_none")]
119    visible: Option<bool>,
120    #[serde(skip_serializing_if = "Option::is_none", rename = "showlegend")]
121    show_legend: Option<bool>,
122    #[serde(skip_serializing_if = "Option::is_none", rename = "legendgroup")]
123    legend_group: Option<String>,
124    #[serde(skip_serializing_if = "Option::is_none")]
125    opacity: Option<f64>,
126    #[serde(skip_serializing_if = "Option::is_none")]
127    x: Option<Vec<H>>,
128    #[serde(skip_serializing_if = "Option::is_none")]
129    y: Option<Vec<H>>,
130    #[serde(skip_serializing_if = "Option::is_none")]
131    text: Option<Dim<String>>,
132    #[serde(skip_serializing_if = "Option::is_none", rename = "hovertext")]
133    hover_text: Option<Dim<String>>,
134    #[serde(skip_serializing_if = "Option::is_none", rename = "hoverinfo")]
135    hover_info: Option<HoverInfo>,
136    #[serde(skip_serializing_if = "Option::is_none", rename = "hovertemplate")]
137    hover_template: Option<Dim<String>>,
138    #[serde(skip_serializing_if = "Option::is_none", rename = "xaxis")]
139    x_axis: Option<String>,
140    #[serde(skip_serializing_if = "Option::is_none", rename = "yaxis")]
141    y_axis: Option<String>,
142    orientation: Option<Orientation>,
143    #[serde(skip_serializing_if = "Option::is_none", rename = "histfunc")]
144    hist_func: Option<HistFunc>,
145    #[serde(skip_serializing_if = "Option::is_none", rename = "histnorm")]
146    hist_norm: Option<HistNorm>,
147    #[serde(skip_serializing_if = "Option::is_none", rename = "alignmentgroup")]
148    alignment_group: Option<String>,
149    #[serde(skip_serializing_if = "Option::is_none", rename = "offsetgroup")]
150    offset_group: Option<String>,
151    #[serde(skip_serializing_if = "Option::is_none", rename = "nbinsx")]
152    n_bins_x: Option<usize>,
153    #[serde(skip_serializing_if = "Option::is_none", rename = "nbinsy")]
154    n_bins_y: Option<usize>,
155    #[serde(skip_serializing_if = "Option::is_none", rename = "autobinx")]
156    auto_bin_x: Option<bool>,
157    #[serde(skip_serializing_if = "Option::is_none", rename = "autobiny")]
158    auto_bin_y: Option<bool>,
159    #[serde(skip_serializing_if = "Option::is_none", rename = "bingroup")]
160    bin_group: Option<String>,
161    #[serde(skip_serializing_if = "Option::is_none", rename = "xbins")]
162    x_bins: Option<Bins>,
163    #[serde(skip_serializing_if = "Option::is_none", rename = "ybins")]
164    y_bins: Option<Bins>,
165    #[serde(skip_serializing_if = "Option::is_none")]
166    marker: Option<Marker>,
167    #[serde(skip_serializing_if = "Option::is_none")]
168    error_x: Option<ErrorData>,
169    #[serde(skip_serializing_if = "Option::is_none")]
170    error_y: Option<ErrorData>,
171    #[serde(skip_serializing_if = "Option::is_none")]
172    cumulative: Option<Cumulative>,
173    #[serde(skip_serializing_if = "Option::is_none", rename = "hoverlabel")]
174    hover_label: Option<Label>,
175    #[serde(skip_serializing_if = "Option::is_none", rename = "xcalendar")]
176    x_calendar: Option<Calendar>,
177    #[serde(skip_serializing_if = "Option::is_none", rename = "ycalendar")]
178    y_calendar: Option<Calendar>,
179}
180
181impl<H> Default for Histogram<H>
182where
183    H: Serialize + Clone + Default + 'static,
184{
185    fn default() -> Self {
186        Histogram {
187            r#type: PlotType::Histogram,
188            name: None,
189            visible: None,
190            show_legend: None,
191            legend_group: None,
192            opacity: None,
193            x: None,
194            y: None,
195            text: None,
196            hover_text: None,
197            hover_info: None,
198            hover_template: None,
199            x_axis: None,
200            y_axis: None,
201            orientation: None,
202            hist_func: None,
203            hist_norm: None,
204            alignment_group: None,
205            offset_group: None,
206            n_bins_x: None,
207            n_bins_y: None,
208            auto_bin_x: None,
209            auto_bin_y: None,
210            bin_group: None,
211            x_bins: None,
212            y_bins: None,
213            marker: None,
214            error_x: None,
215            error_y: None,
216            cumulative: None,
217            hover_label: None,
218            x_calendar: None,
219            y_calendar: None,
220        }
221    }
222}
223
224impl<H> Histogram<H>
225where
226    H: Serialize + Clone + Default + 'static,
227{
228    pub fn new<I>(x: I) -> Box<Self>
229    where
230        I: IntoIterator<Item = H>,
231    {
232        let x = copy_iterable_to_vec(x);
233        Box::new(Histogram {
234            r#type: PlotType::Histogram,
235            x: Some(x),
236            ..Default::default()
237        })
238    }
239
240    pub fn new_xy<I>(x: I, y: I) -> Box<Self>
241    where
242        I: IntoIterator<Item = H>,
243    {
244        let x = copy_iterable_to_vec(x);
245        let y = copy_iterable_to_vec(y);
246        Box::new(Histogram {
247            r#type: PlotType::Histogram,
248            x: Some(x),
249            y: Some(y),
250            ..Default::default()
251        })
252    }
253
254    pub fn new_vertical<I>(y: I) -> Box<Self>
255    where
256        I: IntoIterator<Item = H>,
257    {
258        let y = copy_iterable_to_vec(y);
259        Box::new(Histogram {
260            r#type: PlotType::Histogram,
261            y: Some(y),
262            ..Default::default()
263        })
264    }
265
266    /// Produces `Histogram` traces from a 2 dimensional tensor (`traces_matrix`) indexed by `x`. This
267    /// function requires the `ndarray` feature.
268    ///
269    /// # Arguments
270    /// * `x`             - One dimensional array (or view) that represents the `x` axis coordinates.
271    /// * `traces_matrix` - Two dimensional array (or view) containing the `y` axis coordinates of
272    /// the traces.
273    /// * `array_traces`  - Determines whether the traces are arranged in the matrix over the
274    /// columns (`ArrayTraces::OverColumns`) or over the rows (`ArrayTraces::OverRows`).
275    ///
276    /// # Examples
277    ///
278    /// ```
279    /// use plotly::common::Mode;
280    /// use plotly::{Plot, Histogram, ArrayTraces};
281    /// use ndarray::{Array, Ix1, Ix2};
282    /// use rand_distr::{Distribution, Normal};
283    /// use plotly::Layout;
284    /// use plotly::layout::BarMode;
285    ///
286    /// fn ndarray_to_traces() {
287    ///     let n: usize = 1_250;
288    ///     let rng = rand::thread_rng();
289    ///     let t: Array<f64, Ix1> = Array::range(0., 10., 10. / n as f64);
290    ///     let mut ys: Array<f64, Ix2> = Array::zeros((n, 4));
291    ///     let mut count = 0.;
292    ///     for mut row in ys.gencolumns_mut() {
293    ///         let tmp: Vec<f64> = Normal::new(4. * count, 1.).unwrap().sample_iter(rng).take(n).collect();
294    ///         for i in 0..row.len() {
295    ///             row[i] = tmp[i];
296    ///         }
297    ///         count += 1.;
298    ///     }
299    ///
300    ///     let traces = Histogram::default()
301    ///         .opacity(0.5)
302    ///         .auto_bin_x(true)
303    ///         .to_traces(ys, ArrayTraces::OverColumns);
304    ///
305    ///     let layout = Layout::new().bar_mode(BarMode::Overlay);
306    ///
307    ///     let mut plot = Plot::new();
308    ///     plot.set_layout(layout);
309    ///     plot.add_traces(traces);
310    ///     plot.show();
311    /// }
312    /// fn main() -> std::io::Result<()> {
313    ///     ndarray_to_traces();
314    ///     Ok(())
315    /// }
316    /// ```
317    #[cfg(feature = "plotly_ndarray")]
318    pub fn to_traces(
319        &self,
320        traces_matrix: Array<H, Ix2>,
321        array_traces: ArrayTraces,
322    ) -> Vec<Box<dyn Trace>> {
323        let mut traces: Vec<Box<dyn Trace>> = Vec::new();
324        let mut trace_vectors = private::trace_vectors_from(traces_matrix, array_traces);
325        trace_vectors.reverse();
326        while !trace_vectors.is_empty() {
327            let mut sc = Box::new(self.clone());
328            let data = trace_vectors.pop();
329            if let Some(d) = data {
330                sc.x = Some(d);
331                traces.push(sc);
332            }
333        }
334
335        traces
336    }
337
338    #[cfg(feature = "plotly_ndarray")]
339    pub fn from_array(x: Array<H, Ix1>) -> Box<Self> {
340        Box::new(Histogram {
341            r#type: PlotType::Histogram,
342            x: Some(x.to_vec()),
343            ..Default::default()
344        })
345    }
346
347    pub fn name(mut self, name: &str) -> Box<Self> {
348        self.name = Some(name.to_owned());
349        Box::new(self)
350    }
351
352    pub fn visible(mut self, visible: bool) -> Box<Self> {
353        self.visible = Some(visible);
354        Box::new(self)
355    }
356
357    pub fn show_legend(mut self, show_legend: bool) -> Box<Self> {
358        self.show_legend = Some(show_legend);
359        Box::new(self)
360    }
361
362    pub fn legend_group(mut self, legend_group: &str) -> Box<Self> {
363        self.legend_group = Some(legend_group.to_owned());
364        Box::new(self)
365    }
366
367    pub fn opacity(mut self, opacity: f64) -> Box<Self> {
368        self.opacity = Some(opacity);
369        Box::new(self)
370    }
371
372    pub fn text(mut self, text: &str) -> Box<Self> {
373        self.text = Some(Dim::Scalar(text.to_owned()));
374        Box::new(self)
375    }
376
377    pub fn text_array<S: AsRef<str>>(mut self, text: Vec<S>) -> Box<Self> {
378        let text = private::owned_string_vector(text);
379        self.text = Some(Dim::Vector(text));
380        Box::new(self)
381    }
382
383    pub fn hover_text(mut self, hover_text: &str) -> Box<Self> {
384        self.hover_text = Some(Dim::Scalar(hover_text.to_owned()));
385        Box::new(self)
386    }
387
388    pub fn hover_text_array<S: AsRef<str>>(mut self, hover_text: Vec<S>) -> Box<Self> {
389        let hover_text = private::owned_string_vector(hover_text);
390        self.hover_text = Some(Dim::Vector(hover_text));
391        Box::new(self)
392    }
393
394    pub fn hover_info(mut self, hover_info: HoverInfo) -> Box<Self> {
395        self.hover_info = Some(hover_info);
396        Box::new(self)
397    }
398
399    pub fn hover_template(mut self, hover_template: &str) -> Box<Self> {
400        self.hover_template = Some(Dim::Scalar(hover_template.to_owned()));
401        Box::new(self)
402    }
403
404    pub fn x_axis(mut self, axis: &str) -> Box<Self> {
405        self.x_axis = Some(axis.to_owned());
406        Box::new(self)
407    }
408
409    pub fn y_axis(mut self, axis: &str) -> Box<Self> {
410        self.y_axis = Some(axis.to_owned());
411        Box::new(self)
412    }
413
414    pub fn hover_template_array<S: AsRef<str>>(mut self, hover_template: Vec<S>) -> Box<Self> {
415        let hover_template = private::owned_string_vector(hover_template);
416        self.hover_template = Some(Dim::Vector(hover_template));
417        Box::new(self)
418    }
419
420    pub fn orientation(mut self, orientation: Orientation) -> Box<Self> {
421        self.orientation = Some(orientation);
422        Box::new(self)
423    }
424
425    pub fn hist_func(mut self, hist_func: HistFunc) -> Box<Self> {
426        self.hist_func = Some(hist_func);
427        Box::new(self)
428    }
429
430    pub fn hist_norm(mut self, hist_norm: HistNorm) -> Box<Self> {
431        self.hist_norm = Some(hist_norm);
432        Box::new(self)
433    }
434
435    pub fn alignment_group(mut self, alignment_group: &str) -> Box<Self> {
436        self.alignment_group = Some(alignment_group.to_owned());
437        Box::new(self)
438    }
439
440    pub fn offset_group(mut self, offset_group: &str) -> Box<Self> {
441        self.offset_group = Some(offset_group.to_owned());
442        Box::new(self)
443    }
444
445    pub fn n_bins_x(mut self, n_bins_x: usize) -> Box<Self> {
446        self.n_bins_x = Some(n_bins_x);
447        Box::new(self)
448    }
449
450    pub fn n_bins_y(mut self, n_bins_y: usize) -> Box<Self> {
451        self.n_bins_y = Some(n_bins_y);
452        Box::new(self)
453    }
454
455    pub fn auto_bin_x(mut self, auto_bin_x: bool) -> Box<Self> {
456        self.auto_bin_x = Some(auto_bin_x);
457        Box::new(self)
458    }
459
460    pub fn auto_bin_y(mut self, auto_bin_y: bool) -> Box<Self> {
461        self.auto_bin_y = Some(auto_bin_y);
462        Box::new(self)
463    }
464
465    pub fn bin_group(mut self, bin_group: &str) -> Box<Self> {
466        self.bin_group = Some(bin_group.to_owned());
467        Box::new(self)
468    }
469
470    pub fn x_bins(mut self, x_bins: Bins) -> Box<Self> {
471        self.x_bins = Some(x_bins);
472        Box::new(self)
473    }
474
475    pub fn y_bins(mut self, y_bins: Bins) -> Box<Self> {
476        self.y_bins = Some(y_bins);
477        Box::new(self)
478    }
479
480    pub fn marker(mut self, marker: Marker) -> Box<Self> {
481        self.marker = Some(marker);
482        Box::new(self)
483    }
484
485    pub fn error_x(mut self, error_x: ErrorData) -> Box<Self> {
486        self.error_x = Some(error_x);
487        Box::new(self)
488    }
489
490    pub fn error_y(mut self, error_y: ErrorData) -> Box<Self> {
491        self.error_y = Some(error_y);
492        Box::new(self)
493    }
494
495    pub fn cumulative(mut self, cumulative: Cumulative) -> Box<Self> {
496        self.cumulative = Some(cumulative);
497        Box::new(self)
498    }
499
500    pub fn hover_label(mut self, hover_label: Label) -> Box<Self> {
501        self.hover_label = Some(hover_label);
502        Box::new(self)
503    }
504
505    pub fn x_calendar(mut self, x_calendar: Calendar) -> Box<Self> {
506        self.x_calendar = Some(x_calendar);
507        Box::new(self)
508    }
509
510    pub fn y_calendar(mut self, y_calendar: Calendar) -> Box<Self> {
511        self.y_calendar = Some(y_calendar);
512        Box::new(self)
513    }
514}
515
516impl<H> Trace for Histogram<H>
517where
518    H: Serialize + Clone + Default + 'static,
519{
520    fn serialize(&self) -> String {
521        serde_json::to_string(&self).unwrap()
522    }
523}