#![forbid(unsafe_code)]
use plotters::element::DynElement;
use plotters::prelude::*;
use crate::viz_style::{LineDash, MarkerShape, SeriesStyle};
pub fn rgb_color(style: &SeriesStyle) -> RGBAColor {
RGBAColor(style.rgb.r, style.rgb.g, style.rgb.b, 1.0)
}
pub fn line_style(style: &SeriesStyle) -> ShapeStyle {
rgb_color(style).stroke_width(style.line_width)
}
pub fn dash_pattern(dash: LineDash, line_width: u32) -> Option<Vec<i32>> {
let lw = line_width as i32;
match dash {
LineDash::Solid => None,
LineDash::Dash => Some(vec![6 * lw, 4 * lw]), LineDash::Dot => Some(vec![2 * lw, 4 * lw]), LineDash::DashDot => Some(vec![6 * lw, 3 * lw, 2 * lw, 3 * lw]), }
}
type MarkerFactory<'a> = Box<dyn Fn() -> Circle<(f64, f64), i32> + 'a>;
pub fn create_marker_elements(
points: &[(f64, f64)],
size: i32,
color: RGBAColor,
marker: MarkerShape,
) -> Vec<MarkerFactory<'_>> {
let marker_size = match marker {
MarkerShape::Circle => size,
MarkerShape::Square => size + 1,
MarkerShape::Triangle => size + 1,
MarkerShape::Diamond => size + 1,
MarkerShape::Cross => size + 2,
MarkerShape::X => size + 2,
};
points
.iter()
.map(move |(x, y)| {
Box::new(move || Circle::new((*x, *y), marker_size, color.filled()))
as MarkerFactory<'_>
})
.collect()
}
pub fn fill_style(style: &SeriesStyle) -> ShapeStyle {
rgb_color(style).filled()
}
pub fn legend_swatch<DB>(
x: i32,
y: i32,
style: &SeriesStyle,
marker: MarkerShape,
) -> DynElement<'static, DB, (i32, i32)>
where
DB: DrawingBackend + 'static,
{
let st = line_style(style);
let marker_size = style.marker_size as i32;
(EmptyElement::at((x, y))
+ PathElement::new(vec![(x - 14, y), (x + 14, y)], st)
+ make_marker::<DB>((x, y), marker_size, fill_style(style), marker))
.into_dyn()
}
pub fn make_marker<DB>(
c: (i32, i32),
s: i32,
st: ShapeStyle,
marker: MarkerShape,
) -> DynElement<'static, DB, (i32, i32)>
where
DB: DrawingBackend + 'static,
{
match marker {
MarkerShape::Circle => {
(EmptyElement::at(c) + Circle::new((0, 0), s, st.filled())).into_dyn()
}
MarkerShape::Square => {
(EmptyElement::at(c) + Rectangle::new([(-s, -s), (s, s)], st.filled())).into_dyn()
}
MarkerShape::Triangle => (EmptyElement::at(c)
+ Polygon::new(vec![(0, -s), (-s, s), (s, s)], st.filled()))
.into_dyn(),
MarkerShape::Diamond => (EmptyElement::at(c)
+ Polygon::new(vec![(0, -s), (-s, 0), (0, s), (s, 0)], st.filled()))
.into_dyn(),
MarkerShape::Cross => (EmptyElement::at(c)
+ PathElement::new(vec![(-s, 0), (s, 0)], st.stroke_width(2))
+ PathElement::new(vec![(0, -s), (0, s)], st.stroke_width(2)))
.into_dyn(),
MarkerShape::X => (EmptyElement::at(c)
+ PathElement::new(vec![(-s, -s), (s, s)], st.stroke_width(2))
+ PathElement::new(vec![(-s, s), (s, -s)], st.stroke_width(2)))
.into_dyn(),
}
}