ggplot_rs/scale/
linetype.rs1use crate::aes::Aesthetic;
2use crate::data::Value;
3use crate::render::backend::Linetype;
4use indexmap::IndexSet;
5
6use super::Scale;
7
8#[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}