use ndarray::{ArrayBase, AsArray, Dimension, ViewRepr};
use crate::statistics::min_max;
use crate::traits::numeric::AsNumeric;
pub fn histogram<'a, T, A, D>(data: A, bins: Option<usize>) -> Vec<i64>
where
A: AsArray<'a, T, D>,
D: Dimension,
T: 'a + AsNumeric,
{
let view: ArrayBase<ViewRepr<&'a T>, D> = data.into();
let bins = bins.unwrap_or(256);
if view.is_empty() || bins == 0 {
return vec![0; 1];
}
let (min, max) = min_max(&view);
let mut hist = vec![0; bins];
let bin_width: f64 = (max.to_f64() - min.to_f64()) / bins as f64;
view.iter().for_each(|&v| {
let bin_index: usize = ((v.to_f64() - min.to_f64()) / bin_width) as usize;
let bin_index = bin_index.min(bins - 1);
hist[bin_index] += 1;
});
hist
}
#[inline]
pub fn histogram_bin_midpoint<T>(index: usize, min: T, max: T, bins: usize) -> T
where
T: AsNumeric,
{
let min = min.to_f64();
let max = max.to_f64();
let bin_width = (max - min) / bins as f64;
T::from_f64(min + (index as f64 + 0.5) * bin_width)
}
#[inline]
pub fn histogram_bin_range<T>(index: usize, min: T, max: T, bins: usize) -> (T, T)
where
T: AsNumeric,
{
let min = min.to_f64();
let max = max.to_f64();
let bin_width = (max - min) / bins as f64;
let bin_start = min + (index as f64 * bin_width);
let bin_end = bin_start + bin_width;
(T::from_f64(bin_start), T::from_f64(bin_end))
}