Skip to main content

ggplot_rs/scale/
shape_manual.rs

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