plotters/coord/ranged1d/combinators/
nested.rs
1use crate::coord::ranged1d::{
2 AsRangedCoord, DiscreteRanged, KeyPointHint, NoDefaultFormatting, Ranged, ValueFormatter,
3};
4use std::ops::Range;
5
6#[derive(PartialEq, Eq, Clone, Debug)]
8pub enum NestedValue<C, V> {
9 Category(C),
11 Value(C, V),
13}
14
15impl<C, V> NestedValue<C, V> {
16 pub fn category(&self) -> &C {
18 match self {
19 NestedValue::Category(cat) => cat,
20 NestedValue::Value(cat, _) => cat,
21 }
22 }
23 pub fn nested_value(&self) -> Option<&V> {
25 match self {
26 NestedValue::Category(_) => None,
27 NestedValue::Value(_, val) => Some(val),
28 }
29 }
30}
31
32impl<C, V> From<(C, V)> for NestedValue<C, V> {
33 fn from((cat, val): (C, V)) -> NestedValue<C, V> {
34 NestedValue::Value(cat, val)
35 }
36}
37
38impl<C, V> From<C> for NestedValue<C, V> {
39 fn from(cat: C) -> NestedValue<C, V> {
40 NestedValue::Category(cat)
41 }
42}
43
44pub struct NestedRange<Primary: DiscreteRanged, Secondary: Ranged> {
49 primary: Primary,
50 secondary: Vec<Secondary>,
51}
52
53impl<PT, ST, P, S> ValueFormatter<NestedValue<PT, ST>> for NestedRange<P, S>
54where
55 P: Ranged<ValueType = PT> + DiscreteRanged,
56 S: Ranged<ValueType = ST>,
57 P: ValueFormatter<PT>,
58 S: ValueFormatter<ST>,
59{
60 fn format(value: &NestedValue<PT, ST>) -> String {
61 match value {
62 NestedValue::Category(cat) => P::format(cat),
63 NestedValue::Value(_, val) => S::format(val),
64 }
65 }
66}
67
68impl<P: DiscreteRanged, S: Ranged> Ranged for NestedRange<P, S> {
69 type FormatOption = NoDefaultFormatting;
70 type ValueType = NestedValue<P::ValueType, S::ValueType>;
71
72 fn range(&self) -> Range<Self::ValueType> {
73 let primary_range = self.primary.range();
74
75 let secondary_left = self.secondary[0].range().start;
76 let secondary_right = self.secondary[self.primary.size() - 1].range().end;
77
78 NestedValue::Value(primary_range.start, secondary_left)
79 ..NestedValue::Value(primary_range.end, secondary_right)
80 }
81
82 fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
83 let idx = self.primary.index_of(value.category()).unwrap_or(0);
84 let total = self.primary.size();
85
86 let bucket_size = (limit.1 - limit.0) / total as i32;
87 let mut residual = (limit.1 - limit.0) % total as i32;
88
89 if residual < 0 {
90 residual += total as i32;
91 }
92
93 let s_left = limit.0 + bucket_size * idx as i32 + residual.min(idx as i32);
94 let s_right = s_left + bucket_size + if (residual as usize) < idx { 1 } else { 0 };
95
96 if let Some(secondary_value) = value.nested_value() {
97 self.secondary[idx].map(secondary_value, (s_left, s_right))
98 } else {
99 (s_left + s_right) / 2
100 }
101 }
102
103 fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> {
104 if !hint.weight().allow_light_points() || hint.max_num_points() < self.primary.size() * 2 {
105 self.primary
106 .key_points(hint)
107 .into_iter()
108 .map(NestedValue::Category)
109 .collect()
110 } else {
111 let secondary_size =
112 (hint.max_num_points() - self.primary.size()) / self.primary.size();
113 self.primary
114 .values()
115 .enumerate()
116 .map(|(idx, val)| {
117 std::iter::once(NestedValue::Category(val)).chain(
118 self.secondary[idx]
119 .key_points(secondary_size)
120 .into_iter()
121 .map(move |v| {
122 NestedValue::Value(self.primary.from_index(idx).unwrap(), v)
123 }),
124 )
125 })
126 .flatten()
127 .collect()
128 }
129 }
130}
131
132impl<P: DiscreteRanged, S: DiscreteRanged> DiscreteRanged for NestedRange<P, S> {
133 fn size(&self) -> usize {
134 self.secondary.iter().map(|x| x.size()).sum::<usize>()
135 }
136
137 fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
138 let p_idx = self.primary.index_of(value.category())?;
139 let s_idx = self.secondary[p_idx].index_of(value.nested_value()?)?;
140 Some(
141 s_idx
142 + self.secondary[..p_idx]
143 .iter()
144 .map(|x| x.size())
145 .sum::<usize>(),
146 )
147 }
148
149 fn from_index(&self, mut index: usize) -> Option<Self::ValueType> {
150 for (p_idx, snd) in self.secondary.iter().enumerate() {
151 if snd.size() > index {
152 return Some(NestedValue::Value(
153 self.primary.from_index(p_idx).unwrap(),
154 snd.from_index(index).unwrap(),
155 ));
156 }
157 index -= snd.size();
158 }
159 None
160 }
161}
162
163pub trait BuildNestedCoord: AsRangedCoord
164where
165 Self::CoordDescType: DiscreteRanged,
166{
167 fn nested_coord<S: AsRangedCoord>(
168 self,
169 builder: impl Fn(<Self::CoordDescType as Ranged>::ValueType) -> S,
170 ) -> NestedRange<Self::CoordDescType, S::CoordDescType> {
171 let primary: Self::CoordDescType = self.into();
172 assert!(primary.size() > 0);
173
174 let secondary = primary
175 .values()
176 .map(|value| builder(value).into())
177 .collect();
178
179 NestedRange { primary, secondary }
180 }
181}
182
183impl<T: AsRangedCoord> BuildNestedCoord for T where T::CoordDescType: DiscreteRanged {}
184
185#[cfg(test)]
186mod test {
187 use super::*;
188
189 #[test]
190 fn test_nested_coord() {
191 let coord = (0..10).nested_coord(|x| 0..(x + 1));
192
193 let range = coord.range();
194
195 assert_eq!(NestedValue::Value(0, 0)..NestedValue::Value(10, 11), range);
196 assert_eq!(coord.map(&NestedValue::Category(0), (0, 1100)), 50);
197 assert_eq!(coord.map(&NestedValue::Value(0, 0), (0, 1100)), 0);
198 assert_eq!(coord.map(&NestedValue::Value(5, 4), (0, 1100)), 567);
199
200 assert_eq!(coord.size(), (2 + 12) * 11 / 2);
201 assert_eq!(coord.index_of(&NestedValue::Value(5, 4)), Some(24));
202 assert_eq!(coord.from_index(24), Some(NestedValue::Value(5, 4)));
203 }
204}