Skip to main content

ggplot_rs/scale/
shape.rs

1use crate::aes::Aesthetic;
2use crate::data::Value;
3use crate::render::backend::PointShape;
4
5use super::Scale;
6
7/// Discrete shape scale — maps categories to point shapes.
8#[derive(Clone, Debug)]
9pub struct ScaleShapeDiscrete {
10    name: String,
11    levels: Vec<String>,
12}
13
14impl Default for ScaleShapeDiscrete {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl ScaleShapeDiscrete {
21    pub fn new() -> Self {
22        ScaleShapeDiscrete {
23            name: String::new(),
24            levels: Vec::new(),
25        }
26    }
27}
28
29impl Scale for ScaleShapeDiscrete {
30    fn aesthetic(&self) -> Aesthetic {
31        Aesthetic::Shape
32    }
33
34    fn train(&mut self, values: &[Value]) {
35        for v in values {
36            let key = v.to_group_key();
37            if !self.levels.contains(&key) {
38                self.levels.push(key);
39            }
40        }
41    }
42
43    fn map(&self, value: &Value) -> f64 {
44        let key = value.to_group_key();
45        self.levels
46            .iter()
47            .position(|l| l == &key)
48            .map(|i| i as f64)
49            .unwrap_or(0.0)
50    }
51
52    fn breaks(&self) -> Vec<(f64, String)> {
53        self.levels
54            .iter()
55            .enumerate()
56            .map(|(i, label)| (i as f64, label.clone()))
57            .collect()
58    }
59
60    fn name(&self) -> &str {
61        &self.name
62    }
63
64    fn set_name(&mut self, name: &str) {
65        self.name = name.to_string();
66    }
67
68    fn is_discrete(&self) -> bool {
69        true
70    }
71
72    fn map_to_shape(&self, value: &Value) -> Option<PointShape> {
73        let key = value.to_group_key();
74        let idx = self.levels.iter().position(|l| l == &key).unwrap_or(0);
75        Some(PointShape::ALL[idx % PointShape::ALL.len()])
76    }
77
78    fn clone_box(&self) -> Box<dyn Scale> {
79        Box::new(self.clone())
80    }
81
82    fn reset_training(&mut self) {
83        self.levels.clear();
84    }
85}