Coverage Report

Created: 2026-04-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}