use core::f64;
use svg::node::element::Group;
use super::common::Plot;
use super::utils;
pub struct Scatter {
data: Vec<(f64, f64, f64)>,
color: String,
marker_size: f64,
xlim: (f64, f64),
ylim: (f64, f64),
}
impl Default for Scatter {
fn default() -> Self {
Self {
data: vec![],
color: "black".to_string(),
marker_size: 5.0,
xlim: (f64::NEG_INFINITY, f64::INFINITY),
ylim: (f64::NEG_INFINITY, f64::INFINITY),
}
}
}
impl Scatter {
pub fn new_2d(data: Vec<(f64, f64)>) -> Self {
let default = Self::default();
Self {
data: data.iter().map(|(x, y)| (*x, *y, 0.0)).collect(),
..default
}
}
pub fn new_3d(data: Vec<(f64, f64, f64)>) -> Self {
let default = Self::default();
Self { data, ..default }
}
}
impl Plot for Scatter {
fn render(&self, figsize: (f64, f64), aspect: Option<f64>) -> Group {
let (scale, shift) = utils::get_scale_factors(figsize, self.bbox(), aspect);
let mut scatter_plot = Group::new();
for (x, y, _) in &self.data {
let circle = svg::node::element::Circle::new()
.set("cx", *x * scale.0 + shift.0)
.set("cy", *y * scale.1 + shift.1)
.set("r", self.marker_size)
.set("fill", self.color.clone());
scatter_plot = scatter_plot.add(circle);
}
scatter_plot
}
fn bbox(&self) -> (f64, f64, f64, f64) {
let mut min_x = f64::INFINITY;
let mut max_x = f64::NEG_INFINITY;
let mut min_y = f64::INFINITY;
let mut max_y = f64::NEG_INFINITY;
for (x, y, _) in &self.data {
min_x = min_x.min(*x);
max_x = max_x.max(*x);
min_y = min_y.min(*y);
max_y = max_y.max(*y);
}
min_x = min_x.max(self.xlim.0);
max_x = max_x.min(self.xlim.1);
min_y = min_y.max(self.ylim.0);
max_y = max_y.min(self.ylim.1);
let margin = 0.1;
let mut dx = (max_x - min_x) * margin;
let mut dy = (max_y - min_y) * margin;
dx = if dx.is_finite() && dx != 0.0 { dx } else { 1.0 };
dy = if dy.is_finite() && dy != 0.0 { dy } else { 1.0 };
(min_x - dx, max_x + dx, min_y - dy, max_y + dy)
}
fn color(&mut self, color: &str) -> &mut Self
where
Self: Sized,
{
self.color = color.to_string();
self
}
fn marker_size(&mut self, size: f64) -> &mut Self
where
Self: Sized,
{
self.marker_size = size;
self
}
fn xlim(&mut self, min: f64, max: f64) -> &mut Self
where
Self: Sized,
{
if min > max {
panic!("min must be less than or equal to max");
}
self.xlim = (min, max);
self
}
fn ylim(&mut self, min: f64, max: f64) -> &mut Self
where
Self: Sized,
{
if min > max {
panic!("min must be less than or equal to max");
}
self.ylim = (min, max);
self
}
}