1use crate::aes::Aesthetic;
2use crate::data::Value;
3
4use super::util::{format_number, nice_step};
5use super::Scale;
6
7#[derive(Clone, Debug, Copy)]
9pub struct RGBAColor {
10 pub r: u8,
11 pub g: u8,
12 pub b: u8,
13 pub a: f64,
14}
15
16impl RGBAColor {
17 pub fn new(r: u8, g: u8, b: u8) -> Self {
18 RGBAColor { r, g, b, a: 1.0 }
19 }
20
21 pub fn with_alpha(mut self, a: f64) -> Self {
22 self.a = a;
23 self
24 }
25
26 pub fn lerp(&self, other: &RGBAColor, t: f64) -> RGBAColor {
28 let t = t.clamp(0.0, 1.0);
29 RGBAColor {
30 r: (self.r as f64 * (1.0 - t) + other.r as f64 * t) as u8,
31 g: (self.g as f64 * (1.0 - t) + other.g as f64 * t) as u8,
32 b: (self.b as f64 * (1.0 - t) + other.b as f64 * t) as u8,
33 a: self.a * (1.0 - t) + other.a * t,
34 }
35 }
36}
37
38pub const DEFAULT_PALETTE: &[RGBAColor] = &[
40 RGBAColor {
41 r: 248,
42 g: 118,
43 b: 109,
44 a: 1.0,
45 }, RGBAColor {
47 r: 0,
48 g: 186,
49 b: 56,
50 a: 1.0,
51 }, RGBAColor {
53 r: 97,
54 g: 156,
55 b: 255,
56 a: 1.0,
57 }, RGBAColor {
59 r: 163,
60 g: 103,
61 b: 203,
62 a: 1.0,
63 }, RGBAColor {
65 r: 231,
66 g: 138,
67 b: 0,
68 a: 1.0,
69 }, RGBAColor {
71 r: 0,
72 g: 191,
73 b: 196,
74 a: 1.0,
75 }, RGBAColor {
77 r: 199,
78 g: 124,
79 b: 255,
80 a: 1.0,
81 }, RGBAColor {
83 r: 127,
84 g: 127,
85 b: 127,
86 a: 1.0,
87 }, ];
89
90#[derive(Clone, Debug)]
92pub struct ScaleColorDiscrete {
93 aesthetic: Aesthetic,
94 name: String,
95 levels: Vec<String>,
96 palette: Vec<RGBAColor>,
97}
98
99impl ScaleColorDiscrete {
100 pub fn new(aesthetic: Aesthetic) -> Self {
101 ScaleColorDiscrete {
102 aesthetic,
103 name: String::new(),
104 levels: Vec::new(),
105 palette: DEFAULT_PALETTE.to_vec(),
106 }
107 }
108
109 pub fn with_palette(mut self, colors: Vec<RGBAColor>) -> Self {
110 self.palette = colors;
111 self
112 }
113
114 pub fn with_named_palette(mut self, name: &super::palettes::PaletteName) -> Self {
115 self.palette = super::palettes::palette(name).to_vec();
116 self
117 }
118
119 pub fn with_levels(mut self, levels: Vec<String>) -> Self {
123 self.levels = levels;
124 self
125 }
126
127 pub fn color_for_index(&self, idx: usize) -> RGBAColor {
129 self.palette[idx % self.palette.len()]
130 }
131
132 pub fn color_for_value(&self, value: &Value) -> RGBAColor {
134 let key = value.to_group_key();
135 let idx = self.levels.iter().position(|l| l == &key).unwrap_or(0);
136 self.color_for_index(idx)
137 }
138
139 pub fn levels(&self) -> &[String] {
140 &self.levels
141 }
142}
143
144impl Scale for ScaleColorDiscrete {
145 fn aesthetic(&self) -> Aesthetic {
146 self.aesthetic.clone()
147 }
148
149 fn train(&mut self, values: &[Value]) {
150 for v in values {
151 let key = v.to_group_key();
152 if !self.levels.contains(&key) {
153 self.levels.push(key);
154 }
155 }
156 }
157
158 fn map(&self, value: &Value) -> f64 {
159 let key = value.to_group_key();
160 self.levels
161 .iter()
162 .position(|l| l == &key)
163 .map(|i| i as f64)
164 .unwrap_or(0.0)
165 }
166
167 fn breaks(&self) -> Vec<(f64, String)> {
168 self.levels
169 .iter()
170 .enumerate()
171 .map(|(i, label)| (i as f64, label.clone()))
172 .collect()
173 }
174
175 fn name(&self) -> &str {
176 &self.name
177 }
178
179 fn set_name(&mut self, name: &str) {
180 self.name = name.to_string();
181 }
182
183 fn is_discrete(&self) -> bool {
184 true
185 }
186
187 fn map_to_color(&self, value: &Value) -> Option<(u8, u8, u8)> {
188 let c = self.color_for_value(value);
189 Some((c.r, c.g, c.b))
190 }
191
192 fn clone_box(&self) -> Box<dyn Scale> {
193 Box::new(self.clone())
194 }
195
196 fn reset_training(&mut self) {
197 self.levels.clear();
198 }
199}
200
201#[derive(Clone, Debug)]
203pub struct ScaleColorContinuous {
204 aesthetic: Aesthetic,
205 name: String,
206 low: RGBAColor,
207 high: RGBAColor,
208 min: f64,
209 max: f64,
210}
211
212impl ScaleColorContinuous {
213 pub fn new(aesthetic: Aesthetic) -> Self {
214 ScaleColorContinuous {
215 aesthetic,
216 name: String::new(),
217 low: RGBAColor::new(0, 0, 255),
218 high: RGBAColor::new(255, 0, 0),
219 min: f64::INFINITY,
220 max: f64::NEG_INFINITY,
221 }
222 }
223
224 pub fn with_colors(mut self, low: RGBAColor, high: RGBAColor) -> Self {
225 self.low = low;
226 self.high = high;
227 self
228 }
229
230 pub fn color_at(&self, t: f64) -> RGBAColor {
231 self.low.lerp(&self.high, t)
232 }
233}
234
235impl Scale for ScaleColorContinuous {
236 fn aesthetic(&self) -> Aesthetic {
237 self.aesthetic.clone()
238 }
239
240 fn train(&mut self, values: &[Value]) {
241 for v in values {
242 if let Some(f) = v.as_f64() {
243 if f.is_finite() {
244 if f < self.min {
245 self.min = f;
246 }
247 if f > self.max {
248 self.max = f;
249 }
250 }
251 }
252 }
253 }
254
255 fn map(&self, value: &Value) -> f64 {
256 let f = match value.as_f64() {
257 Some(f) => f,
258 None => return 0.0,
259 };
260 let range = self.max - self.min;
261 if range.abs() < f64::EPSILON {
262 0.5
263 } else {
264 (f - self.min) / range
265 }
266 }
267
268 fn breaks(&self) -> Vec<(f64, String)> {
269 if self.min > self.max || !self.min.is_finite() || !self.max.is_finite() {
270 return vec![];
271 }
272
273 let range = self.max - self.min;
274 if range.abs() < f64::EPSILON {
275 return vec![(0.5, format_number(self.min))];
276 }
277
278 let n_breaks = 5;
279 let raw_step = range / n_breaks as f64;
280 let step = nice_step(raw_step);
281
282 let start = (self.min / step).ceil() * step;
283 let mut breaks = Vec::new();
284 let mut v = start;
285 while v <= self.max + step * 0.001 {
286 let pos = self.map(&Value::Float(v));
287 breaks.push((pos, format_number(v)));
288 v += step;
289 }
290 breaks
291 }
292
293 fn name(&self) -> &str {
294 &self.name
295 }
296
297 fn set_name(&mut self, name: &str) {
298 self.name = name.to_string();
299 }
300
301 fn map_to_color(&self, value: &Value) -> Option<(u8, u8, u8)> {
302 let t = self.map(value);
303 let c = self.color_at(t);
304 Some((c.r, c.g, c.b))
305 }
306
307 fn domain(&self) -> Option<(f64, f64)> {
308 if self.min.is_finite() && self.max.is_finite() && self.min <= self.max {
309 Some((self.min, self.max))
310 } else {
311 None
312 }
313 }
314
315 fn clone_box(&self) -> Box<dyn Scale> {
316 Box::new(self.clone())
317 }
318
319 fn reset_training(&mut self) {
320 self.min = f64::INFINITY;
321 self.max = f64::NEG_INFINITY;
322 }
323}