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::{
    backend::DrawingBackend,
    prelude::{RGBColor, BLACK},
};

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

#[derive(Clone, Debug)]
pub struct Points {
    pub x: Vec<f64>,
    pub y: Vec<f64>,
    pub size: u32,
    pub color: RGBColor,
    pub force_fit_all: bool,
    pub legend: bool,
    pub label: String,
}

impl Default for Points {
    fn default() -> Self {
        Self {
            x: Vec::new(),
            y: Vec::new(),
            size: 2,
            color: BLACK,
            force_fit_all: true,
            legend: false,
            label: "".to_string(),
        }
    }
}

impl<B: DrawingBackend> Plottable<B> for Points
where
    B::ErrorType: 'static,
{
    fn plot(
        &self,
        plot_options: &PlotOptions,
        drawing_coords: &DrawingCoords,
    ) -> Result<PlottableValues, Box<dyn Error>> {
        let mut xs = self.x.clone();
        let mut ys = self.y.clone();

        if plot_options.x_log {
            for x in xs.iter_mut() {
                *x = x.abs().log10();
            }
        }

        if plot_options.y_log {
            for y in ys.iter_mut() {
                *y = y.abs().log10();
            }
        }

        let coords = draw_points(&xs, &ys, &drawing_coords)?;
        Ok(PlottableValues {
            points: vec![(
                coords,
                self.size,
                self.color,
                if self.legend {
                    Some(self.label.clone())
                } else {
                    None
                },
            )],
            ..Default::default()
        })
    }

    fn force_fit(&self) -> bool {
        self.force_fit_all
    }

    fn get_x(&self) -> Vec<f64> {
        self.x.clone()
    }

    fn get_y(&self) -> Vec<f64> {
        self.y.clone()
    }

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