ggplot_rs/scale/
shape_manual.rs1use crate::aes::Aesthetic;
2use crate::data::Value;
3use crate::render::backend::PointShape;
4use indexmap::IndexSet;
5
6use super::Scale;
7
8#[derive(Clone, Debug)]
10pub struct ScaleShapeManual {
11 name: String,
12 levels: IndexSet<String>,
13 shapes: Vec<PointShape>,
14}
15
16impl ScaleShapeManual {
17 pub fn new(values: Vec<(&str, PointShape)>) -> Self {
18 let levels: IndexSet<String> = values.iter().map(|(k, _)| k.to_string()).collect();
19 let shapes: Vec<PointShape> = values.iter().map(|(_, s)| *s).collect();
20 ScaleShapeManual {
21 name: String::new(),
22 levels,
23 shapes,
24 }
25 }
26}
27
28impl Scale for ScaleShapeManual {
29 fn aesthetic(&self) -> Aesthetic {
30 Aesthetic::Shape
31 }
32
33 fn train(&mut self, values: &[Value]) {
34 for v in values {
35 let key = v.key_str();
36 if !self.levels.contains(key.as_ref()) {
37 self.levels.insert(key.into_owned());
38 }
39 }
40 }
41
42 fn map(&self, value: &Value) -> f64 {
43 let key = value.key_str();
44 self.levels
45 .get_index_of(key.as_ref())
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_shape(&self, value: &Value) -> Option<PointShape> {
71 if self.shapes.is_empty() {
73 return None;
74 }
75 let key = value.key_str();
76 let idx = self.levels.get_index_of(key.as_ref()).unwrap_or(0);
77 Some(self.shapes[idx % self.shapes.len()])
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}