plotters-statistical 0.1.0

Statistical chart primitives (box, violin, ROC, PR, regularization-path, residual) as native plotters series
Documentation
//! A vertical colorbar drawn directly onto a drawing area, shared by the
//! heatmap figures.

use plotters::coord::Shift;
use plotters::prelude::*;
use plotters::style::text_anchor::{HPos, Pos, VPos};

use crate::colormap::{GradientColorMap, Normalization};

/// Draw a vertical colorbar filling the left edge of `area`, with a handful of
/// tick labels to its right. `steps` controls the gradient resolution.
pub fn draw_colorbar<DB: DrawingBackend>(
    area: &DrawingArea<DB, Shift>,
    colormap: &GradientColorMap,
    norm: &Normalization,
    ticks: usize,
) -> Result<(), Box<dyn std::error::Error>>
where
    DB::ErrorType: 'static,
{
    let (w, h) = area.dim_in_pixel();
    let (w, h) = (w as i32, h as i32);
    let bar_w = 16;
    let top = 8;
    let bottom = h - 8;
    let bar_h = (bottom - top).max(1);
    let steps = bar_h.max(2);

    // Gradient strip: one thin rect per pixel row, t = 1 at the top.
    for s in 0..steps {
        let y0 = top + (bar_h * s) / steps;
        let y1 = top + (bar_h * (s + 1)) / steps;
        let t = 1.0 - s as f64 / (steps - 1) as f64;
        let color = colormap.color(t);
        area.draw(&Rectangle::new([(4, y0), (4 + bar_w, y1)], color.filled()))?;
    }
    // Outline.
    area.draw(&Rectangle::new(
        [(4, top), (4 + bar_w, bottom)],
        BLACK.stroke_width(1),
    ))?;

    // Tick labels.
    let ticks = ticks.max(2);
    let label_style = TextStyle::from(("sans-serif", 12).into_font())
        .color(&BLACK)
        .pos(Pos::new(HPos::Left, VPos::Center));
    for k in 0..ticks {
        let t = k as f64 / (ticks - 1) as f64;
        let y = bottom - ((bar_h * k as i32) / (ticks as i32 - 1));
        let value = norm.value(t);
        let _ = w; // width is available if callers extend this later
        area.draw(&Text::new(
            format!("{value:.2}"),
            (4 + bar_w + 6, y),
            label_style.clone(),
        ))?;
    }
    Ok(())
}