• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::marker::PhantomData;
2 
3 use super::builder::LabelAreaPosition;
4 use super::context::ChartContext;
5 use crate::coord::cartesian::{Cartesian2d, MeshLine};
6 use crate::coord::ranged1d::{BoldPoints, LightPoints, Ranged, ValueFormatter};
7 use crate::drawing::DrawingAreaErrorKind;
8 use crate::style::{
9     AsRelative, Color, FontDesc, FontFamily, FontStyle, IntoTextStyle, RGBColor, ShapeStyle,
10     SizeDesc, TextStyle,
11 };
12 
13 use plotters_backend::DrawingBackend;
14 
15 /// The style used to describe the mesh and axis for a secondary coordinate system.
16 pub struct SecondaryMeshStyle<'a, 'b, X: Ranged, Y: Ranged, DB: DrawingBackend> {
17     style: MeshStyle<'a, 'b, X, Y, DB>,
18 }
19 
20 impl<'a, 'b, XT, YT, X: Ranged<ValueType = XT>, Y: Ranged<ValueType = YT>, DB: DrawingBackend>
21     SecondaryMeshStyle<'a, 'b, X, Y, DB>
22 where
23     X: ValueFormatter<XT>,
24     Y: ValueFormatter<YT>,
25 {
new(target: &'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>) -> Self26     pub(super) fn new(target: &'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>) -> Self {
27         let mut style = target.configure_mesh();
28         style.draw_x_mesh = false;
29         style.draw_y_mesh = false;
30         Self { style }
31     }
32 
33     /// Set the style definition for the axis
34     /// - `style`: The style for the axis
axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self35     pub fn axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
36         self.style.axis_style(style);
37         self
38     }
39 
40     /// The offset of x labels. This is used when we want to place the label in the middle of
41     /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this
42     /// use case is deprecated, see [CentricDiscreteRanged coord decorator](../coord/trait.IntoCentric.html) for more details
43     /// - `value`: The offset in pixel
x_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self44     pub fn x_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self {
45         self.style.x_label_offset(value);
46         self
47     }
48 
49     /// The offset of y labels. This is used when we want to place the label in the middle of
50     /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this
51     /// use case is deprecated, see [CentricDiscreteRanged coord decorator](../coord/trait.IntoCentric.html) for more details
52     /// - `value`: The offset in pixel
y_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self53     pub fn y_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self {
54         self.style.y_label_offset(value);
55         self
56     }
57 
58     /// Set how many labels for the X axis at most
59     /// - `value`: The maximum desired number of labels in the X axis
x_labels(&mut self, value: usize) -> &mut Self60     pub fn x_labels(&mut self, value: usize) -> &mut Self {
61         self.style.x_labels(value);
62         self
63     }
64 
65     /// Set how many label for the Y axis at most
66     /// - `value`: The maximum desired number of labels in the Y axis
y_labels(&mut self, value: usize) -> &mut Self67     pub fn y_labels(&mut self, value: usize) -> &mut Self {
68         self.style.y_labels(value);
69         self
70     }
71 
72     /// Set the formatter function for the X label text
73     /// - `fmt`: The formatter function
x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self74     pub fn x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self {
75         self.style.x_label_formatter(fmt);
76         self
77     }
78 
79     /// Set the formatter function for the Y label text
80     /// - `fmt`: The formatter function
y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self81     pub fn y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self {
82         self.style.y_label_formatter(fmt);
83         self
84     }
85 
86     /// Set the axis description's style. If not given, use label style instead.
87     /// - `style`: The text style that would be applied to descriptions
axis_desc_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self88     pub fn axis_desc_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self {
89         self.style
90             .axis_desc_style(style.into_text_style(&self.style.parent_size));
91         self
92     }
93 
94     /// Set the X axis's description
95     /// - `desc`: The description of the X axis
x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self96     pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
97         self.style.x_desc(desc);
98         self
99     }
100 
101     /// Set the Y axis's description
102     /// - `desc`: The description of the Y axis
y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self103     pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
104         self.style.y_desc(desc);
105         self
106     }
107 
108     /// Draw the axes for the secondary coordinate system
draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>>109     pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
110         self.style.draw()
111     }
112 
113     /// Set the label style for the secondary axis
label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self114     pub fn label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self {
115         self.style.label_style(style);
116         self
117     }
118 
119     /// Set all the tick mark to the same size
120     /// `value`: The new size
set_all_tick_mark_size<S: SizeDesc>(&mut self, value: S) -> &mut Self121     pub fn set_all_tick_mark_size<S: SizeDesc>(&mut self, value: S) -> &mut Self {
122         let size = value.in_pixels(&self.style.parent_size);
123         self.style.x_tick_size = [size, size];
124         self.style.y_tick_size = [size, size];
125         self
126     }
127 
set_tick_mark_size<S: SizeDesc>( &mut self, pos: LabelAreaPosition, value: S, ) -> &mut Self128     pub fn set_tick_mark_size<S: SizeDesc>(
129         &mut self,
130         pos: LabelAreaPosition,
131         value: S,
132     ) -> &mut Self {
133         *match pos {
134             LabelAreaPosition::Top => &mut self.style.x_tick_size[0],
135             LabelAreaPosition::Bottom => &mut self.style.x_tick_size[1],
136             LabelAreaPosition::Left => &mut self.style.y_tick_size[0],
137             LabelAreaPosition::Right => &mut self.style.y_tick_size[1],
138         } = value.in_pixels(&self.style.parent_size);
139         self
140     }
141 }
142 
143 /// The struct that is used for tracking the configuration of a mesh of any chart
144 pub struct MeshStyle<'a, 'b, X: Ranged, Y: Ranged, DB: DrawingBackend> {
145     pub(super) parent_size: (u32, u32),
146     pub(super) draw_x_mesh: bool,
147     pub(super) draw_y_mesh: bool,
148     pub(super) draw_x_axis: bool,
149     pub(super) draw_y_axis: bool,
150     pub(super) x_label_offset: i32,
151     pub(super) y_label_offset: i32,
152     pub(super) n_x_labels: usize,
153     pub(super) n_y_labels: usize,
154     pub(super) axis_desc_style: Option<TextStyle<'b>>,
155     pub(super) x_desc: Option<String>,
156     pub(super) y_desc: Option<String>,
157     pub(super) bold_line_style: Option<ShapeStyle>,
158     pub(super) light_line_style: Option<ShapeStyle>,
159     pub(super) axis_style: Option<ShapeStyle>,
160     pub(super) x_label_style: Option<TextStyle<'b>>,
161     pub(super) y_label_style: Option<TextStyle<'b>>,
162     pub(super) format_x: &'b dyn Fn(&X::ValueType) -> String,
163     pub(super) format_y: &'b dyn Fn(&Y::ValueType) -> String,
164     pub(super) target: Option<&'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>>,
165     pub(super) _phantom_data: PhantomData<(X, Y)>,
166     pub(super) x_tick_size: [i32; 2],
167     pub(super) y_tick_size: [i32; 2],
168 }
169 
170 impl<'a, 'b, X, Y, XT, YT, DB> MeshStyle<'a, 'b, X, Y, DB>
171 where
172     X: Ranged<ValueType = XT> + ValueFormatter<XT>,
173     Y: Ranged<ValueType = YT> + ValueFormatter<YT>,
174     DB: DrawingBackend,
175 {
new(chart: &'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>) -> Self176     pub(crate) fn new(chart: &'b mut ChartContext<'a, DB, Cartesian2d<X, Y>>) -> Self {
177         let base_tick_size = (5u32).percent().max(5).in_pixels(chart.plotting_area());
178 
179         let mut x_tick_size = [base_tick_size, base_tick_size];
180         let mut y_tick_size = [base_tick_size, base_tick_size];
181 
182         for idx in 0..2 {
183             if chart.is_overlapping_drawing_area(chart.x_label_area[idx].as_ref()) {
184                 x_tick_size[idx] = -x_tick_size[idx];
185             }
186             if chart.is_overlapping_drawing_area(chart.y_label_area[idx].as_ref()) {
187                 y_tick_size[idx] = -y_tick_size[idx];
188             }
189         }
190 
191         MeshStyle {
192             parent_size: chart.drawing_area.dim_in_pixel(),
193             axis_style: None,
194             x_label_offset: 0,
195             y_label_offset: 0,
196             draw_x_mesh: true,
197             draw_y_mesh: true,
198             draw_x_axis: true,
199             draw_y_axis: true,
200             n_x_labels: 10,
201             n_y_labels: 10,
202             bold_line_style: None,
203             light_line_style: None,
204             x_label_style: None,
205             y_label_style: None,
206             format_x: &X::format,
207             format_y: &Y::format,
208             target: Some(chart),
209             _phantom_data: PhantomData,
210             x_desc: None,
211             y_desc: None,
212             axis_desc_style: None,
213             x_tick_size,
214             y_tick_size,
215         }
216     }
217 }
218 
219 impl<'a, 'b, X, Y, DB> MeshStyle<'a, 'b, X, Y, DB>
220 where
221     X: Ranged,
222     Y: Ranged,
223     DB: DrawingBackend,
224 {
225     /// Set all the tick mark to the same size
226     /// `value`: The new size
set_all_tick_mark_size<S: SizeDesc>(&mut self, value: S) -> &mut Self227     pub fn set_all_tick_mark_size<S: SizeDesc>(&mut self, value: S) -> &mut Self {
228         let size = value.in_pixels(&self.parent_size);
229         self.x_tick_size = [size, size];
230         self.y_tick_size = [size, size];
231         self
232     }
233 
234     /// Set the tick mark size on the axes. When this is set to negative, the axis value label will
235     /// become inward.
236     ///
237     /// - `pos`: The which label area we want to set
238     /// - `value`: The size specification
set_tick_mark_size<S: SizeDesc>( &mut self, pos: LabelAreaPosition, value: S, ) -> &mut Self239     pub fn set_tick_mark_size<S: SizeDesc>(
240         &mut self,
241         pos: LabelAreaPosition,
242         value: S,
243     ) -> &mut Self {
244         *match pos {
245             LabelAreaPosition::Top => &mut self.x_tick_size[0],
246             LabelAreaPosition::Bottom => &mut self.x_tick_size[1],
247             LabelAreaPosition::Left => &mut self.y_tick_size[0],
248             LabelAreaPosition::Right => &mut self.y_tick_size[1],
249         } = value.in_pixels(&self.parent_size);
250         self
251     }
252 
253     /// The offset of x labels. This is used when we want to place the label in the middle of
254     /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this
255     /// use case is deprecated, see [CentricDiscreteRanged coord decorator](../coord/trait.IntoCentric.html) for more details
256     /// - `value`: The offset in pixel
x_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self257     pub fn x_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self {
258         self.x_label_offset = value.in_pixels(&self.parent_size);
259         self
260     }
261 
262     /// The offset of y labels. This is used when we want to place the label in the middle of
263     /// the grid. This is used to adjust label position for histograms, but since plotters 0.3, this
264     /// use case is deprecated, see [CentricDiscreteRanged coord decorator](../coord/trait.IntoCentric.html) for more details
265     /// - `value`: The offset in pixel
y_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self266     pub fn y_label_offset<S: SizeDesc>(&mut self, value: S) -> &mut Self {
267         self.y_label_offset = value.in_pixels(&self.parent_size);
268         self
269     }
270 
271     /// Disable the mesh for the x axis.
disable_x_mesh(&mut self) -> &mut Self272     pub fn disable_x_mesh(&mut self) -> &mut Self {
273         self.draw_x_mesh = false;
274         self
275     }
276 
277     /// Disable the mesh for the y axis
disable_y_mesh(&mut self) -> &mut Self278     pub fn disable_y_mesh(&mut self) -> &mut Self {
279         self.draw_y_mesh = false;
280         self
281     }
282 
283     /// Disable drawing the X axis
disable_x_axis(&mut self) -> &mut Self284     pub fn disable_x_axis(&mut self) -> &mut Self {
285         self.draw_x_axis = false;
286         self
287     }
288 
289     /// Disable drawing the Y axis
disable_y_axis(&mut self) -> &mut Self290     pub fn disable_y_axis(&mut self) -> &mut Self {
291         self.draw_y_axis = false;
292         self
293     }
294 
295     /// Disable drawing all meshes
disable_mesh(&mut self) -> &mut Self296     pub fn disable_mesh(&mut self) -> &mut Self {
297         self.disable_x_mesh().disable_y_mesh()
298     }
299 
300     /// Disable drawing all axes
disable_axes(&mut self) -> &mut Self301     pub fn disable_axes(&mut self) -> &mut Self {
302         self.disable_x_axis().disable_y_axis()
303     }
304 
305     /// Set the style definition for the axis
306     /// - `style`: The style for the axis
axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self307     pub fn axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
308         self.axis_style = Some(style.into());
309         self
310     }
311     /// Set how many labels for the X axis at most
312     /// - `value`: The maximum desired number of labels in the X axis
x_labels(&mut self, value: usize) -> &mut Self313     pub fn x_labels(&mut self, value: usize) -> &mut Self {
314         self.n_x_labels = value;
315         self
316     }
317 
318     /// Set how many label for the Y axis at most
319     /// - `value`: The maximum desired number of labels in the Y axis
y_labels(&mut self, value: usize) -> &mut Self320     pub fn y_labels(&mut self, value: usize) -> &mut Self {
321         self.n_y_labels = value;
322         self
323     }
324 
325     /// Set the style for the coarse grind grid
326     /// - `style`: This is the coarse grind grid style
bold_line_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self327     pub fn bold_line_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
328         self.bold_line_style = Some(style.into());
329         self
330     }
331 
332     /// Set the style for the fine grind grid
333     /// - `style`: The fine grind grid style
light_line_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self334     pub fn light_line_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
335         self.light_line_style = Some(style.into());
336         self
337     }
338 
339     /// Set the style of the label text
340     /// - `style`: The text style that would be applied to the labels
label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self341     pub fn label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self {
342         let style = style.into_text_style(&self.parent_size);
343         self.x_label_style = Some(style.clone());
344         self.y_label_style = Some(style);
345         self
346     }
347 
348     /// Set the style of the label X axis text
349     /// - `style`: The text style that would be applied to the labels
x_label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self350     pub fn x_label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self {
351         self.x_label_style = Some(style.into_text_style(&self.parent_size));
352         self
353     }
354 
355     /// Set the style of the label Y axis text
356     /// - `style`: The text style that would be applied to the labels
y_label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self357     pub fn y_label_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self {
358         self.y_label_style = Some(style.into_text_style(&self.parent_size));
359         self
360     }
361 
362     /// Set the formatter function for the X label text
363     /// - `fmt`: The formatter function
x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self364     pub fn x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self {
365         self.format_x = fmt;
366         self
367     }
368 
369     /// Set the formatter function for the Y label text
370     /// - `fmt`: The formatter function
y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self371     pub fn y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self {
372         self.format_y = fmt;
373         self
374     }
375 
376     /// Set the axis description's style. If not given, use label style instead.
377     /// - `style`: The text style that would be applied to descriptions
axis_desc_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self378     pub fn axis_desc_style<T: IntoTextStyle<'b>>(&mut self, style: T) -> &mut Self {
379         self.axis_desc_style = Some(style.into_text_style(&self.parent_size));
380         self
381     }
382 
383     /// Set the X axis's description
384     /// - `desc`: The description of the X axis
x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self385     pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
386         self.x_desc = Some(desc.into());
387         self
388     }
389 
390     /// Set the Y axis's description
391     /// - `desc`: The description of the Y axis
y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self392     pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
393         self.y_desc = Some(desc.into());
394         self
395     }
396 
397     /// Draw the configured mesh on the target plot
draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>>398     pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
399         let mut target = None;
400         std::mem::swap(&mut target, &mut self.target);
401         let target = target.unwrap();
402 
403         let default_mesh_color_1 = RGBColor(0, 0, 0).mix(0.2);
404         let default_mesh_color_2 = RGBColor(0, 0, 0).mix(0.1);
405         let default_axis_color = RGBColor(0, 0, 0);
406         let default_label_font = FontDesc::new(
407             FontFamily::SansSerif,
408             f64::from((12i32).percent().max(12).in_pixels(&self.parent_size)),
409             FontStyle::Normal,
410         );
411 
412         let bold_style = self
413             .bold_line_style
414             .clone()
415             .unwrap_or_else(|| (&default_mesh_color_1).into());
416         let light_style = self
417             .light_line_style
418             .clone()
419             .unwrap_or_else(|| (&default_mesh_color_2).into());
420         let axis_style = self
421             .axis_style
422             .clone()
423             .unwrap_or_else(|| (&default_axis_color).into());
424 
425         let x_label_style = self
426             .x_label_style
427             .clone()
428             .unwrap_or_else(|| default_label_font.clone().into());
429 
430         let y_label_style = self
431             .y_label_style
432             .clone()
433             .unwrap_or_else(|| default_label_font.into());
434 
435         let axis_desc_style = self
436             .axis_desc_style
437             .clone()
438             .unwrap_or_else(|| x_label_style.clone());
439 
440         target.draw_mesh(
441             (
442                 LightPoints::new(self.n_y_labels, self.n_y_labels * 10),
443                 LightPoints::new(self.n_x_labels, self.n_x_labels * 10),
444             ),
445             &light_style,
446             &x_label_style,
447             &y_label_style,
448             |_| None,
449             self.draw_x_mesh,
450             self.draw_y_mesh,
451             self.x_label_offset,
452             self.y_label_offset,
453             false,
454             false,
455             &axis_style,
456             &axis_desc_style,
457             self.x_desc.clone(),
458             self.y_desc.clone(),
459             self.x_tick_size,
460             self.y_tick_size,
461         )?;
462 
463         target.draw_mesh(
464             (BoldPoints(self.n_y_labels), BoldPoints(self.n_x_labels)),
465             &bold_style,
466             &x_label_style,
467             &y_label_style,
468             |m| match m {
469                 MeshLine::XMesh(_, _, v) => Some((self.format_x)(v)),
470                 MeshLine::YMesh(_, _, v) => Some((self.format_y)(v)),
471             },
472             self.draw_x_mesh,
473             self.draw_y_mesh,
474             self.x_label_offset,
475             self.y_label_offset,
476             self.draw_x_axis,
477             self.draw_y_axis,
478             &axis_style,
479             &axis_desc_style,
480             None,
481             None,
482             self.x_tick_size,
483             self.y_tick_size,
484         )
485     }
486 }
487