mod data;
mod heatmap;
pub use data::{Data, DataLoader, convert};
pub use heatmap::{Heatmap, Order};
use std::{fmt::Display, path::PathBuf};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Array(Vec<Error>),
Clap(clap::Error),
Csv(csv::Error),
FileNotFound(PathBuf),
Image(image::ImageError),
InvalidData(String),
Io(std::io::Error),
ParseRange(String, String),
ParseFloat(String, std::num::ParseFloatError),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Array(errs) => {
for (i, err) in errs.iter().enumerate() {
writeln!(f, "Error {}: {}", i + 1, err)?;
}
Ok(())
},
Error::Io(e) => write!(f, "IO error: {}", e),
Error::ParseRange(s, msg) => write!(f, "{s}: Failed to parse range: {}", msg),
Error::ParseFloat(s, e) => write!(f, "{s}: Failed to parse float: {}", e),
Error::Clap(e) => {
if e.kind() == clap::error::ErrorKind::DisplayHelp || e.kind() == clap::error::ErrorKind::DisplayVersion {
write!(f, "{}", e)
} else {
write!(f, "Command line argument error: {}", e)
}
},
Error::Image(e) => write!(f, "Image error: {}", e),
Error::InvalidData(msg) => write!(f, "Invalid data: {}", msg),
Error::FileNotFound(path) => write!(f, "{}: File not found", path.display()),
Error::Csv(e) => write!(f, "CSV error: {}", e),
}
}
}
pub struct ScalerBuilder;
impl ScalerBuilder {
pub fn build() -> Data<f64> {
Self::build_with(5)
}
pub fn build_with(height: usize) -> Data<f64> {
log::debug!("Generating scaler data with height: {}", height);
let range = 0_i32..240_i32;
let line = range.into_iter()
.map(|i| Some(i as f64 / 240.0))
.collect::<Vec<Option<f64>>>();
let table = (0..height)
.map(|_| line.clone()).collect::<Vec<Vec<_>>>();
Data::new(table)
}
}