• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
default() -> Properties19     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)]
script(&self) -> String33     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
set(&mut self, axes: Axes) -> &mut Properties70     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
set(&mut self, color: Color) -> &mut Properties78     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
set(&mut self, label: Label) -> &mut Properties86     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]`
set(&mut self, opacity: Opacity) -> &mut Properties100     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 
plot<F>(&mut self, fc: FilledCurve<X, Y1, Y2>, configure: F) -> &mut Figure where F: FnOnce(&mut Properties) -> &mut Properties,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