rasters/
histogram.rs

1//! Utilities to compute histogram
2
3use serde_derive::Serialize;
4
5/// Configuration to generate histogram. Can be constructed
6/// from min, max and either step-size or number of bins.
7#[derive(Debug, PartialEq, Clone, Serialize)]
8pub struct Config {
9    min: f64,
10    max: f64,
11    step: f64,
12    len: usize,
13}
14
15impl Config {
16    pub fn from_min_max_step(min: f64, max: f64, step: f64) -> Self {
17        assert!(min <= max, "min must be smaller than max");
18        let len = ((max - min) / step).ceil() as usize;
19        Config {
20            min,
21            max,
22            step,
23            len,
24        }
25    }
26    pub fn from_min_max_bins(min: f64, max: f64, len: usize) -> Self {
27        assert!(min <= max, "min must be smaller than max");
28        let step = (max - min) / len as f64;
29        Config {
30            min,
31            max,
32            step,
33            len,
34        }
35    }
36
37    #[inline]
38    pub fn len(&self) -> usize {
39        self.len
40    }
41
42    #[inline]
43    pub fn step(&self) -> f64 {
44        self.step
45    }
46
47    #[inline]
48    pub fn max(&self) -> f64 {
49        self.max
50    }
51
52    #[inline]
53    pub fn min(&self) -> f64 {
54        self.min
55    }
56
57    #[inline]
58    pub fn bin_for(&self, val: f64) -> HistBin {
59        use HistBin::*;
60        if val >= self.max {
61            Max
62        } else if val < self.min {
63            Min
64        } else {
65            let bin = ((val - self.min) / self.step).floor() as usize;
66            if bin >= self.len {
67                Max
68            } else {
69                Bin(bin)
70            }
71        }
72    }
73}
74
75/// Represent the location of a value with respect to a
76/// histogram configuration.
77#[derive(Debug)]
78pub enum HistBin {
79    Min,
80    Max,
81    Bin(usize),
82}
83
84/// A histogram that can be built by accumulating individual
85/// values, or other histograms.
86#[derive(Debug, Clone, Serialize)]
87pub struct Histogram<'a> {
88    cfg: &'a Config,
89    hist: Vec<usize>,
90    min: usize,
91    max: usize,
92    count: usize,
93}
94impl<'a> Histogram<'a> {
95    pub fn new(cfg: &'a Config) -> Self {
96        Histogram {
97            cfg,
98            hist: vec![0; cfg.len()],
99            min: 0,
100            max: 0,
101            count: 0,
102        }
103    }
104}
105
106use std::ops::AddAssign;
107impl<'a, 'b> AddAssign<Histogram<'b>> for Histogram<'a> {
108    fn add_assign(&mut self, other: Histogram<'b>) {
109        assert!(
110            self.cfg == other.cfg,
111            "adding histogram with a different config"
112        );
113        for (a, b) in self.hist.iter_mut().zip(other.hist.iter()) {
114            *a += *b;
115        }
116        self.min += other.min;
117        self.max += other.max;
118        self.count += other.count;
119    }
120}
121impl<'a> AddAssign<f64> for Histogram<'a> {
122    fn add_assign(&mut self, other: f64) {
123        use HistBin::*;
124        match self.cfg.bin_for(other) {
125            Min => {
126                self.min += 1;
127            }
128            Max => {
129                self.max += 1;
130            }
131            Bin(bin) => {
132                self.hist[bin] += 1;
133            }
134        }
135        self.count += 1;
136    }
137}