pub use crate::plot::colormap::ColorMap;
#[derive(Clone)]
pub struct Heatmap {
pub data: Vec<Vec<f64>>,
pub row_labels: Option<Vec<String>>,
pub col_labels: Option<Vec<String>>,
pub color_map: ColorMap,
pub show_values: bool,
pub legend_label: Option<String>,
pub show_tooltips: bool,
pub tooltip_labels: Option<Vec<String>>,
pub x_range: Option<(f64, f64)>,
pub y_range: Option<(f64, f64)>,
pub cell_size: f64,
}
impl Default for Heatmap {
fn default() -> Self {
Self::new()
}
}
impl Heatmap {
pub fn new() -> Self {
Self {
data: vec![],
row_labels: None,
col_labels: None,
color_map: ColorMap::Viridis,
show_values: false,
legend_label: None,
show_tooltips: false,
tooltip_labels: None,
x_range: None,
y_range: None,
cell_size: 0.99,
}
}
pub fn with_data<U, T, I>(mut self, data: I) -> Self
where
I: IntoIterator<Item = T>,
T: IntoIterator<Item = U>,
U: Into<f64>,
{
let mut a: Vec<f64> = vec![];
for d in data.into_iter() {
for v in d {
a.push(v.into())
}
self.data.push(a);
a = vec![];
}
self
}
pub fn with_labels(mut self, rows: Vec<String>, cols: Vec<String>) -> Self {
self.row_labels = Some(rows);
self.col_labels = Some(cols);
self
}
pub fn with_y_categories(
mut self,
desired_order: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
let order: Vec<String> = desired_order.into_iter().map(|s| s.into()).collect();
if let Some(ref current_labels) = self.row_labels.clone() {
let label_to_idx: std::collections::HashMap<&str, usize> = current_labels
.iter()
.enumerate()
.map(|(i, s)| (s.as_str(), i))
.collect();
let mut new_data: Vec<Vec<f64>> = order
.iter()
.filter_map(|label| {
label_to_idx
.get(label.as_str())
.map(|&i| self.data[i].clone())
})
.collect();
new_data.reverse();
self.data = new_data;
}
let mut bottom_to_top = order;
bottom_to_top.reverse();
self.row_labels = Some(bottom_to_top);
self
}
pub fn with_x_categories(
mut self,
desired_order: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
let order: Vec<String> = desired_order.into_iter().map(|s| s.into()).collect();
if let Some(ref current_labels) = self.col_labels.clone() {
let label_to_idx: std::collections::HashMap<&str, usize> = current_labels
.iter()
.enumerate()
.map(|(i, s)| (s.as_str(), i))
.collect();
self.data = self
.data
.iter()
.map(|row| {
order
.iter()
.filter_map(|label| label_to_idx.get(label.as_str()).map(|&j| row[j]))
.collect()
})
.collect();
}
self.col_labels = Some(order);
self
}
pub fn with_color_map(mut self, map: ColorMap) -> Self {
self.color_map = map;
self
}
pub fn with_values(mut self) -> Self {
self.show_values = true;
self
}
pub fn with_legend<S: Into<String>>(mut self, label: S) -> Self {
self.legend_label = Some(label.into());
self
}
pub fn with_tooltips(mut self) -> Self {
self.show_tooltips = true;
self
}
pub fn with_tooltip_labels(
mut self,
labels: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.tooltip_labels = Some(labels.into_iter().map(|s| s.into()).collect());
self
}
pub fn with_x_range(mut self, x_min: impl Into<f64>, x_max: impl Into<f64>) -> Self {
self.x_range = Some((x_min.into(), x_max.into()));
self
}
pub fn with_y_range(mut self, y_min: impl Into<f64>, y_max: impl Into<f64>) -> Self {
self.y_range = Some((y_min.into(), y_max.into()));
self
}
pub fn with_cell_size(mut self, factor: impl Into<f64>) -> Self {
self.cell_size = factor.into().clamp(0.5, 1.0);
self
}
}