strafe-plot 0.1.1

Statistical plotting for Rust statistics based on R
// "Whatever you do, work at it with all your heart, as working for the Lord,
// not for human masters, since you know that you will receive an inheritance
// from the Lord as a reward. It is the Lord Christ you are serving."
// (Col 3:23-24)

use std::error::Error;

use plotters::prelude::{DrawingBackend, RGBColor, BLUE};

use crate::{
    drawing_coords::DrawingCoords,
    linear_model::draw_line,
    plot_options::PlotOptions,
    plottable::{Plottable, PlottableValues},
};

#[derive(Clone, Debug)]
pub struct VerticalLine {
    pub x: f64,
    pub color: RGBColor,
    pub size: u32,
    pub dash: bool,
    pub dash_length: f64,
    pub dash_iterations: usize,
    pub legend: bool,
    pub label: String,
}

impl Default for VerticalLine {
    fn default() -> Self {
        Self {
            x: 0.0,
            color: BLUE,
            size: 2,
            dash: false,
            dash_length: 0.003,
            dash_iterations: 10,
            legend: false,
            label: "".to_string(),
        }
    }
}

impl<B: DrawingBackend> Plottable<B> for VerticalLine
where
    B::ErrorType: 'static,
{
    fn plot(
        &self,
        _: &PlotOptions,
        drawing_coords: &DrawingCoords,
    ) -> Result<PlottableValues, Box<dyn Error>> {
        let coords = draw_line(
            &[self.x, self.x],
            &[
                drawing_coords.y_min - drawing_coords.y_space,
                drawing_coords.y_max + drawing_coords.y_space,
            ],
            &drawing_coords,
            self.dash,
            self.dash_length,
            self.dash_iterations,
        )?;
        let mut first = true;
        Ok(PlottableValues {
            lines: coords
                .into_iter()
                .map(|coords| {
                    (
                        coords,
                        self.size,
                        self.color,
                        if first && self.legend {
                            first = false;
                            Some(self.label.clone())
                        } else {
                            None
                        },
                    )
                })
                .collect(),
            ..Default::default()
        })
    }

    fn force_fit(&self) -> bool {
        false
    }

    fn get_x(&self) -> Vec<f64> {
        vec![self.x, self.x]
    }

    fn get_y(&self) -> Vec<f64> {
        Vec::new()
    }

    fn get_legend(&self) -> bool {
        self.legend
    }
}