Skip to main content

ggplot_rs/scale/
linetype.rs

1use crate::aes::Aesthetic;
2use crate::data::Value;
3use crate::render::backend::Linetype;
4use indexmap::IndexSet;
5
6use super::Scale;
7
8/// Discrete linetype scale — maps categories to line dash patterns.
9#[derive(Clone, Debug)]
10pub struct ScaleLinetypeDiscrete {
11    name: String,
12    levels: IndexSet<String>,
13}
14
15impl Default for ScaleLinetypeDiscrete {
16    fn default() -> Self {
17        Self::new()
18    }
19}
20
21impl ScaleLinetypeDiscrete {
22    pub fn new() -> Self {
23        ScaleLinetypeDiscrete {
24            name: String::new(),
25            levels: IndexSet::new(),
26        }
27    }
28}
29
30impl Scale for ScaleLinetypeDiscrete {
31    fn aesthetic(&self) -> Aesthetic {
32        Aesthetic::Linetype
33    }
34
35    fn train(&mut self, values: &[Value]) {
36        for v in values {
37            let key = v.key_str();
38            if !self.levels.contains(key.as_ref()) {
39                self.levels.insert(key.into_owned());
40            }
41        }
42    }
43
44    fn map(&self, value: &Value) -> f64 {
45        let key = value.key_str();
46        self.levels
47            .get_index_of(key.as_ref())
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_linetype(&self, value: &Value) -> Option<Linetype> {
73        let key = value.key_str();
74        let idx = self.levels.get_index_of(key.as_ref()).unwrap_or(0);
75        Some(Linetype::ALL[idx % Linetype::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}