• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 pub trait BindKeyPoints
95 where
96     Self: AsRangedCoord,
97 {
98     /// Bind a existing coordinate spec with a given key points vector. See [WithKeyPoints](struct.WithKeyPoints.html ) for more details.
99     /// Example:
100     /// ```
101     ///use plotters::prelude::*;
102     ///use plotters_bitmap::BitMapBackend;
103     ///let mut buffer = vec![0;1024*768*3];
104     /// let root = BitMapBackend::with_buffer(&mut buffer, (1024, 768)).into_drawing_area();
105     /// let mut chart = ChartBuilder::on(&root)
106     ///    .build_ranged(
107     ///        (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
108     ///        0..10
109     /// ).unwrap();
110     /// chart.configure_mesh().draw().unwrap();
111     ///```
with_key_points(self, points: Vec<Self::Value>) -> WithKeyPoints<Self::CoordDescType>112     fn with_key_points(self, points: Vec<Self::Value>) -> WithKeyPoints<Self::CoordDescType> {
113         WithKeyPoints {
114             inner: self.into(),
115             bold_points: points,
116             light_points: vec![],
117         }
118     }
119 }
120 
121 impl<T: AsRangedCoord> BindKeyPoints for T {}
122 
123 /// The coordinate decorator that allows customized keypoint algorithms.
124 /// Normally, all the coordinate spec implements its own key point algorith
125 /// But this decorator allows you override the pre-defined key point algorithm.
126 ///
127 /// To use this decorator, see [BindKeyPointMethod::with_key_point_func](trait.BindKeyPointMethod.html#tymethod.with_key_point_func)
128 pub struct WithKeyPointMethod<R: Ranged> {
129     inner: R,
130     bold_func: Box<dyn Fn(usize) -> Vec<R::ValueType>>,
131     light_func: Box<dyn Fn(usize) -> Vec<R::ValueType>>,
132 }
133 
134 pub trait BindKeyPointMethod
135 where
136     Self: AsRangedCoord,
137 {
138     /// Bind a existing coordinate spec with a given key points algorithm. See [WithKeyPointMethod](struct.WithKeyMethod.html ) for more details.
139     /// Example:
140     /// ```
141     ///use plotters::prelude::*;
142     ///use plotters_bitmap::BitMapBackend;
143     ///let mut buffer = vec![0;1024*768*3];
144     /// let root = BitMapBackend::with_buffer(&mut buffer, (1024, 768)).into_drawing_area();
145     /// let mut chart = ChartBuilder::on(&root)
146     ///    .build_ranged(
147     ///        (0..100).with_key_point_func(|n| (0..100 / n as i32).map(|x| x * 100 / n as i32).collect()),
148     ///        0..10
149     /// ).unwrap();
150     /// chart.configure_mesh().draw().unwrap();
151     ///```
with_key_point_func<F: Fn(usize) -> Vec<Self::Value> + 'static>( self, func: F, ) -> WithKeyPointMethod<Self::CoordDescType>152     fn with_key_point_func<F: Fn(usize) -> Vec<Self::Value> + 'static>(
153         self,
154         func: F,
155     ) -> WithKeyPointMethod<Self::CoordDescType> {
156         WithKeyPointMethod {
157             inner: self.into(),
158             bold_func: Box::new(func),
159             light_func: Box::new(|_| vec![]),
160         }
161     }
162 }
163 
164 impl<T: AsRangedCoord> BindKeyPointMethod for T {}
165 
166 impl<R: Ranged> WithKeyPointMethod<R> {
167     /// 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, ) -> Self168     pub fn with_light_point_func<F: Fn(usize) -> Vec<R::ValueType> + 'static>(
169         mut self,
170         func: F,
171     ) -> Self {
172         self.light_func = Box::new(func);
173         self
174     }
175 }
176 
177 impl<R: Ranged> Ranged for WithKeyPointMethod<R> {
178     type ValueType = R::ValueType;
179     type FormatOption = R::FormatOption;
180 
range(&self) -> Range<Self::ValueType>181     fn range(&self) -> Range<Self::ValueType> {
182         self.inner.range()
183     }
184 
map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32185     fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
186         self.inner.map(value, limit)
187     }
188 
key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType>189     fn key_points<Hint: KeyPointHint>(&self, hint: Hint) -> Vec<Self::ValueType> {
190         if hint.weight().allow_light_points() {
191             (self.light_func)(hint.max_num_points())
192         } else {
193             (self.bold_func)(hint.max_num_points())
194         }
195     }
196 
axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32>197     fn axis_pixel_range(&self, limit: (i32, i32)) -> Range<i32> {
198         self.inner.axis_pixel_range(limit)
199     }
200 }
201 
202 impl<R: DiscreteRanged> DiscreteRanged for WithKeyPointMethod<R> {
size(&self) -> usize203     fn size(&self) -> usize {
204         self.inner.size()
205     }
index_of(&self, value: &Self::ValueType) -> Option<usize>206     fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
207         self.inner.index_of(value)
208     }
from_index(&self, index: usize) -> Option<Self::ValueType>209     fn from_index(&self, index: usize) -> Option<Self::ValueType> {
210         self.inner.from_index(index)
211     }
212 }
213 
214 #[cfg(test)]
215 mod test {
216     use super::*;
217     use crate::coord::ranged1d::{BoldPoints, LightPoints};
218     #[test]
test_with_key_points()219     fn test_with_key_points() {
220         let range = (0..100).with_key_points(vec![1, 2, 3]);
221         assert_eq!(range.map(&3, (0, 1000)), 30);
222         assert_eq!(range.range(), 0..100);
223         assert_eq!(range.key_points(BoldPoints(100)), vec![1, 2, 3]);
224         assert_eq!(range.key_points(LightPoints::new(100, 100)), vec![]);
225         let range = range.with_light_points(5..10);
226         assert_eq!(range.key_points(BoldPoints(10)), vec![1, 2, 3]);
227         assert_eq!(
228             range.key_points(LightPoints::new(10, 10)),
229             (5..10).collect::<Vec<_>>()
230         );
231 
232         assert_eq!(range.size(), 101);
233         assert_eq!(range.index_of(&10), Some(10));
234         assert_eq!(range.from_index(10), Some(10));
235 
236         assert_eq!(range.axis_pixel_range((0, 1000)), 0..1000);
237 
238         let mut range = range;
239 
240         assert_eq!(range.light_points().len(), 5);
241         assert_eq!(range.light_points_mut().len(), 5);
242         assert_eq!(range.bold_points().len(), 3);
243         assert_eq!(range.bold_points_mut().len(), 3);
244     }
245 
246     #[test]
test_with_key_point_method()247     fn test_with_key_point_method() {
248         let range = (0..100).with_key_point_func(|_| vec![1, 2, 3]);
249         assert_eq!(range.map(&3, (0, 1000)), 30);
250         assert_eq!(range.range(), 0..100);
251         assert_eq!(range.key_points(BoldPoints(100)), vec![1, 2, 3]);
252         assert_eq!(range.key_points(LightPoints::new(100, 100)), vec![]);
253         let range = range.with_light_point_func(|_| (5..10).collect());
254         assert_eq!(range.key_points(BoldPoints(10)), vec![1, 2, 3]);
255         assert_eq!(
256             range.key_points(LightPoints::new(10, 10)),
257             (5..10).collect::<Vec<_>>()
258         );
259 
260         assert_eq!(range.size(), 101);
261         assert_eq!(range.index_of(&10), Some(10));
262         assert_eq!(range.from_index(10), Some(10));
263 
264         assert_eq!(range.axis_pixel_range((0, 1000)), 0..1000);
265     }
266 }
267