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.
4 use std::ops::Range;
5 
6 use 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
16 pub struct WithKeyPoints<Inner: Ranged> {
17     inner: Inner,
18     bold_points: Vec<Inner::ValueType>,
19     light_points: Vec<Inner::ValueType>,
20 }
21 
22 impl<I: Ranged> WithKeyPoints<I> {
23     /// Specify the light key points, which is used to render the light mesh line
with_light_points<T: IntoIterator<Item = I::ValueType>>(mut self, iter: T) -> Self24     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
bold_points(&self) -> &[I::ValueType]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
bold_points_mut(&mut self) -> &mut [I::ValueType]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
light_points(&self) -> &[I::ValueType]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
light_points_mut(&mut self) -> &mut [I::ValueType]46     pub fn light_points_mut(&mut self) -> &mut [I::ValueType] {
47         self.light_points.as_mut()
48     }
49 }
50 
51 impl<R: Ranged> Ranged for WithKeyPoints<R>
52 where
53     R::ValueType: Clone,
54 {
55     type ValueType = R::ValueType;
56     type FormatOption = R::FormatOption;
57 
range(&self) -> Range<Self::ValueType>58     fn range(&self) -> Range<Self::ValueType> {
59         self.inner.range()
60     }
61 
map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i3262     fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
63         self.inner.map(value, limit)
64     }
65 
key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType>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 
axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32>74     fn axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32> {
75         self.inner.axis_pixel_range(limit)
76     }
77 }
78 
79 impl<R: DiscreteRanged> DiscreteRanged for WithKeyPoints<R>
80 where
81     R::ValueType: Clone,
82 {
size(&self) -> usize83     fn size(&self) -> usize {
84         self.inner.size()
85     }
index_of(&self, value: &Self::ValueType) -> Option<usize>86     fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
87         self.inner.index_of(value)
88     }
from_index(&self, index: usize) -> Option<Self::ValueType>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.
95 pub trait BindKeyPoints
96 where
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     ///```
with_key_points(self, points: Vec<Self::Value>) -> WithKeyPoints<Self::CoordDescType>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 
122 impl<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)
129 pub 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.
136 pub trait BindKeyPointMethod
137 where
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     ///```
with_key_point_func<F: Fn(usize) -> Vec<Self::Value> + 'static>( self, func: F, ) -> WithKeyPointMethod<Self::CoordDescType>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 
166 impl<T: AsRangedCoord> BindKeyPointMethod for T {}
167 
168 impl<R: Ranged> WithKeyPointMethod<R> {
169     /// Define the light key point algorithm, by default this returns an empty set
with_light_point_func<F: Fn(usize) -> Vec<R::ValueType> + 'static>( mut self, func: F, ) -> Self170     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 
179 impl<R: Ranged> Ranged for WithKeyPointMethod<R> {
180     type ValueType = R::ValueType;
181     type FormatOption = R::FormatOption;
182 
range(&self) -> Range<Self::ValueType>183     fn range(&self) -> Range<Self::ValueType> {
184         self.inner.range()
185     }
186 
map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32187     fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
188         self.inner.map(value, limit)
189     }
190 
key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType>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 
axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32>199     fn axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32> {
200         self.inner.axis_pixel_range(limit)
201     }
202 }
203 
204 impl<R: DiscreteRanged> DiscreteRanged for WithKeyPointMethod<R> {
size(&self) -> usize205     fn size(&self) -> usize {
206         self.inner.size()
207     }
index_of(&self, value: &Self::ValueType) -> Option<usize>208     fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
209         self.inner.index_of(value)
210     }
from_index(&self, index: usize) -> Option<Self::ValueType>211     fn from_index(&self, index: usize) -> Option<Self::ValueType> {
212         self.inner.from_index(index)
213     }
214 }
215 
216 #[cfg(test)]
217 mod test {
218     use super::*;
219     use crate::coord::ranged1d::{BoldPoints, LightPoints};
220     #[test]
test_with_key_points()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]
test_with_key_point_method()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