| 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 |
| 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 | |
| 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 | |
| 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 | |
| 79 | impl<R: DiscreteRanged> DiscreteRanged for WithKeyPoints<R> |
| 80 | where |
| 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. |
| 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 | ///``` |
| 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 | ///``` |
| 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 |
| 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 | |
| 179 | impl<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 | |
| 204 | impl<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)] |
| 217 | mod 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 | |