1use crate::aes::Aesthetic;
2use crate::data::Value;
3
4use super::Scale;
5
6#[derive(Clone, Debug)]
8pub struct ScaleAlphaContinuous {
9 name: String,
10 min: f64,
11 max: f64,
12 trained: bool,
13 range: (f64, f64),
15 locale: Option<crate::locale::Locale>,
17}
18
19impl ScaleAlphaContinuous {
20 pub fn new() -> Self {
21 ScaleAlphaContinuous {
22 name: String::new(),
23 min: f64::INFINITY,
24 max: f64::NEG_INFINITY,
25 trained: false,
26 range: (0.1, 1.0),
27 locale: None,
28 }
29 }
30
31 pub fn with_range(mut self, min: f64, max: f64) -> Self {
32 self.range = (min, max);
33 self
34 }
35
36 pub fn with_name(mut self, name: &str) -> Self {
37 self.name = name.to_string();
38 self
39 }
40}
41
42impl Default for ScaleAlphaContinuous {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl Scale for ScaleAlphaContinuous {
49 fn set_default_locale(&mut self, locale: &crate::locale::Locale) {
50 if self.locale.is_none() {
51 self.locale = Some(locale.clone());
52 }
53 }
54
55 fn locale(&self) -> Option<&crate::locale::Locale> {
56 self.locale.as_ref()
57 }
58
59 fn aesthetic(&self) -> Aesthetic {
60 Aesthetic::Alpha
61 }
62
63 fn train(&mut self, values: &[Value]) {
64 for v in values {
65 if let Some(f) = v.as_f64() {
66 if f.is_finite() {
67 if f < self.min {
68 self.min = f;
69 }
70 if f > self.max {
71 self.max = f;
72 }
73 }
74 }
75 }
76 self.trained = true;
77 }
78
79 fn map(&self, value: &Value) -> f64 {
80 let f = match value.as_f64() {
81 Some(f) => f,
82 None => return 0.0,
83 };
84 let range = self.max - self.min;
85 if range.abs() < f64::EPSILON {
86 0.5
87 } else {
88 ((f - self.min) / range).clamp(0.0, 1.0)
89 }
90 }
91
92 fn breaks(&self) -> Vec<(f64, String)> {
93 if !self.trained || self.min > self.max {
94 return vec![];
95 }
96 let range = self.max - self.min;
97 if super::util::is_degenerate_range(self.min, self.max) {
98 return vec![(
99 0.5,
100 super::util::format_number_opt(self.min, self.locale.as_ref()),
101 )];
102 }
103 let n_breaks = 4;
104 let step = super::util::nice_step(range / n_breaks as f64);
105 let start = (self.min / step).ceil() * step;
106 let values = super::util::stepped_breaks(start, self.max, step);
107 let labels = super::util::format_numbers_opt(&values, self.locale.as_ref());
108 values
109 .iter()
110 .zip(labels)
111 .map(|(&v, l)| (self.map(&Value::Float(v)), l))
112 .collect()
113 }
114
115 fn name(&self) -> &str {
116 &self.name
117 }
118
119 fn set_name(&mut self, name: &str) {
120 self.name = name.to_string();
121 }
122
123 fn map_to_alpha(&self, value: &Value) -> Option<f64> {
124 let t = self.map(value);
125 let (lo, hi) = self.range;
126 Some(lo + t * (hi - lo))
127 }
128
129 fn map_fraction_to_alpha(&self, fraction: f64) -> Option<f64> {
130 let (lo, hi) = self.range;
131 Some(lo + fraction.clamp(0.0, 1.0) * (hi - lo))
132 }
133
134 fn clone_box(&self) -> Box<dyn Scale> {
135 Box::new(self.clone())
136 }
137
138 fn reset_training(&mut self) {
139 self.min = f64::INFINITY;
140 self.max = f64::NEG_INFINITY;
141 self.trained = false;
142 }
143}