plotters-statistical 0.1.0

Statistical chart primitives (box, violin, ROC, PR, regularization-path, residual) as native plotters series
Documentation
//! Shared styling: a color-blind-safe default palette and small helpers for
//! building [`ShapeStyle`]s, used by every chart type so the crate's output is
//! visually consistent.
//!
//! The default palette is the **Okabe–Ito** qualitative palette, designed to be
//! distinguishable under the common forms of color-vision deficiency.
//!
//! > Okabe, M. & Ito, K. (2008). *Color Universal Design (CUD): How to make
//! > figures and presentations that are friendly to colorblind people.*
//! > <https://jfly.uni-koeln.de/color/>

use plotters::style::{Color, RGBAColor, RGBColor, ShapeStyle};

/// The eight Okabe–Ito colors as `(r, g, b)` triples, in the recommended order.
///
/// Index 0 is black; [`palette_color`] skips it by default so cycling starts on
/// a hue, but it is available here for callers who want the full set.
pub const OKABE_ITO: [(u8, u8, u8); 8] = [
    (0, 0, 0),       // black
    (230, 159, 0),   // orange
    (86, 180, 233),  // sky blue
    (0, 158, 115),   // bluish green
    (240, 228, 66),  // yellow
    (0, 114, 178),   // blue
    (213, 94, 0),    // vermillion
    (204, 121, 167), // reddish purple
];

/// Default label / axis font family used across the crate's examples.
pub const DEFAULT_FONT: &str = "sans-serif";

/// Default font size (points) for legend and annotation text.
pub const DEFAULT_FONT_SIZE: u32 = 16;

/// Returns the `i`-th palette color, cycling through the seven non-black
/// Okabe–Ito hues. Deterministic, so the *k*-th series always gets the same
/// color across every chart type.
///
/// ```
/// use plotters_statistical::style::palette_color;
/// use plotters::style::Color;
/// // Cycling wraps after seven hues: index 0 and index 7 map to the same color.
/// assert_eq!(palette_color(0).to_rgba(), palette_color(7).to_rgba());
/// ```
pub fn palette_color(i: usize) -> RGBColor {
    // Skip index 0 (black) so multi-series charts start on a hue.
    let (r, g, b) = OKABE_ITO[1 + (i % (OKABE_ITO.len() - 1))];
    RGBColor(r, g, b)
}

/// A solid-fill [`ShapeStyle`] of the given color (`filled = true`).
pub fn fill_style<C: Color>(color: &C) -> ShapeStyle {
    ShapeStyle {
        color: color.to_rgba(),
        filled: true,
        stroke_width: 0,
    }
}

/// A stroked (outline) [`ShapeStyle`] of the given color and width
/// (`filled = false`).
pub fn stroke_style<C: Color>(color: &C, width: u32) -> ShapeStyle {
    ShapeStyle {
        color: color.to_rgba(),
        filled: false,
        stroke_width: width,
    }
}

/// A translucent fill built from `color` at the given `alpha` (0.0–1.0).
///
/// Used for area shading (AUC fills, violin bodies, box interiors) where an
/// opaque fill would hide gridlines or overlapping series.
pub fn translucent_fill<C: Color>(color: &C, alpha: f64) -> ShapeStyle {
    ShapeStyle {
        color: color.mix(alpha),
        filled: true,
        stroke_width: 0,
    }
}

/// Convenience: a fully-specified [`RGBAColor`] with explicit alpha.
pub fn rgba(r: u8, g: u8, b: u8, alpha: f64) -> RGBAColor {
    RGBColor(r, g, b).mix(alpha)
}