ggplot_rs/scale/
discrete.rs1use crate::aes::Aesthetic;
2use crate::data::Value;
3
4use super::Scale;
5
6#[derive(Clone, Debug)]
8pub struct ScaleDiscrete {
9 aesthetic: Aesthetic,
10 name: String,
11 levels: Vec<String>,
12 custom_labels: Option<Vec<String>>,
13 limits: Option<Vec<String>>,
15}
16
17impl ScaleDiscrete {
18 pub fn new() -> Self {
19 ScaleDiscrete {
20 aesthetic: Aesthetic::X,
21 name: String::new(),
22 levels: Vec::new(),
23 custom_labels: None,
24 limits: None,
25 }
26 }
27
28 pub fn for_aesthetic(mut self, aes: Aesthetic) -> Self {
29 self.aesthetic = aes;
30 self
31 }
32
33 pub fn with_name(mut self, name: &str) -> Self {
34 self.name = name.to_string();
35 self
36 }
37
38 pub fn with_labels(mut self, labels: Vec<String>) -> Self {
40 self.custom_labels = Some(labels);
41 self
42 }
43
44 pub fn with_limits(mut self, limits: Vec<&str>) -> Self {
47 self.limits = Some(limits.into_iter().map(|s| s.to_string()).collect());
48 self
49 }
50}
51
52impl ScaleDiscrete {
53 fn effective_levels(&self) -> &[String] {
55 if let Some(ref limits) = self.limits {
56 limits
57 } else {
58 &self.levels
59 }
60 }
61}
62
63impl Default for ScaleDiscrete {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl Scale for ScaleDiscrete {
70 fn aesthetic(&self) -> Aesthetic {
71 self.aesthetic.clone()
72 }
73
74 fn train(&mut self, values: &[Value]) {
75 if let Some(ref limits) = self.limits {
76 self.levels = limits.clone();
78 } else {
79 for v in values {
80 let key = v.to_group_key();
81 if !self.levels.contains(&key) {
82 self.levels.push(key);
83 }
84 }
85 }
86 }
87
88 fn map(&self, value: &Value) -> f64 {
89 let key = value.to_group_key();
90 let effective = self.effective_levels();
91 let n = effective.len();
92 if n == 0 {
93 return 0.5;
94 }
95 match effective.iter().position(|l| l == &key) {
96 Some(idx) => (idx as f64 + 0.5) / n as f64,
97 None => 0.5, }
99 }
100
101 fn breaks(&self) -> Vec<(f64, String)> {
102 let effective = self.effective_levels();
103 let n = effective.len();
104 if n == 0 {
105 return vec![];
106 }
107 effective
108 .iter()
109 .enumerate()
110 .map(|(i, level)| {
111 let pos = (i as f64 + 0.5) / n as f64;
112 let label = if let Some(ref labels) = self.custom_labels {
113 labels.get(i).cloned().unwrap_or_else(|| level.clone())
114 } else {
115 level.clone()
116 };
117 (pos, label)
118 })
119 .collect()
120 }
121
122 fn name(&self) -> &str {
123 &self.name
124 }
125
126 fn set_name(&mut self, name: &str) {
127 self.name = name.to_string();
128 }
129
130 fn is_discrete(&self) -> bool {
131 true
132 }
133
134 fn clone_box(&self) -> Box<dyn Scale> {
135 Box::new(self.clone())
136 }
137
138 fn reset_training(&mut self) {
139 if self.limits.is_none() {
140 self.levels.clear();
141 }
142 }
143}