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