Skip to main content

ggplot_rs/scale/
grey.rs

1use crate::aes::Aesthetic;
2use crate::data::Value;
3use indexmap::IndexSet;
4
5use super::Scale;
6
7/// Greyscale discrete color scale.
8/// Maps discrete levels to evenly-spaced grey values between `start` and `end`.
9/// Default range is 0.2 (dark grey) to 0.8 (light grey), where 0.0 = black and 1.0 = white.
10#[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    /// Set the grey range. `start` and `end` are values in [0, 1]
31    /// where 0.0 = black and 1.0 = white.
32    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}