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