1// The customized coordinate combinators.
2// This file contains a set of coorindate combinators that allows you determine the
3// keypoint by your own code.
4use std::ops::Range;
5
6use crate::coord::ranged1d::{AsRangedCoord, DiscreteRanged, KeyPointHint, Ranged};
7
8/// The coordinate decorator that binds a key point vector.
9/// Normally, all the ranged coordinate implements its own keypoint algorithm
10/// to determine how to render the tick mark and mesh grid.
11/// This decorator allows customized tick mark specifiied by vector.
12/// See [BindKeyPoints::with_key_points](trait.BindKeyPoints.html#tymethod.with_key_points)
13/// for details.
14/// Note: For any coordinate spec wrapped by this decorator, the maxium number of labels configured by
15/// MeshStyle will be ignored and the key point function will always returns the entire vector
16pub struct WithKeyPoints<Inner: Ranged> {
17 inner: Inner,
18 bold_points: Vec<Inner::ValueType>,
19 light_points: Vec<Inner::ValueType>,
20}
21
22impl<I: Ranged> WithKeyPoints<I> {
23 /// Specify the light key points, which is used to render the light mesh line
24 pub fn with_light_points<T: IntoIterator<Item = I::ValueType>>(mut self, iter: T) -> Self {
25 self.light_points.clear();
26 self.light_points.extend(iter);
27 self
28 }
29
30 /// Get a reference to the bold points
31 pub fn bold_points(&self) -> &[I::ValueType] {
32 self.bold_points.as_ref()
33 }
34
35 /// Get a mut reference to the bold points
36 pub fn bold_points_mut(&mut self) -> &mut [I::ValueType] {
37 self.bold_points.as_mut()
38 }
39
40 /// Get a reference to light key points
41 pub fn light_points(&self) -> &[I::ValueType] {
42 self.light_points.as_ref()
43 }
44
45 /// Get a mut reference to the light key points
46 pub fn light_points_mut(&mut self) -> &mut [I::ValueType] {
47 self.light_points.as_mut()
48 }
49}
50
51impl<R: Ranged> Ranged for WithKeyPoints<R>
52where
53 R::ValueType: Clone,
54{
55 type ValueType = R::ValueType;
56 type FormatOption = R::FormatOption;
57
58 fn range(&self) -> Range<Self::ValueType> {
59 self.inner.range()
60 }
61
62 fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
63 self.inner.map(value, limit)
64 }
65
66 fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> {
67 if hint.weight().allow_light_points() {
68 self.light_points.clone()
69 } else {
70 self.bold_points.clone()
71 }
72 }
73
74 fn axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32> {
75 self.inner.axis_pixel_range(limit)
76 }
77}
78
79impl<R: DiscreteRanged> DiscreteRanged for WithKeyPoints<R>
80where
81 R::ValueType: Clone,
82{
83 fn size(&self) -> usize {
84 self.inner.size()
85 }
86 fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
87 self.inner.index_of(value)
88 }
89 fn from_index(&self, index: usize) -> Option<Self::ValueType> {
90 self.inner.from_index(index)
91 }
92}
93
94/// Bind a existing coordinate spec with a given key points vector. See [WithKeyPoints](struct.WithKeyPoints.html ) for more details.
95pub trait BindKeyPoints
96where
97 Self: AsRangedCoord,
98{
99 /// Bind a existing coordinate spec with a given key points vector. See [WithKeyPoints](struct.WithKeyPoints.html ) for more details.
100 /// Example:
101 /// ```
102 ///use plotters::prelude::*;
103 ///use plotters_bitmap::BitMapBackend;
104 ///let mut buffer = vec![0;1024*768*3];
105 /// let root = BitMapBackend::with_buffer(&mut buffer, (1024, 768)).into_drawing_area();
106 /// let mut chart = ChartBuilder::on(&root)
107 /// .build_cartesian_2d(
108 /// (0..100).with_key_points(vec![1,20,50,90]), // <= This line will make the plot shows 4 tick marks at 1, 20, 50, 90
109 /// 0..10
110 /// ).unwrap();
111 /// chart.configure_mesh().draw().unwrap();
112 ///```
113 fn with_key_points(self, points: Vec<Self::Value>) -> WithKeyPoints<Self::CoordDescType> {
114 WithKeyPoints {
115 inner: self.into(),
116 bold_points: points,
117 light_points: vec![],
118 }
119 }
120}
121
122impl<T: AsRangedCoord> BindKeyPoints for T {}
123
124/// The coordinate decorator that allows customized keypoint algorithms.
125/// Normally, all the coordinate spec implements its own key point algorith
126/// But this decorator allows you override the pre-defined key point algorithm.
127///
128/// To use this decorator, see [BindKeyPointMethod::with_key_point_func](trait.BindKeyPointMethod.html#tymethod.with_key_point_func)
129pub struct WithKeyPointMethod<R: Ranged> {
130 inner: R,
131 bold_func: Box<dyn Fn(usize) -> Vec<R::ValueType>>,
132 light_func: Box<dyn Fn(usize) -> Vec<R::ValueType>>,
133}
134
135/// Bind an existing coordinate spec with a given key points algorithm. See [WithKeyPointMethod](struct.WithKeyMethod.html ) for more details.
136pub trait BindKeyPointMethod
137where
138 Self: AsRangedCoord,
139{
140 /// Bind a existing coordinate spec with a given key points algorithm. See [WithKeyPointMethod](struct.WithKeyMethod.html ) for more details.
141 /// Example:
142 /// ```
143 ///use plotters::prelude::*;
144 ///use plotters_bitmap::BitMapBackend;
145 ///let mut buffer = vec![0;1024*768*3];
146 /// let root = BitMapBackend::with_buffer(&mut buffer, (1024, 768)).into_drawing_area();
147 /// let mut chart = ChartBuilder::on(&root)
148 /// .build_cartesian_2d(
149 /// (0..100).with_key_point_func(|n| (0..100 / n as i32).map(|x| x * 100 / n as i32).collect()),
150 /// 0..10
151 /// ).unwrap();
152 /// chart.configure_mesh().draw().unwrap();
153 ///```
154 fn with_key_point_func<F: Fn(usize) -> Vec<Self::Value> + 'static>(
155 self,
156 func: F,
157 ) -> WithKeyPointMethod<Self::CoordDescType> {
158 WithKeyPointMethod {
159 inner: self.into(),
160 bold_func: Box::new(func),
161 light_func: Box::new(|_| Vec::new()),
162 }
163 }
164}
165
166impl<T: AsRangedCoord> BindKeyPointMethod for T {}
167
168impl<R: Ranged> WithKeyPointMethod<R> {
169 /// Define the light key point algorithm, by default this returns an empty set
170 pub fn with_light_point_func<F: Fn(usize) -> Vec<R::ValueType> + 'static>(
171 mut self,
172 func: F,
173 ) -> Self {
174 self.light_func = Box::new(func);
175 self
176 }
177}
178
179impl<R: Ranged> Ranged for WithKeyPointMethod<R> {
180 type ValueType = R::ValueType;
181 type FormatOption = R::FormatOption;
182
183 fn range(&self) -> Range<Self::ValueType> {
184 self.inner.range()
185 }
186
187 fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
188 self.inner.map(value, limit)
189 }
190
191 fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> {
192 if hint.weight().allow_light_points() {
193 (self.light_func)(hint.max_num_points())
194 } else {
195 (self.bold_func)(hint.max_num_points())
196 }
197 }
198
199 fn axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32> {
200 self.inner.axis_pixel_range(limit)
201 }
202}
203
204impl<R: DiscreteRanged> DiscreteRanged for WithKeyPointMethod<R> {
205 fn size(&self) -> usize {
206 self.inner.size()
207 }
208 fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
209 self.inner.index_of(value)
210 }
211 fn from_index(&self, index: usize) -> Option<Self::ValueType> {
212 self.inner.from_index(index)
213 }
214}
215
216#[cfg(test)]
217mod test {
218 use super::*;
219 use crate::coord::ranged1d::{BoldPoints, LightPoints};
220 #[test]
221 fn test_with_key_points() {
222 let range = (0..100).with_key_points(vec![1, 2, 3]);
223 assert_eq!(range.map(&3, (0, 1000)), 30);
224 assert_eq!(range.range(), 0..100);
225 assert_eq!(range.key_points(BoldPoints(100)), vec![1, 2, 3]);
226 assert_eq!(range.key_points(LightPoints::new(100, 100)), vec![]);
227 let range = range.with_light_points(5..10);
228 assert_eq!(range.key_points(BoldPoints(10)), vec![1, 2, 3]);
229 assert_eq!(
230 range.key_points(LightPoints::new(10, 10)),
231 (5..10).collect::<Vec<_>>()
232 );
233
234 assert_eq!(range.size(), 101);
235 assert_eq!(range.index_of(&10), Some(10));
236 assert_eq!(range.from_index(10), Some(10));
237
238 assert_eq!(range.axis_pixel_range((0, 1000)), 0..1000);
239
240 let mut range = range;
241
242 assert_eq!(range.light_points().len(), 5);
243 assert_eq!(range.light_points_mut().len(), 5);
244 assert_eq!(range.bold_points().len(), 3);
245 assert_eq!(range.bold_points_mut().len(), 3);
246 }
247
248 #[test]
249 fn test_with_key_point_method() {
250 let range = (0..100).with_key_point_func(|_| vec![1, 2, 3]);
251 assert_eq!(range.map(&3, (0, 1000)), 30);
252 assert_eq!(range.range(), 0..100);
253 assert_eq!(range.key_points(BoldPoints(100)), vec![1, 2, 3]);
254 assert_eq!(range.key_points(LightPoints::new(100, 100)), vec![]);
255 let range = range.with_light_point_func(|_| (5..10).collect());
256 assert_eq!(range.key_points(BoldPoints(10)), vec![1, 2, 3]);
257 assert_eq!(
258 range.key_points(LightPoints::new(10, 10)),
259 (5..10).collect::<Vec<_>>()
260 );
261
262 assert_eq!(range.size(), 101);
263 assert_eq!(range.index_of(&10), Some(10));
264 assert_eq!(range.from_index(10), Some(10));
265
266 assert_eq!(range.axis_pixel_range((0, 1000)), 0..1000);
267 }
268}
269