|
|
|
|
@ -7,6 +7,7 @@ use crate::format::F64Formatter;
|
|
|
|
|
use crate::stats::Stats; |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
/// A struct that represents a bucket of an histogram.
|
|
|
|
|
struct Bucket { |
|
|
|
|
range: Range<f64>, |
|
|
|
|
count: usize, |
|
|
|
|
@ -23,6 +24,7 @@ impl Bucket {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
/// A struct holding data to plot a Histogram of numerical data.
|
|
|
|
|
pub struct Histogram { |
|
|
|
|
vec: Vec<Bucket>, |
|
|
|
|
max: f64, |
|
|
|
|
@ -34,7 +36,35 @@ pub struct Histogram {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Histogram { |
|
|
|
|
pub fn new(size: usize, step: f64, stats: Stats, precision: Option<usize>) -> Histogram { |
|
|
|
|
/// Creates a Histogram from a vector of numerical data.
|
|
|
|
|
///
|
|
|
|
|
/// `intervals` is the number of histogram buckets to display (capped to the
|
|
|
|
|
/// length of input data).
|
|
|
|
|
///
|
|
|
|
|
/// `precision` is an Option with the number of decimals to display. If
|
|
|
|
|
/// "None" is used, human units will be used, with an heuristic based on the
|
|
|
|
|
/// input data for deciding the units and the decimal places.
|
|
|
|
|
pub fn new(vec: &[f64], intervals: usize, precision: Option<usize>) -> Histogram { |
|
|
|
|
let stats = Stats::new(vec, precision); |
|
|
|
|
let size = intervals.min(vec.len()); |
|
|
|
|
let step = (stats.max - stats.min) / size as f64; |
|
|
|
|
let mut histogram = Histogram::new_with_stats(size, step, stats, precision); |
|
|
|
|
histogram.load(vec); |
|
|
|
|
histogram |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Creates a Histogram with no input data.
|
|
|
|
|
///
|
|
|
|
|
///
|
|
|
|
|
/// Parameters are similar to those on the `new` method, but a parameter
|
|
|
|
|
/// named `stats` is needed to decide how future data (to be injected with
|
|
|
|
|
/// the load method) will be accommodated.
|
|
|
|
|
pub fn new_with_stats( |
|
|
|
|
size: usize, |
|
|
|
|
step: f64, |
|
|
|
|
stats: Stats, |
|
|
|
|
precision: Option<usize>, |
|
|
|
|
) -> Histogram { |
|
|
|
|
let mut vec = Vec::<Bucket>::with_capacity(size); |
|
|
|
|
let mut lower = stats.min; |
|
|
|
|
for _ in 0..size { |
|
|
|
|
@ -52,12 +82,14 @@ impl Histogram {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Add to the `Histogram` data the values of a slice of numerical data.
|
|
|
|
|
pub fn load(&mut self, vec: &[f64]) { |
|
|
|
|
for x in vec { |
|
|
|
|
self.add(*x); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Add to the `Histogram` a single piece of numerical data.
|
|
|
|
|
pub fn add(&mut self, n: f64) { |
|
|
|
|
if let Some(slot) = self.find_slot(n) { |
|
|
|
|
self.vec[slot].inc(); |
|
|
|
|
@ -158,7 +190,7 @@ mod tests {
|
|
|
|
|
#[test] |
|
|
|
|
fn test_buckets() { |
|
|
|
|
let stats = Stats::new(&[-2.0, 14.0], None); |
|
|
|
|
let mut hist = Histogram::new(8, 2.5, stats, None); |
|
|
|
|
let mut hist = Histogram::new_with_stats(8, 2.5, stats, None); |
|
|
|
|
hist.load(&[ |
|
|
|
|
-1.0, -1.1, 2.0, 2.0, 2.1, -0.9, 11.0, 11.2, 1.9, 1.99, 1.98, 1.97, 1.96, |
|
|
|
|
]); |
|
|
|
|
@ -174,7 +206,7 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn test_buckets_bad_stats() { |
|
|
|
|
let mut hist = Histogram::new(6, 1.0, Stats::new(&[-2.0, 4.0], None), None); |
|
|
|
|
let mut hist = Histogram::new_with_stats(6, 1.0, Stats::new(&[-2.0, 4.0], None), None); |
|
|
|
|
hist.load(&[-1.0, 2.0, -1.0, 2.0, 10.0, 10.0, 10.0, -10.0]); |
|
|
|
|
assert_eq!(hist.top, 2); |
|
|
|
|
} |
|
|
|
|
@ -182,7 +214,7 @@ mod tests {
|
|
|
|
|
#[test] |
|
|
|
|
fn display_test() { |
|
|
|
|
let stats = Stats::new(&[-2.0, 14.0], None); |
|
|
|
|
let mut hist = Histogram::new(8, 2.5, stats, Some(3)); |
|
|
|
|
let mut hist = Histogram::new_with_stats(8, 2.5, stats, Some(3)); |
|
|
|
|
hist.load(&[ |
|
|
|
|
-1.0, -1.1, 2.0, 2.0, 2.1, -0.9, 11.0, 11.2, 1.9, 1.99, 1.98, 1.97, 1.96, |
|
|
|
|
]); |
|
|
|
|
@ -195,7 +227,7 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn display_test_bad_width() { |
|
|
|
|
let mut hist = Histogram::new(8, 2.5, Stats::new(&[-2.0, 14.0], None), Some(3)); |
|
|
|
|
let mut hist = Histogram::new_with_stats(8, 2.5, Stats::new(&[-2.0, 14.0], None), Some(3)); |
|
|
|
|
hist.load(&[ |
|
|
|
|
-1.0, -1.1, 2.0, 2.0, 2.1, -0.9, 11.0, 11.2, 1.9, 1.99, 1.98, 1.97, 1.96, |
|
|
|
|
]); |
|
|
|
|
@ -216,15 +248,7 @@ mod tests {
|
|
|
|
|
500000.0, |
|
|
|
|
500000.0, |
|
|
|
|
]; |
|
|
|
|
let intervals = vector.len(); |
|
|
|
|
let stats = Stats::new(vector, None); |
|
|
|
|
let mut hist = Histogram::new( |
|
|
|
|
intervals, |
|
|
|
|
(stats.max - stats.min) / intervals as f64, |
|
|
|
|
stats, |
|
|
|
|
None, |
|
|
|
|
); |
|
|
|
|
hist.load(vector); |
|
|
|
|
let hist = Histogram::new(vector, vector.len(), None); |
|
|
|
|
Paint::disable(); |
|
|
|
|
let display = format!("{}", hist); |
|
|
|
|
assert!(display.contains("[-12.0 M .. -10.4 M] [4] ∎∎∎∎\n")); |
|
|
|
|
|