use std::error::Error;
use plotters::{
backend::DrawingBackend,
prelude::{RGBColor, BLUE},
};
use crate::{
drawing_coords::DrawingCoords,
linear_model::draw_line,
plot_options::PlotOptions,
plottable::{Plottable, PlottableValues},
};
#[derive(Clone, Debug)]
pub struct Line {
pub x: Vec<f64>,
pub y: Vec<f64>,
pub size: u32,
pub color: RGBColor,
pub dash: bool,
pub dash_length: f64,
pub dash_iterations: usize,
pub force_fit_all: bool,
pub legend: bool,
pub label: String,
}
impl Default for Line {
fn default() -> Self {
Self {
x: Vec::new(),
y: Vec::new(),
size: 2,
color: BLUE,
dash: false,
dash_length: 0.003,
dash_iterations: 10,
force_fit_all: true,
legend: false,
label: "".to_string(),
}
}
}
impl<B: DrawingBackend> Plottable<B> for Line
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_line(
&xs,
&ys,
&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 {
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
}
}