/rust/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-0.3.7/src/chart/axes3d.rs
Line | Count | Source |
1 | | use std::marker::PhantomData; |
2 | | |
3 | | use super::ChartContext; |
4 | | use crate::coord::cartesian::Cartesian3d; |
5 | | use crate::coord::ranged1d::{BoldPoints, LightPoints, Ranged, ValueFormatter}; |
6 | | use crate::style::colors::{BLACK, TRANSPARENT}; |
7 | | use crate::style::Color; |
8 | | use crate::style::{AsRelative, ShapeStyle, SizeDesc, TextStyle}; |
9 | | |
10 | | use super::Coord3D; |
11 | | |
12 | | use crate::drawing::DrawingAreaErrorKind; |
13 | | |
14 | | use plotters_backend::DrawingBackend; |
15 | | |
16 | | /** |
17 | | Implements 3D plot axes configurations. |
18 | | |
19 | | The best way to use this struct is by way of the [`configure_axes()`] function. |
20 | | See [`ChartContext::configure_axes()`] for more information and examples. |
21 | | */ |
22 | | pub struct Axes3dStyle<'a, 'b, X: Ranged, Y: Ranged, Z: Ranged, DB: DrawingBackend> { |
23 | | pub(super) parent_size: (u32, u32), |
24 | | pub(super) target: Option<&'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>>, |
25 | | pub(super) tick_size: i32, |
26 | | pub(super) light_lines_limit: [usize; 3], |
27 | | pub(super) n_labels: [usize; 3], |
28 | | pub(super) bold_line_style: ShapeStyle, |
29 | | pub(super) light_line_style: ShapeStyle, |
30 | | pub(super) axis_panel_style: ShapeStyle, |
31 | | pub(super) axis_style: ShapeStyle, |
32 | | pub(super) label_style: TextStyle<'b>, |
33 | | pub(super) format_x: &'b dyn Fn(&X::ValueType) -> String, |
34 | | pub(super) format_y: &'b dyn Fn(&Y::ValueType) -> String, |
35 | | pub(super) format_z: &'b dyn Fn(&Z::ValueType) -> String, |
36 | | _phantom: PhantomData<&'a (X, Y, Z)>, |
37 | | } |
38 | | |
39 | | impl<'a, 'b, X, Y, Z, XT, YT, ZT, DB> Axes3dStyle<'a, 'b, X, Y, Z, DB> |
40 | | where |
41 | | X: Ranged<ValueType = XT> + ValueFormatter<XT>, |
42 | | Y: Ranged<ValueType = YT> + ValueFormatter<YT>, |
43 | | Z: Ranged<ValueType = ZT> + ValueFormatter<ZT>, |
44 | | DB: DrawingBackend, |
45 | | { |
46 | | /** |
47 | | Set the size of the tick marks. |
48 | | |
49 | | - `value` Desired tick mark size, in pixels. |
50 | | |
51 | | See [`ChartContext::configure_axes()`] for more information and examples. |
52 | | */ |
53 | 0 | pub fn tick_size<Size: SizeDesc>(&mut self, size: Size) -> &mut Self { |
54 | 0 | let actual_size = size.in_pixels(&self.parent_size); |
55 | 0 | self.tick_size = actual_size; |
56 | 0 | self |
57 | 0 | } |
58 | | |
59 | | /** |
60 | | Set the maximum number of divisions for the minor grid in the X axis. |
61 | | |
62 | | - `value`: Maximum desired divisions between two consecutive X labels. |
63 | | |
64 | | See [`ChartContext::configure_axes()`] for more information and examples. |
65 | | */ |
66 | 0 | pub fn x_max_light_lines(&mut self, value: usize) -> &mut Self { |
67 | 0 | self.light_lines_limit[0] = value; |
68 | 0 | self |
69 | 0 | } |
70 | | |
71 | | /** |
72 | | Set the maximum number of divisions for the minor grid in the Y axis. |
73 | | |
74 | | - `value`: Maximum desired divisions between two consecutive Y labels. |
75 | | |
76 | | See [`ChartContext::configure_axes()`] for more information and examples. |
77 | | */ |
78 | 0 | pub fn y_max_light_lines(&mut self, value: usize) -> &mut Self { |
79 | 0 | self.light_lines_limit[1] = value; |
80 | 0 | self |
81 | 0 | } |
82 | | |
83 | | /** |
84 | | Set the maximum number of divisions for the minor grid in the Z axis. |
85 | | |
86 | | - `value`: Maximum desired divisions between two consecutive Z labels. |
87 | | |
88 | | See [`ChartContext::configure_axes()`] for more information and examples. |
89 | | */ |
90 | 0 | pub fn z_max_light_lines(&mut self, value: usize) -> &mut Self { |
91 | 0 | self.light_lines_limit[2] = value; |
92 | 0 | self |
93 | 0 | } |
94 | | |
95 | | /** |
96 | | Set the maximum number of divisions for the minor grid. |
97 | | |
98 | | - `value`: Maximum desired divisions between two consecutive labels in X, Y, and Z. |
99 | | |
100 | | See [`ChartContext::configure_axes()`] for more information and examples. |
101 | | */ |
102 | 0 | pub fn max_light_lines(&mut self, value: usize) -> &mut Self { |
103 | 0 | self.light_lines_limit[0] = value; |
104 | 0 | self.light_lines_limit[1] = value; |
105 | 0 | self.light_lines_limit[2] = value; |
106 | 0 | self |
107 | 0 | } |
108 | | |
109 | | /** |
110 | | Set the number of labels on the X axes. |
111 | | |
112 | | See [`ChartContext::configure_axes()`] for more information and examples. |
113 | | */ |
114 | 0 | pub fn x_labels(&mut self, n: usize) -> &mut Self { |
115 | 0 | self.n_labels[0] = n; |
116 | 0 | self |
117 | 0 | } |
118 | | |
119 | | /** |
120 | | Set the number of labels on the Y axes. |
121 | | |
122 | | See [`ChartContext::configure_axes()`] for more information and examples. |
123 | | */ |
124 | 0 | pub fn y_labels(&mut self, n: usize) -> &mut Self { |
125 | 0 | self.n_labels[1] = n; |
126 | 0 | self |
127 | 0 | } |
128 | | |
129 | | /** |
130 | | Set the number of labels on the Z axes. |
131 | | |
132 | | See [`ChartContext::configure_axes()`] for more information and examples. |
133 | | */ |
134 | 0 | pub fn z_labels(&mut self, n: usize) -> &mut Self { |
135 | 0 | self.n_labels[2] = n; |
136 | 0 | self |
137 | 0 | } |
138 | | |
139 | | /** |
140 | | Sets the style of the panels in the background. |
141 | | |
142 | | See [`ChartContext::configure_axes()`] for more information and examples. |
143 | | */ |
144 | 0 | pub fn axis_panel_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self { |
145 | 0 | self.axis_panel_style = style.into(); |
146 | 0 | self |
147 | 0 | } |
148 | | |
149 | | /** |
150 | | Sets the style of the major grid lines. |
151 | | |
152 | | See [`ChartContext::configure_axes()`] for more information and examples. |
153 | | */ |
154 | 0 | pub fn bold_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self { |
155 | 0 | self.bold_line_style = style.into(); |
156 | 0 | self |
157 | 0 | } |
158 | | |
159 | | /** |
160 | | Sets the style of the minor grid lines. |
161 | | |
162 | | See [`ChartContext::configure_axes()`] for more information and examples. |
163 | | */ |
164 | 0 | pub fn light_grid_style<S: Into<ShapeStyle>>(&mut self, style: S) -> &mut Self { |
165 | 0 | self.light_line_style = style.into(); |
166 | 0 | self |
167 | 0 | } |
168 | | |
169 | | /** |
170 | | Sets the text style of the axis labels. |
171 | | |
172 | | See [`ChartContext::configure_axes()`] for more information and examples. |
173 | | */ |
174 | 0 | pub fn label_style<S: Into<TextStyle<'b>>>(&mut self, style: S) -> &mut Self { |
175 | 0 | self.label_style = style.into(); |
176 | 0 | self |
177 | 0 | } |
178 | | |
179 | | /** |
180 | | Specifies the string format of the X axis labels. |
181 | | |
182 | | See [`ChartContext::configure_axes()`] for more information and examples. |
183 | | */ |
184 | 0 | pub fn x_formatter<F: Fn(&X::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self { |
185 | 0 | self.format_x = f; |
186 | 0 | self |
187 | 0 | } |
188 | | |
189 | | /** |
190 | | Specifies the string format of the Y axis labels. |
191 | | |
192 | | See [`ChartContext::configure_axes()`] for more information and examples. |
193 | | */ |
194 | 0 | pub fn y_formatter<F: Fn(&Y::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self { |
195 | 0 | self.format_y = f; |
196 | 0 | self |
197 | 0 | } |
198 | | |
199 | | /** |
200 | | Specifies the string format of the Z axis labels. |
201 | | |
202 | | See [`ChartContext::configure_axes()`] for more information and examples. |
203 | | */ |
204 | 0 | pub fn z_formatter<F: Fn(&Z::ValueType) -> String>(&mut self, f: &'b F) -> &mut Self { |
205 | 0 | self.format_z = f; |
206 | 0 | self |
207 | 0 | } |
208 | | |
209 | | /** |
210 | | Constructs a new configuration object and defines the defaults. |
211 | | |
212 | | This is used internally by Plotters and should probably not be included in user code. |
213 | | See [`ChartContext::configure_axes()`] for more information and examples. |
214 | | */ |
215 | 0 | pub(crate) fn new(chart: &'b mut ChartContext<'a, DB, Cartesian3d<X, Y, Z>>) -> Self { |
216 | 0 | let parent_size = chart.drawing_area.dim_in_pixel(); |
217 | 0 | let base_tick_size = (5u32).percent().max(5).in_pixels(chart.plotting_area()); |
218 | 0 | let tick_size = base_tick_size; |
219 | 0 | Self { |
220 | 0 | parent_size, |
221 | 0 | tick_size, |
222 | 0 | light_lines_limit: [10, 10, 10], |
223 | 0 | n_labels: [10, 10, 10], |
224 | 0 | bold_line_style: Into::<ShapeStyle>::into(BLACK.mix(0.2)), |
225 | 0 | light_line_style: Into::<ShapeStyle>::into(TRANSPARENT), |
226 | 0 | axis_panel_style: Into::<ShapeStyle>::into(BLACK.mix(0.1)), |
227 | 0 | axis_style: Into::<ShapeStyle>::into(BLACK.mix(0.8)), |
228 | 0 | label_style: ("sans-serif", (12).percent().max(12).in_pixels(&parent_size)).into(), |
229 | 0 | format_x: &X::format, |
230 | 0 | format_y: &Y::format, |
231 | 0 | format_z: &Z::format, |
232 | 0 | _phantom: PhantomData, |
233 | 0 | target: Some(chart), |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | 0 | pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> |
238 | 0 | where |
239 | 0 | XT: Clone, |
240 | 0 | YT: Clone, |
241 | 0 | ZT: Clone, |
242 | | { |
243 | 0 | let chart = self.target.take().unwrap(); |
244 | 0 | let kps_bold = chart.get_key_points( |
245 | 0 | BoldPoints(self.n_labels[0]), |
246 | 0 | BoldPoints(self.n_labels[1]), |
247 | 0 | BoldPoints(self.n_labels[2]), |
248 | | ); |
249 | 0 | let kps_light = chart.get_key_points( |
250 | 0 | LightPoints::new( |
251 | 0 | self.n_labels[0], |
252 | 0 | self.n_labels[0] * self.light_lines_limit[0], |
253 | | ), |
254 | 0 | LightPoints::new( |
255 | 0 | self.n_labels[1], |
256 | 0 | self.n_labels[1] * self.light_lines_limit[1], |
257 | | ), |
258 | 0 | LightPoints::new( |
259 | 0 | self.n_labels[2], |
260 | 0 | self.n_labels[2] * self.light_lines_limit[2], |
261 | | ), |
262 | | ); |
263 | | |
264 | 0 | let panels = chart.draw_axis_panels( |
265 | 0 | &kps_bold, |
266 | 0 | &kps_light, |
267 | 0 | self.axis_panel_style, |
268 | 0 | self.bold_line_style, |
269 | 0 | self.light_line_style, |
270 | 0 | )?; |
271 | | |
272 | 0 | for i in 0..3 { |
273 | 0 | let axis = chart.draw_axis(i, &panels, self.axis_style)?; |
274 | 0 | let labels: Vec<_> = match i { |
275 | 0 | 0 => kps_bold |
276 | 0 | .x_points |
277 | 0 | .iter() |
278 | 0 | .map(|x| { |
279 | 0 | let x_text = (self.format_x)(x); |
280 | 0 | let mut p = axis[0].clone(); |
281 | 0 | p[0] = Coord3D::X(x.clone()); |
282 | 0 | (p, x_text) |
283 | 0 | }) |
284 | 0 | .collect(), |
285 | 0 | 1 => kps_bold |
286 | 0 | .y_points |
287 | 0 | .iter() |
288 | 0 | .map(|y| { |
289 | 0 | let y_text = (self.format_y)(y); |
290 | 0 | let mut p = axis[0].clone(); |
291 | 0 | p[1] = Coord3D::Y(y.clone()); |
292 | 0 | (p, y_text) |
293 | 0 | }) |
294 | 0 | .collect(), |
295 | 0 | _ => kps_bold |
296 | 0 | .z_points |
297 | 0 | .iter() |
298 | 0 | .map(|z| { |
299 | 0 | let z_text = (self.format_z)(z); |
300 | 0 | let mut p = axis[0].clone(); |
301 | 0 | p[2] = Coord3D::Z(z.clone()); |
302 | 0 | (p, z_text) |
303 | 0 | }) |
304 | 0 | .collect(), |
305 | | }; |
306 | 0 | chart.draw_axis_ticks( |
307 | 0 | axis, |
308 | 0 | &labels[..], |
309 | 0 | self.tick_size, |
310 | 0 | self.axis_style, |
311 | 0 | self.label_style.clone(), |
312 | 0 | )?; |
313 | | } |
314 | | |
315 | 0 | Ok(()) |
316 | 0 | } |
317 | | } |