1 | //! Filled curve plots |
2 | |
3 | use std::borrow::Cow; |
4 | use std::iter::IntoIterator; |
5 | |
6 | use crate::data::Matrix; |
7 | use crate::traits::{self, Data, Set}; |
8 | use crate::{Axes, Color, Default, Display, Figure, Label, Opacity, Plot, Script}; |
9 | |
10 | /// Properties common to filled curve plots |
11 | pub struct Properties { |
12 | axes: Option<Axes>, |
13 | color: Option<Color>, |
14 | label: Option<Cow<'static, str>>, |
15 | opacity: Option<f64>, |
16 | } |
17 | |
18 | impl Default for Properties { |
19 | fn default() -> Properties { |
20 | Properties { |
21 | axes: None, |
22 | color: None, |
23 | label: None, |
24 | opacity: None, |
25 | } |
26 | } |
27 | } |
28 | |
29 | impl Script for Properties { |
30 | // Allow clippy::format_push_string even with older versions of rust (<1.62) which |
31 | // don't have it defined. |
32 | #[allow (clippy::all)] |
33 | fn script(&self) -> String { |
34 | let mut script = if let Some(axes) = self.axes { |
35 | format!("axes {} " , axes.display()) |
36 | } else { |
37 | String::new() |
38 | }; |
39 | script.push_str("with filledcurves " ); |
40 | |
41 | script.push_str("fillstyle " ); |
42 | |
43 | if let Some(opacity) = self.opacity { |
44 | script.push_str(&format!("solid {} " , opacity)) |
45 | } |
46 | |
47 | // TODO border shoulde be configurable |
48 | script.push_str("noborder " ); |
49 | |
50 | if let Some(color) = self.color { |
51 | script.push_str(&format!("lc rgb '{}' " , color.display())); |
52 | } |
53 | |
54 | if let Some(ref label) = self.label { |
55 | script.push_str("title '" ); |
56 | script.push_str(label); |
57 | script.push(' \'' ) |
58 | } else { |
59 | script.push_str("notitle" ) |
60 | } |
61 | |
62 | script |
63 | } |
64 | } |
65 | |
66 | impl Set<Axes> for Properties { |
67 | /// Select axes to plot against |
68 | /// |
69 | /// **Note** By default, the `BottomXLeftY` axes are used |
70 | fn set(&mut self, axes: Axes) -> &mut Properties { |
71 | self.axes = Some(axes); |
72 | self |
73 | } |
74 | } |
75 | |
76 | impl Set<Color> for Properties { |
77 | /// Sets the fill color |
78 | fn set(&mut self, color: Color) -> &mut Properties { |
79 | self.color = Some(color); |
80 | self |
81 | } |
82 | } |
83 | |
84 | impl Set<Label> for Properties { |
85 | /// Sets the legend label |
86 | fn set(&mut self, label: Label) -> &mut Properties { |
87 | self.label = Some(label.0); |
88 | self |
89 | } |
90 | } |
91 | |
92 | impl Set<Opacity> for Properties { |
93 | /// Changes the opacity of the fill color |
94 | /// |
95 | /// **Note** By default, the fill color is totally opaque (`opacity = 1.0`) |
96 | /// |
97 | /// # Panics |
98 | /// |
99 | /// Panics if `opacity` is outside the range `[0, 1]` |
100 | fn set(&mut self, opacity: Opacity) -> &mut Properties { |
101 | self.opacity = Some(opacity.0); |
102 | self |
103 | } |
104 | } |
105 | |
106 | /// Fills the area between two curves |
107 | pub struct FilledCurve<X, Y1, Y2> { |
108 | /// X coordinate of the data points of both curves |
109 | pub x: X, |
110 | /// Y coordinate of the data points of the first curve |
111 | pub y1: Y1, |
112 | /// Y coordinate of the data points of the second curve |
113 | pub y2: Y2, |
114 | } |
115 | |
116 | impl<X, Y1, Y2> traits::Plot<FilledCurve<X, Y1, Y2>> for Figure |
117 | where |
118 | X: IntoIterator, |
119 | X::Item: Data, |
120 | Y1: IntoIterator, |
121 | Y1::Item: Data, |
122 | Y2: IntoIterator, |
123 | Y2::Item: Data, |
124 | { |
125 | type Properties = Properties; |
126 | |
127 | fn plot<F>(&mut self, fc: FilledCurve<X, Y1, Y2>, configure: F) -> &mut Figure |
128 | where |
129 | F: FnOnce(&mut Properties) -> &mut Properties, |
130 | { |
131 | let FilledCurve { x, y1, y2 } = fc; |
132 | |
133 | let mut props = Default::default(); |
134 | configure(&mut props); |
135 | |
136 | let (x_factor, y_factor) = |
137 | crate::scale_factor(&self.axes, props.axes.unwrap_or(crate::Axes::BottomXLeftY)); |
138 | |
139 | let data = Matrix::new(izip!(x, y1, y2), (x_factor, y_factor, y_factor)); |
140 | self.plots.push(Plot::new(data, &props)); |
141 | self |
142 | } |
143 | } |
144 | |