pub mod alpha;
pub mod binned;
pub mod bivariate;
pub mod color;
pub mod continuous;
pub mod datetime;
pub mod discrete;
pub mod format;
pub mod gradient;
pub mod gradient_n;
pub mod grey;
pub mod identity;
pub mod linetype;
pub mod linetype_manual;
pub mod linewidth;
pub mod manual;
pub mod modified;
pub mod palettes;
pub mod scale_set;
pub mod sec_axis;
pub mod shape;
pub mod shape_manual;
pub mod size;
pub mod steps;
pub mod transform;
pub mod util;
pub use scale_set::ScaleSet;
use crate::aes::Aesthetic;
use crate::data::Value;
use crate::render::backend::{Linetype, PointShape};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Oob {
#[default]
Censor,
Squish,
}
pub(crate) const DEFAULT_NA_VALUE: (u8, u8, u8) = (127, 127, 127);
pub(crate) fn resolve_oob(f: f64, limits: Option<(f64, f64)>, oob: Oob) -> Option<f64> {
let Some((lo, hi)) = limits else {
return Some(f);
};
if lo > hi {
return None;
}
if f < lo || f > hi {
match oob {
Oob::Squish => Some(f.clamp(lo, hi)),
Oob::Censor => None,
}
} else {
Some(f)
}
}
pub trait Scale: Send + Sync {
fn aesthetic(&self) -> Aesthetic;
fn train(&mut self, values: &[Value]);
fn map(&self, value: &Value) -> f64;
fn breaks(&self) -> Vec<(f64, String)>;
fn name(&self) -> &str;
fn set_name(&mut self, name: &str);
fn transform(&self, value: &Value) -> Value {
value.clone()
}
fn is_discrete(&self) -> bool {
false
}
fn map_to_color(&self, _value: &Value) -> Option<(u8, u8, u8)> {
None
}
fn map_to_shape(&self, _value: &Value) -> Option<PointShape> {
None
}
fn map_to_linetype(&self, _value: &Value) -> Option<Linetype> {
None
}
fn map_to_size(&self, _value: &Value) -> Option<f64> {
None
}
fn map_to_alpha(&self, _value: &Value) -> Option<f64> {
None
}
fn sec_axis(&self) -> Option<&sec_axis::SecAxis> {
None
}
fn set_default_locale(&mut self, _locale: &crate::locale::Locale) {}
fn locale(&self) -> Option<&crate::locale::Locale> {
None
}
fn format_value(&self, _value: &Value) -> Option<String> {
None
}
fn set_limits(&mut self, _min: f64, _max: f64) {
}
fn filter_limits(&self) -> Option<(f64, f64)> {
None
}
fn domain(&self) -> Option<(f64, f64)> {
None
}
fn expanded_domain(&self) -> Option<(f64, f64)> {
None
}
fn axis_position_opposite(&self) -> bool {
false
}
fn set_expand(&mut self, _mult: f64, _add: f64) {}
fn map_fraction_to_size(&self, _fraction: f64) -> Option<f64> {
None
}
fn map_fraction_to_alpha(&self, _fraction: f64) -> Option<f64> {
None
}
fn clone_box(&self) -> Box<dyn Scale>;
fn reset_training(&mut self) {}
fn validate(&self, _warnings: &mut Vec<String>) {}
}
#[cfg(test)]
mod default_trait_method_tests {
use super::Scale;
use crate::aes::Aesthetic;
use crate::data::Value;
#[test]
fn set_expand_and_map_fraction_to_size_defaults_are_harmless() {
let mut scale = crate::scale::identity::ScaleColorIdentity::new(Aesthetic::Color);
scale.set_expand(0.1, 5.0);
assert_eq!(scale.map_fraction_to_size(0.5), None);
assert_eq!(scale.map_fraction_to_alpha(0.5), None);
let mut warnings = Vec::new();
scale.validate(&mut warnings);
assert!(warnings.is_empty());
assert_eq!(
scale.map_to_color(&Value::Str("#FFFFFF".into())),
Some((255, 255, 255))
);
assert_eq!(scale.format_value(&Value::Str("#FFFFFF".into())), None);
}
#[test]
fn resolve_oob_without_limits_always_passes_through() {
assert_eq!(
super::resolve_oob(42.0, None, super::Oob::Censor),
Some(42.0)
);
assert_eq!(
super::resolve_oob(-5.0, None, super::Oob::Squish),
Some(-5.0)
);
}
}