1 | use crate::element::{DynElement, IntoDynElement, PathElement, Polygon}; |
2 | use crate::style::colors::TRANSPARENT; |
3 | use crate::style::ShapeStyle; |
4 | use plotters_backend::DrawingBackend; |
5 | |
6 | /** |
7 | An area series is similar to a line series but uses a filled polygon. |
8 | It takes an iterator of data points in guest coordinate system |
9 | and creates appropriate lines and points with the given style. |
10 | |
11 | # Example |
12 | |
13 | ``` |
14 | use plotters::prelude::*; |
15 | let x_values = [0.0f64, 1., 2., 3., 4.]; |
16 | let drawing_area = SVGBackend::new("area_series.svg" , (300, 200)).into_drawing_area(); |
17 | drawing_area.fill(&WHITE).unwrap(); |
18 | let mut chart_builder = ChartBuilder::on(&drawing_area); |
19 | chart_builder.margin(10).set_left_and_bottom_label_area_size(20); |
20 | let mut chart_context = chart_builder.build_cartesian_2d(0.0..4.0, 0.0..3.0).unwrap(); |
21 | chart_context.configure_mesh().draw().unwrap(); |
22 | chart_context.draw_series(AreaSeries::new(x_values.map(|x| (x, 0.3 * x)), 0., BLACK.mix(0.2))).unwrap(); |
23 | chart_context.draw_series(AreaSeries::new(x_values.map(|x| (x, 2.5 - 0.05 * x * x)), 0., RED.mix(0.2))).unwrap(); |
24 | chart_context.draw_series(AreaSeries::new(x_values.map(|x| (x, 2. - 0.1 * x * x)), 0., BLUE.mix(0.2)).border_style(BLUE)).unwrap(); |
25 | ``` |
26 | |
27 | The result is a chart with three line series; one of them has a highlighted blue border: |
28 | |
29 | ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@b6703f7/apidoc/area_series.svg) |
30 | */ |
31 | pub struct AreaSeries<DB: DrawingBackend, X: Clone, Y: Clone> { |
32 | area_style: ShapeStyle, |
33 | border_style: ShapeStyle, |
34 | baseline: Y, |
35 | data: Vec<(X, Y)>, |
36 | state: u32, |
37 | _p: std::marker::PhantomData<DB>, |
38 | } |
39 | |
40 | impl<DB: DrawingBackend, X: Clone, Y: Clone> AreaSeries<DB, X, Y> { |
41 | /** |
42 | Creates an area series with transparent border. |
43 | |
44 | See [`AreaSeries`] for more information and examples. |
45 | */ |
46 | pub fn new<S: Into<ShapeStyle>, I: IntoIterator<Item = (X, Y)>>( |
47 | iter: I, |
48 | baseline: Y, |
49 | area_style: S, |
50 | ) -> Self { |
51 | Self { |
52 | area_style: area_style.into(), |
53 | baseline, |
54 | data: iter.into_iter().collect(), |
55 | state: 0, |
56 | border_style: (&TRANSPARENT).into(), |
57 | _p: std::marker::PhantomData, |
58 | } |
59 | } |
60 | |
61 | /** |
62 | Sets the border style of the area series. |
63 | |
64 | See [`AreaSeries`] for more information and examples. |
65 | */ |
66 | pub fn border_style<S: Into<ShapeStyle>>(mut self, style: S) -> Self { |
67 | self.border_style = style.into(); |
68 | self |
69 | } |
70 | } |
71 | |
72 | impl<DB: DrawingBackend, X: Clone + 'static, Y: Clone + 'static> Iterator for AreaSeries<DB, X, Y> { |
73 | type Item = DynElement<'static, DB, (X, Y)>; |
74 | fn next(&mut self) -> Option<Self::Item> { |
75 | if self.state == 0 { |
76 | let mut data: Vec<_> = self.data.clone(); |
77 | |
78 | if !data.is_empty() { |
79 | data.push((data[data.len() - 1].0.clone(), self.baseline.clone())); |
80 | data.push((data[0].0.clone(), self.baseline.clone())); |
81 | } |
82 | |
83 | self.state = 1; |
84 | |
85 | Some(Polygon::new(data, self.area_style).into_dyn()) |
86 | } else if self.state == 1 { |
87 | let data: Vec<_> = self.data.clone(); |
88 | |
89 | self.state = 2; |
90 | |
91 | Some(PathElement::new(data, self.border_style).into_dyn()) |
92 | } else { |
93 | None |
94 | } |
95 | } |
96 | } |
97 | |