1use crate::aes::Aesthetic;
2use crate::data::Value;
3use indexmap::IndexSet;
4
5use super::Scale;
6
7#[derive(Clone)]
11pub struct ScaleColorGrey {
12 aesthetic: Aesthetic,
13 name: String,
14 start: f64,
15 end: f64,
16 levels: IndexSet<String>,
17}
18
19impl ScaleColorGrey {
20 pub fn new(aesthetic: Aesthetic) -> Self {
21 ScaleColorGrey {
22 aesthetic,
23 name: String::new(),
24 start: 0.2,
25 end: 0.8,
26 levels: IndexSet::new(),
27 }
28 }
29
30 pub fn with_range(mut self, start: f64, end: f64) -> Self {
33 self.start = start;
34 self.end = end;
35 self
36 }
37
38 fn grey_for_index(&self, idx: usize) -> u8 {
39 let n = self.levels.len().max(1);
40 let t = if n == 1 {
41 (self.start + self.end) / 2.0
42 } else {
43 self.start + (self.end - self.start) * (idx as f64 / (n - 1) as f64)
44 };
45 (t.clamp(0.0, 1.0) * 255.0) as u8
46 }
47}
48
49impl Scale for ScaleColorGrey {
50 fn aesthetic(&self) -> Aesthetic {
51 self.aesthetic.clone()
52 }
53
54 fn train(&mut self, values: &[Value]) {
55 for v in values {
56 let key = v.key_str();
57 if !self.levels.contains(key.as_ref()) {
58 self.levels.insert(key.into_owned());
59 }
60 }
61 }
62
63 fn map(&self, value: &Value) -> f64 {
64 let key = value.key_str();
65 self.levels
66 .get_index_of(key.as_ref())
67 .map(|i| i as f64)
68 .unwrap_or(0.0)
69 }
70
71 fn breaks(&self) -> Vec<(f64, String)> {
72 self.levels
73 .iter()
74 .enumerate()
75 .map(|(i, label)| (i as f64, label.clone()))
76 .collect()
77 }
78
79 fn name(&self) -> &str {
80 &self.name
81 }
82
83 fn set_name(&mut self, name: &str) {
84 self.name = name.to_string();
85 }
86
87 fn is_discrete(&self) -> bool {
88 true
89 }
90
91 fn map_to_color(&self, value: &Value) -> Option<(u8, u8, u8)> {
92 let key = value.key_str();
93 let idx = self.levels.get_index_of(key.as_ref()).unwrap_or(0);
94 let g = self.grey_for_index(idx);
95 Some((g, g, g))
96 }
97
98 fn clone_box(&self) -> Box<dyn Scale> {
99 Box::new(self.clone())
100 }
101
102 fn reset_training(&mut self) {
103 self.levels.clear();
104 }
105}