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