use cairo::Context;
use ndarray::AsArray;
use palette::Rgba;
use ::{utils, chart, frame};
#[derive(Clone, Debug)]
pub struct Scatter {
data_points: Vec<chart::point::Point>,
global_frame: frame::Frame,
data_frame: frame::Frame,
color: Rgba,
shape: chart::point::Shape,
point_size: f64,
}
impl Scatter {
pub fn new<'a, I: AsArray<'a, f64>>(x_data_coords: I, y_data_coords: I) -> Scatter {
let x_view: Vec<_> = x_data_coords.into().iter().map(|v| utils::NonNan::new(*v).unwrap()).collect();
let y_view: Vec<_> = y_data_coords.into().iter().map(|v| utils::NonNan::new(*v).unwrap()).collect();
let ref x_data_min = x_view.iter().min().expect("Could not find x min");
let ref x_data_max = x_view.iter().max().expect("Could not find x max");
let ref y_data_min = y_view.iter().min().expect("Could not find y min");
let ref y_data_max = y_view.iter().max().expect("Could not find y max");
let color = Rgba::new(0.1, 0.1, 0.8, 0.9);
let shape = chart::point::Shape::Circle;
let point_size = 0.01;
let mut data_points = Vec::<chart::point::Point>::new();
for (ref x, ref y) in x_view.iter().zip(y_view.iter()) {
let mut point = chart::point::Point::new(x.val(), y.val());
point.set_color(color);
point.set_shape(shape.clone());
point.set_size(point_size);
data_points.push(chart::point::Point::new(x.val(), y.val()));
}
Scatter {
data_points: data_points,
global_frame: frame::Frame::new(),
data_frame: frame::Frame::from_sides(x_data_min.val(), x_data_max.val(),
y_data_min.val(), y_data_max.val()),
color: color,
shape: shape,
point_size: point_size,
}
}
pub fn set_color(mut self, color: Rgba) -> Self {
self.color = color;
self
}
pub fn set_color_rgb(mut self, red: f32, green: f32, blue: f32) -> Self {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
self.color = Rgba::new(red, green, blue, 1.0);
self
}
pub fn set_color_rgba(mut self, red: f32, green: f32, blue: f32, alpha: f32) -> Self {
let red = red.max(0.0);
let red = red.min(1.0);
let green = green.max(0.0);
let green = green.min(1.0);
let blue = blue.max(0.0);
let blue = blue.min(1.0);
let alpha = alpha.max(0.0);
let alpha = alpha.min(1.0);
self.color = Rgba::new(red, green, blue, alpha);
self
}
pub fn set_point_size(mut self, size: f64) -> Self {
self.point_size = size;
self
}
pub fn set_shape(mut self, shape_id: &str) -> Self {
self.shape = match shape_id {
"Circle" | "circle" | "c" | "o" => chart::point::Shape::Circle,
"Square" | "square" | "s" => chart::point::Shape::Square,
"Tick" | "tick" | "t" => chart::point::Shape::Tick,
_ => chart::point::Shape::Circle,
};
self
}
}
impl utils::Drawable for Scatter {
fn scale_size(&mut self, factor: f64) {
self.point_size *= factor;
}
fn fit(&mut self, canvas_global_frame: &frame::Frame, canvas_data_frame: &frame::Frame) {
self.global_frame = canvas_global_frame.clone();
self.data_frame = canvas_data_frame.clone();
for data_point in self.data_points.iter_mut() {
data_point.set_color(self.color);
data_point.set_shape(self.shape.clone());
data_point.set_size(self.point_size);
data_point.fit(canvas_global_frame, canvas_data_frame);
}
}
fn draw(&self, cr: &Context, fig_rel_height: f64, fig_rel_width: f64) {
for data_point in self.data_points.iter() {
let canvas_x = utils::map_range(data_point.x_coord(),
self.data_frame.left(), self.data_frame.right(),
self.global_frame.left(), self.global_frame.right());
let canvas_y = utils::map_range(data_point.y_coord(),
self.data_frame.bottom(), self.data_frame.top(),
self.global_frame.bottom(), self.global_frame.top());
let mut canvas_point = data_point.clone();
canvas_point.set_x_coord(canvas_x);
canvas_point.set_y_coord(canvas_y);
canvas_point.draw(cr, fig_rel_height, fig_rel_width);
}
}
}
impl utils::Plottable for Scatter {
fn data_frame(&self) -> frame::Frame {
self.data_frame.clone()
}
fn data_x_min(&self) -> f64 {
self.data_frame.left()
}
fn data_x_max(&self) -> f64 {
self.data_frame.right()
}
fn data_y_min(&self) -> f64 {
self.data_frame.bottom()
}
fn data_y_max(&self) -> f64 {
self.data_frame.top()
}
fn set_data_frame(&mut self, new_data_frame: frame::Frame) {
self.data_frame = new_data_frame;
}
}