malevich 0.4.0

Terminal plotting: a small grammar of marks, honest axes, millions of points
Documentation
//! The rule mark: a reference line across the whole plot.

use crate::render::Color;

/// A reference line spanning the plot: horizontal at a y value, or vertical at an
/// x value. The zero line, a target, a threshold — annotations, not data.
///
/// A rule extends the axis domain to include its position, so it is always visible.
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum Orientation {
    Horizontal(f64),
    Vertical(f64),
}

/// A reference line across the plot area.
#[derive(Debug, Clone)]
pub struct Rule {
    pub(crate) orientation: Orientation,
    pub(crate) color: Option<Color>,
    pub(crate) label: Option<String>,
}

impl Rule {
    /// A horizontal rule at `y`, spanning the plot's width.
    ///
    /// # Panics
    ///
    /// Panics if `y` is not finite.
    pub fn h(y: f64) -> Rule {
        assert!(y.is_finite(), "Rule::h requires a finite position");
        Rule {
            orientation: Orientation::Horizontal(y),
            color: None,
            label: None,
        }
    }

    /// A vertical rule at `x`, spanning the plot's height.
    ///
    /// # Panics
    ///
    /// Panics if `x` is not finite.
    pub fn v(x: f64) -> Rule {
        assert!(x.is_finite(), "Rule::v requires a finite position");
        Rule {
            orientation: Orientation::Vertical(x),
            color: None,
            label: None,
        }
    }

    /// Sets an explicit color; without one, rules draw in the default foreground —
    /// annotations should recede, not compete.
    #[must_use]
    pub fn color(mut self, color: Color) -> Rule {
        self.color = Some(color);
        self
    }

    /// Names this rule in the legend.
    #[must_use]
    pub fn label(mut self, label: impl Into<String>) -> Rule {
        self.label = Some(label.into());
        self
    }
}

#[cfg(test)]
#[path = "tests/rule_tests.rs"]
mod tests;