1use std::borrow::Cow;
4
5use crate::data::Matrix;
6use crate::traits::{self, Data, Set};
7use crate::{
8 Color, Display, ErrorBarDefault, Figure, Label, LineType, LineWidth, Plot, PointSize,
9 PointType, Script,
10};
11
12pub struct Properties {
14 color: Option<Color>,
15 label: Option<Cow<'static, str>>,
16 line_type: LineType,
17 linewidth: Option<f64>,
18 point_size: Option<f64>,
19 point_type: Option<PointType>,
20 style: Style,
21}
22
23impl ErrorBarDefault<Style> for Properties {
24 fn default(style: Style) -> Properties {
25 Properties {
26 color: None,
27 label: None,
28 line_type: LineType::Solid,
29 linewidth: None,
30 point_type: None,
31 point_size: None,
32 style,
33 }
34 }
35}
36
37impl Script for Properties {
38 fn script(&self) -> String {
39 let mut script = format!("with {} ", self.style.display());
40
41 script.push_str(&format!("lt {} ", self.line_type.display()));
42
43 if let Some(lw) = self.linewidth {
44 script.push_str(&format!("lw {} ", lw))
45 }
46
47 if let Some(color) = self.color {
48 script.push_str(&format!("lc rgb '{}' ", color.display()))
49 }
50
51 if let Some(pt) = self.point_type {
52 script.push_str(&format!("pt {} ", pt.display()))
53 }
54
55 if let Some(ps) = self.point_size {
56 script.push_str(&format!("ps {} ", ps))
57 }
58
59 if let Some(ref label) = self.label {
60 script.push_str("title '");
61 script.push_str(label);
62 script.push('\'')
63 } else {
64 script.push_str("notitle")
65 }
66
67 script
68 }
69}
70
71impl Set<Color> for Properties {
72 fn set(&mut self, color: Color) -> &mut Properties {
74 self.color = Some(color);
75 self
76 }
77}
78
79impl Set<Label> for Properties {
80 fn set(&mut self, label: Label) -> &mut Properties {
82 self.label = Some(label.0);
83 self
84 }
85}
86
87impl Set<LineType> for Properties {
88 fn set(&mut self, lt: LineType) -> &mut Properties {
92 self.line_type = lt;
93 self
94 }
95}
96
97impl Set<LineWidth> for Properties {
98 fn set(&mut self, lw: LineWidth) -> &mut Properties {
104 let lw = lw.0;
105
106 assert!(lw > 0.);
107
108 self.linewidth = Some(lw);
109 self
110 }
111}
112
113impl Set<PointSize> for Properties {
114 fn set(&mut self, ps: PointSize) -> &mut Properties {
120 let ps = ps.0;
121
122 assert!(ps > 0.);
123
124 self.point_size = Some(ps);
125 self
126 }
127}
128
129impl Set<PointType> for Properties {
130 fn set(&mut self, pt: PointType) -> &mut Properties {
132 self.point_type = Some(pt);
133 self
134 }
135}
136
137#[derive(Clone, Copy)]
138enum Style {
139 XErrorBars,
140 XErrorLines,
141 YErrorBars,
142 YErrorLines,
143}
144
145impl Display<&'static str> for Style {
146 fn display(&self) -> &'static str {
147 match *self {
148 Style::XErrorBars => "xerrorbars",
149 Style::XErrorLines => "xerrorlines",
150 Style::YErrorBars => "yerrorbars",
151 Style::YErrorLines => "yerrorlines",
152 }
153 }
154}
155
156pub enum ErrorBar<X, Y, L, H> {
158 XErrorBars {
160 x: X,
162 y: Y,
164 x_low: L,
166 x_high: H,
168 },
169 XErrorLines {
171 x: X,
173 y: Y,
175 x_low: L,
177 x_high: H,
179 },
180 YErrorBars {
182 x: X,
184 y: Y,
186 y_low: L,
188 y_high: H,
190 },
191 YErrorLines {
193 x: X,
195 y: Y,
197 y_low: L,
199 y_high: H,
201 },
202}
203
204impl<X, Y, L, H> ErrorBar<X, Y, L, H> {
205 fn style(&self) -> Style {
206 match *self {
207 ErrorBar::XErrorBars { .. } => Style::XErrorBars,
208 ErrorBar::XErrorLines { .. } => Style::XErrorLines,
209 ErrorBar::YErrorBars { .. } => Style::YErrorBars,
210 ErrorBar::YErrorLines { .. } => Style::YErrorLines,
211 }
212 }
213}
214
215impl<X, Y, L, H> traits::Plot<ErrorBar<X, Y, L, H>> for Figure
216where
217 H: IntoIterator,
218 H::Item: Data,
219 L: IntoIterator,
220 L::Item: Data,
221 X: IntoIterator,
222 X::Item: Data,
223 Y: IntoIterator,
224 Y::Item: Data,
225{
226 type Properties = Properties;
227
228 fn plot<F>(&mut self, e: ErrorBar<X, Y, L, H>, configure: F) -> &mut Figure
229 where
230 F: FnOnce(&mut Properties) -> &mut Properties,
231 {
232 let (x_factor, y_factor) = crate::scale_factor(&self.axes, crate::Axes::BottomXLeftY);
233
234 let style = e.style();
235 let (x, y, length, height, e_factor) = match e {
236 ErrorBar::XErrorBars {
237 x,
238 y,
239 x_low,
240 x_high,
241 }
242 | ErrorBar::XErrorLines {
243 x,
244 y,
245 x_low,
246 x_high,
247 } => (x, y, x_low, x_high, x_factor),
248 ErrorBar::YErrorBars {
249 x,
250 y,
251 y_low,
252 y_high,
253 }
254 | ErrorBar::YErrorLines {
255 x,
256 y,
257 y_low,
258 y_high,
259 } => (x, y, y_low, y_high, y_factor),
260 };
261 let data = Matrix::new(
262 itertools::izip!(x, y, length, height),
263 (x_factor, y_factor, e_factor, e_factor),
264 );
265 self.plots.push(Plot::new(
266 data,
267 configure(&mut ErrorBarDefault::default(style)),
268 ));
269 self
270 }
271}
272
273