visu 0.2.3

Tool to simply visualise data
Documentation
use std::{array::from_fn, ops::Range};

use count_digits::CountDigits;

#[derive(Debug)]
pub struct NormalizedData<const SIZE: usize> {
    pub x_range:   Range<u128>,
    pub y_range:   Range<u128>,
    pub data:      [Vec<u128>; SIZE],
    pub y_divider: u128,
}

pub fn normalize_data<const SIZE: usize>(data: [&[u128]; SIZE]) -> NormalizedData<SIZE> {
    let Some(size) = data.first().map(|a| a.len()) else {
        panic!("Trying to visualise empty data set");
    };

    assert!(
        data.iter().all(|a| a.len() == size),
        "All data samples must be of the same size"
    );

    let all_max: Vec<u128> = data.iter().map(|a| *a.iter().max().unwrap()).collect();

    let max_digits = all_max.iter().map(CountDigits::count_digits).max().unwrap();

    let data: [Vec<u128>; SIZE] = from_fn(|i| {
        let set_max_digits = all_max[i].count_digits();

        let shift = max_digits - set_max_digits;

        data[i].iter().map(|val| val * 10_u128.pow(shift.try_into().unwrap())).collect()
    });

    let all_max: Vec<u128> = data.iter().map(|a| *a.iter().max().unwrap()).collect();

    let total_max = *all_max.iter().max().unwrap();

    let max_digits = total_max.count_digits() - 1;

    let range_max_pow = 10_u128.pow(max_digits.try_into().unwrap());

    let first_digit = total_max / range_max_pow;

    let max_digit = first_digit + 1;

    let range_max = max_digit * range_max_pow;

    NormalizedData {
        x_range: 0..size as u128 - 1,
        y_range: 0..range_max,
        data,
        y_divider: range_max_pow / 10,
    }
}

#[cfg(test)]
mod test {
    use crate::normalized_data::normalize_data;

    #[test]
    fn test_normalize() {
        let norm = normalize_data([&[3, 8], &[10, 30]]);
        assert_eq!(norm.x_range, 0..1);
        assert_eq!(norm.y_range, 0..90);
        assert_eq!(norm.data, [[30, 80], [10, 30]]);

        let norm = normalize_data([&[9_000], &[15_000_000_000_000_000]]);
        assert_eq!(norm.x_range, 0..0);
        assert_eq!(norm.y_range, 0..100_000_000_000_000_000);
    }
}