Skip to main content

ggplot_rs/scale/
linetype_manual.rs

1use crate::aes::Aesthetic;
2use crate::data::Value;
3use crate::render::backend::Linetype;
4
5use super::Scale;
6
7/// Manual linetype scale — maps named levels to user-specified linetypes.
8#[derive(Clone, Debug)]
9pub struct ScaleLinetypeManual {
10    name: String,
11    levels: Vec<String>,
12    linetypes: Vec<Linetype>,
13}
14
15impl ScaleLinetypeManual {
16    pub fn new(values: Vec<(&str, Linetype)>) -> Self {
17        let levels: Vec<String> = values.iter().map(|(k, _)| k.to_string()).collect();
18        let linetypes: Vec<Linetype> = values.iter().map(|(_, lt)| *lt).collect();
19        ScaleLinetypeManual {
20            name: String::new(),
21            levels,
22            linetypes,
23        }
24    }
25}
26
27impl Scale for ScaleLinetypeManual {
28    fn aesthetic(&self) -> Aesthetic {
29        Aesthetic::Linetype
30    }
31
32    fn train(&mut self, values: &[Value]) {
33        for v in values {
34            let key = v.to_group_key();
35            if !self.levels.contains(&key) {
36                self.levels.push(key);
37            }
38        }
39    }
40
41    fn map(&self, value: &Value) -> f64 {
42        let key = value.to_group_key();
43        self.levels
44            .iter()
45            .position(|l| l == &key)
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_linetype(&self, value: &Value) -> Option<Linetype> {
71        let key = value.to_group_key();
72        let idx = self.levels.iter().position(|l| l == &key).unwrap_or(0);
73        if idx < self.linetypes.len() {
74            Some(self.linetypes[idx])
75        } else {
76            Some(self.linetypes[idx % self.linetypes.len()])
77        }
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}