use crate::artist::ScatterArtist;
use crate::colormap::Colormap;
use crate::decimate::{DecimateMethod, DecimateMode};
use crate::primitives::Color;
use crate::theme::Marker;
impl ScatterArtist {
pub fn color(&mut self, color: Color) -> &mut Self {
self.color = color;
self
}
pub fn marker(&mut self, marker: Marker) -> &mut Self {
self.marker = marker;
self
}
pub fn size(&mut self, size: f64) -> &mut Self {
self.size = size;
self
}
pub fn label(&mut self, label: &str) -> &mut Self {
self.label = Some(label.to_string());
self
}
pub fn alpha(&mut self, alpha: f64) -> &mut Self {
self.alpha = alpha.clamp(0.0, 1.0);
self
}
pub fn colors(&mut self, colors: Vec<Color>) -> &mut Self {
self.colors = Some(colors);
self
}
pub fn c(&mut self, c: Vec<f64>) -> &mut Self {
self.c = Some(c);
self
}
pub fn cmap(&mut self, cmap: Colormap) -> &mut Self {
self.cmap = Some(cmap);
self
}
pub fn decimate(&mut self, threshold: usize) -> &mut Self {
self.decimate = DecimateMode::Explicit(threshold, DecimateMethod::Lttb);
self
}
pub fn decimate_with(&mut self, threshold: usize, method: DecimateMethod) -> &mut Self {
self.decimate = DecimateMode::Explicit(threshold, method);
self
}
pub fn no_decimate(&mut self) -> &mut Self {
self.decimate = DecimateMode::Off;
self
}
}
#[cfg(test)]
mod tests {
use crate::axes::Axes;
use crate::decimate::{DecimateMethod, DecimateMode, DEFAULT_DECIMATE_THRESHOLD};
fn make_axes() -> Axes {
Axes::new()
}
#[test]
fn scatter_defaults_to_auto_decimate() {
let mut ax = make_axes();
let artist = ax.scatter([0.0, 1.0, 2.0], [0.0, 1.0, 2.0]).unwrap();
assert_eq!(artist.decimate, DecimateMode::Auto);
}
#[test]
fn scatter_decimate_sets_explicit_lttb() {
let mut ax = make_axes();
let artist = ax.scatter([0.0, 1.0], [0.0, 1.0]).unwrap();
artist.decimate(2000);
assert_eq!(
artist.decimate,
DecimateMode::Explicit(2000, DecimateMethod::Lttb)
);
}
#[test]
fn scatter_decimate_with_sets_explicit_method() {
let mut ax = make_axes();
let artist = ax.scatter([0.0, 1.0], [0.0, 1.0]).unwrap();
artist.decimate_with(750, DecimateMethod::MinMax);
assert_eq!(
artist.decimate,
DecimateMode::Explicit(750, DecimateMethod::MinMax)
);
}
#[test]
fn scatter_no_decimate_disables() {
let mut ax = make_axes();
let artist = ax.scatter([0.0, 1.0], [0.0, 1.0]).unwrap();
artist.no_decimate();
assert_eq!(artist.decimate, DecimateMode::Off);
}
#[test]
fn scatter_auto_kicks_in_above_threshold() {
let n = DEFAULT_DECIMATE_THRESHOLD + 2500;
let x: Vec<f64> = (0..n).map(|i| i as f64).collect();
let y: Vec<f64> = x.iter().map(|v| (v * 0.02).cos()).collect();
let indices = DecimateMode::Auto.resolve_indices(&x, &y);
assert_eq!(indices.len(), DEFAULT_DECIMATE_THRESHOLD);
assert_eq!(*indices.first().unwrap(), 0);
assert_eq!(*indices.last().unwrap(), n - 1);
}
#[test]
fn scatter_auto_no_op_below_threshold() {
let n = 100;
let x: Vec<f64> = (0..n).map(|i| i as f64).collect();
let y = x.clone();
let indices = DecimateMode::Auto.resolve_indices(&x, &y);
assert_eq!(indices.len(), n);
assert_eq!(indices, (0..n).collect::<Vec<_>>());
}
#[test]
fn scatter_no_decimate_keeps_all_points() {
let n = DEFAULT_DECIMATE_THRESHOLD * 3;
let x: Vec<f64> = (0..n).map(|i| i as f64).collect();
let y = x.clone();
let indices = DecimateMode::Off.resolve_indices(&x, &y);
assert_eq!(indices.len(), n);
assert_eq!(*indices.first().unwrap(), 0);
assert_eq!(*indices.last().unwrap(), n - 1);
}
#[test]
fn scatter_explicit_minmax_overrides_auto() {
let n = 8000;
let x: Vec<f64> = (0..n).map(|i| i as f64).collect();
let y: Vec<f64> = x.iter().map(|v| (v * 0.03).sin()).collect();
let indices = DecimateMode::Explicit(300, DecimateMethod::MinMax).resolve_indices(&x, &y);
assert!(indices.len() <= 300);
assert_eq!(*indices.first().unwrap(), 0);
assert_eq!(*indices.last().unwrap(), n - 1);
}
}