criterion_plot/
filledcurve.rs

1//! Filled curve plots
2
3use std::borrow::Cow;
4use std::iter::IntoIterator;
5
6use crate::data::Matrix;
7use crate::traits::{self, Data, Set};
8use crate::{Axes, Color, Default, Display, Figure, Label, Opacity, Plot, Script};
9
10/// Properties common to filled curve plots
11pub struct Properties {
12    axes: Option<Axes>,
13    color: Option<Color>,
14    label: Option<Cow<'static, str>>,
15    opacity: Option<f64>,
16}
17
18impl 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
29impl 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
66impl 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
76impl 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
84impl 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
92impl 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
107pub 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
116impl<X, Y1, Y2> traits::Plot<FilledCurve<X, Y1, Y2>> for Figure
117where
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}