ploteria/
errorbar.rs

1//! Error bar plots
2
3use std::borrow::Cow;
4use std::iter::IntoIterator;
5
6use data::Matrix;
7use traits::{self, Data};
8use {Color, Display, ErrorBarDefault, Figure, LineType, Plot, PointType, Script};
9
10/// Properties common to error bar plots
11pub struct Properties {
12    color: Option<Color>,
13    label: Option<Cow<'static, str>>,
14    line_type: LineType,
15    linewidth: Option<f64>,
16    point_size: Option<f64>,
17    point_type: Option<PointType>,
18    style: Style,
19}
20
21impl Properties {
22    /// Changes the color of the error bars
23    pub fn color(&mut self, color: Color) -> &mut Properties {
24        self.color = Some(color);
25        self
26    }
27
28    /// Sets the legend label
29    pub fn label<S>(&mut self, label: S) -> &mut Properties
30    where
31        S: Into<Cow<'static, str>>,
32    {
33        self.label = Some(label.into());
34        self
35    }
36
37    /// Change the line type
38    ///
39    /// **Note** By default `Solid` lines are used
40    pub fn line_type(&mut self, lt: LineType) -> &mut Properties {
41        self.line_type = lt;
42        self
43    }
44
45    /// Changes the linewidth
46    ///
47    /// # Panics
48    ///
49    /// Panics if `lw` is a non-positive value
50    pub fn line_width(&mut self, lw: f64) -> &mut Properties {
51        assert!(lw > 0.);
52
53        self.linewidth = Some(lw);
54        self
55    }
56
57    /// Changes the size of the points
58    ///
59    /// # Panics
60    ///
61    /// Panics if `size` is a non-positive value
62    pub fn point_size(&mut self, ps: f64) -> &mut Properties {
63        assert!(ps > 0.);
64
65        self.point_size = Some(ps);
66        self
67    }
68
69    /// Changes the point type
70    pub fn point_type(&mut self, pt: PointType) -> &mut Properties {
71        self.point_type = Some(pt);
72        self
73    }
74}
75
76impl ErrorBarDefault<Style> for Properties {
77    fn default(style: Style) -> Properties {
78        Properties {
79            color: None,
80            label: None,
81            line_type: LineType::Solid,
82            linewidth: None,
83            point_type: None,
84            point_size: None,
85            style,
86        }
87    }
88}
89
90impl Script for Properties {
91    fn script(&self) -> String {
92        let mut script = format!("with {} ", self.style.display());
93
94        script.push_str(&format!("lt {} ", self.line_type.display()));
95
96        if let Some(lw) = self.linewidth {
97            script.push_str(&format!("lw {} ", lw))
98        }
99
100        if let Some(color) = self.color {
101            script.push_str(&format!("lc rgb '{}' ", color.display()))
102        }
103
104        if let Some(pt) = self.point_type {
105            script.push_str(&format!("pt {} ", pt.display()))
106        }
107
108        if let Some(ps) = self.point_size {
109            script.push_str(&format!("ps {} ", ps))
110        }
111
112        if let Some(ref label) = self.label {
113            script.push_str("title '");
114            script.push_str(label);
115            script.push('\'')
116        } else {
117            script.push_str("notitle")
118        }
119
120        script
121    }
122}
123
124#[derive(Clone, Copy)]
125enum Style {
126    XErrorBars,
127    XErrorLines,
128    YErrorBars,
129    YErrorLines,
130}
131
132impl Display<&'static str> for Style {
133    fn display(&self) -> &'static str {
134        match *self {
135            Style::XErrorBars => "xerrorbars",
136            Style::XErrorLines => "xerrorlines",
137            Style::YErrorBars => "yerrorbars",
138            Style::YErrorLines => "yerrorlines",
139        }
140    }
141}
142
143/// Asymmetric error bar plots
144pub enum ErrorBar<X, Y, L, H> {
145    /// Horizontal error bars
146    XErrorBars {
147        /// X coordinate of the data points
148        x: X,
149        /// Y coordinate of the data points
150        y: Y,
151        /// X coordinate of the left end of the error bar
152        x_low: L,
153        /// Y coordinate of the right end of the error bar
154        x_high: H,
155    },
156    /// Horizontal error bars, where each point is joined by a line
157    XErrorLines {
158        /// X coordinate of the data points
159        x: X,
160        /// Y coordinate of the data points
161        y: Y,
162        /// X coordinate of the left end of the error bar
163        x_low: L,
164        /// Y coordinate of the right end of the error bar
165        x_high: H,
166    },
167    /// Vertical error bars
168    YErrorBars {
169        /// X coordinate of the data points
170        x: X,
171        /// Y coordinate of the data points
172        y: Y,
173        /// Y coordinate of the bottom of the error bar
174        y_low: L,
175        /// Y coordinate of the top of the error bar
176        y_high: H,
177    },
178    /// Vertical error bars, where each point is joined by a line
179    YErrorLines {
180        /// X coordinate of the data points
181        x: X,
182        /// Y coordinate of the data points
183        y: Y,
184        /// Y coordinate of the bottom of the error bar
185        y_low: L,
186        /// Y coordinate of the top of the error bar
187        y_high: H,
188    },
189}
190
191impl<X, Y, L, H> ErrorBar<X, Y, L, H> {
192    fn style(&self) -> Style {
193        match *self {
194            ErrorBar::XErrorBars { .. } => Style::XErrorBars,
195            ErrorBar::XErrorLines { .. } => Style::XErrorLines,
196            ErrorBar::YErrorBars { .. } => Style::YErrorBars,
197            ErrorBar::YErrorLines { .. } => Style::YErrorLines,
198        }
199    }
200}
201
202impl<X, Y, L, H> traits::Plot<ErrorBar<X, Y, L, H>> for Figure
203where
204    H: IntoIterator,
205    H::Item: Data,
206    L: IntoIterator,
207    L::Item: Data,
208    X: IntoIterator,
209    X::Item: Data,
210    Y: IntoIterator,
211    Y::Item: Data,
212{
213    type Properties = Properties;
214
215    fn plot<F>(&mut self, e: ErrorBar<X, Y, L, H>, configure: F) -> &mut Figure
216    where
217        F: FnOnce(&mut Properties) -> &mut Properties,
218    {
219        let (x_factor, y_factor) = ::scale_factor(&self.axes, ::Axes::BottomXLeftY);
220
221        let style = e.style();
222        let (x, y, length, height, e_factor) = match e {
223            ErrorBar::XErrorBars {
224                x,
225                y,
226                x_low,
227                x_high,
228            }
229            | ErrorBar::XErrorLines {
230                x,
231                y,
232                x_low,
233                x_high,
234            } => (x, y, x_low, x_high, x_factor),
235            ErrorBar::YErrorBars {
236                x,
237                y,
238                y_low,
239                y_high,
240            }
241            | ErrorBar::YErrorLines {
242                x,
243                y,
244                y_low,
245                y_high,
246            } => (x, y, y_low, y_high, y_factor),
247        };
248        let data = Matrix::new(
249            izip!(x, y, length, height),
250            (x_factor, y_factor, e_factor, e_factor),
251        );
252        self.plots.push(Plot::new(
253            data,
254            configure(&mut ErrorBarDefault::default(style)),
255        ));
256        self
257    }
258}
259
260// TODO XY error bar
261// pub struct XyErrorBar<X, Y, XL, XH, YL, YH> {
262// x: X,
263// y: Y,
264// x_low: XL,
265// x_high: XH,
266// y_low: YL,
267// y_high: YH,
268// }
269
270// TODO Symmetric error bars
271// pub enum SymmetricErrorBar {
272// XSymmetricErrorBar { x: X, y: Y, x_delta: D },
273// XSymmetricErrorLines { x: X, y: Y, x_delta: D },
274// YSymmetricErrorBar { x: X, y: Y, y_delta: D },
275// YSymmetricErrorLines { x: X, y: Y, y_delta: D },
276// }