1use std::borrow::Cow;
4
5use crate::data::Matrix;
6use crate::traits::{self, Data, Set};
7use crate::{
8 Axes, Color, CurveDefault, Display, Figure, Label, LineType, LineWidth, Plot, PointSize,
9 PointType, Script,
10};
11
12pub struct Properties {
14 axes: Option<Axes>,
15 color: Option<Color>,
16 label: Option<Cow<'static, str>>,
17 line_type: LineType,
18 linewidth: Option<f64>,
19 point_type: Option<PointType>,
20 point_size: Option<f64>,
21 style: Style,
22}
23
24impl CurveDefault<Style> for Properties {
25 fn default(style: Style) -> Properties {
26 Properties {
27 axes: None,
28 color: None,
29 label: None,
30 line_type: LineType::Solid,
31 linewidth: None,
32 point_size: None,
33 point_type: None,
34 style,
35 }
36 }
37}
38
39impl Script for Properties {
40 fn script(&self) -> String {
41 let mut script = if let Some(axes) = self.axes {
42 format!("axes {} ", axes.display())
43 } else {
44 String::new()
45 };
46
47 script.push_str(&format!("with {} ", self.style.display()));
48 script.push_str(&format!("lt {} ", self.line_type.display()));
49
50 if let Some(lw) = self.linewidth {
51 script.push_str(&format!("lw {} ", lw))
52 }
53
54 if let Some(color) = self.color {
55 script.push_str(&format!("lc rgb '{}' ", color.display()))
56 }
57
58 if let Some(pt) = self.point_type {
59 script.push_str(&format!("pt {} ", pt.display()))
60 }
61
62 if let Some(ps) = self.point_size {
63 script.push_str(&format!("ps {} ", ps))
64 }
65
66 if let Some(ref label) = self.label {
67 script.push_str("title '");
68 script.push_str(label);
69 script.push('\'')
70 } else {
71 script.push_str("notitle")
72 }
73
74 script
75 }
76}
77
78impl Set<Axes> for Properties {
79 fn set(&mut self, axes: Axes) -> &mut Properties {
83 self.axes = Some(axes);
84 self
85 }
86}
87
88impl Set<Color> for Properties {
89 fn set(&mut self, color: Color) -> &mut Properties {
91 self.color = Some(color);
92 self
93 }
94}
95
96impl Set<Label> for Properties {
97 fn set(&mut self, label: Label) -> &mut Properties {
99 self.label = Some(label.0);
100 self
101 }
102}
103
104impl Set<LineType> for Properties {
105 fn set(&mut self, lt: LineType) -> &mut Properties {
109 self.line_type = lt;
110 self
111 }
112}
113
114impl Set<LineWidth> for Properties {
115 fn set(&mut self, lw: LineWidth) -> &mut Properties {
121 let lw = lw.0;
122
123 assert!(lw > 0.);
124
125 self.linewidth = Some(lw);
126 self
127 }
128}
129
130impl Set<PointSize> for Properties {
131 fn set(&mut self, ps: PointSize) -> &mut Properties {
137 let ps = ps.0;
138
139 assert!(ps > 0.);
140
141 self.point_size = Some(ps);
142 self
143 }
144}
145
146impl Set<PointType> for Properties {
147 fn set(&mut self, pt: PointType) -> &mut Properties {
149 self.point_type = Some(pt);
150 self
151 }
152}
153
154pub enum Curve<X, Y> {
156 Dots {
158 x: X,
160 y: Y,
162 },
163 Impulses {
165 x: X,
167 y: Y,
169 },
170 Lines {
172 x: X,
174 y: Y,
176 },
177 LinesPoints {
179 x: X,
181 y: Y,
183 },
184 Points {
186 x: X,
188 y: Y,
190 },
191 Steps {
193 x: X,
195 y: Y,
197 },
198}
199
200impl<X, Y> Curve<X, Y> {
201 fn style(&self) -> Style {
202 match *self {
203 Curve::Dots { .. } => Style::Dots,
204 Curve::Impulses { .. } => Style::Impulses,
205 Curve::Lines { .. } => Style::Lines,
206 Curve::LinesPoints { .. } => Style::LinesPoints,
207 Curve::Points { .. } => Style::Points,
208 Curve::Steps { .. } => Style::Steps,
209 }
210 }
211}
212
213#[derive(Clone, Copy)]
214enum Style {
215 Dots,
216 Impulses,
217 Lines,
218 LinesPoints,
219 Points,
220 Steps,
221}
222
223impl Display<&'static str> for Style {
224 fn display(&self) -> &'static str {
225 match *self {
226 Style::Dots => "dots",
227 Style::Impulses => "impulses",
228 Style::Lines => "lines",
229 Style::LinesPoints => "linespoints",
230 Style::Points => "points",
231 Style::Steps => "steps",
232 }
233 }
234}
235
236impl<X, Y> traits::Plot<Curve<X, Y>> for Figure
237where
238 X: IntoIterator,
239 X::Item: Data,
240 Y: IntoIterator,
241 Y::Item: Data,
242{
243 type Properties = Properties;
244
245 fn plot<F>(&mut self, curve: Curve<X, Y>, configure: F) -> &mut Figure
246 where
247 F: FnOnce(&mut Properties) -> &mut Properties,
248 {
249 let style = curve.style();
250 let (x, y) = match curve {
251 Curve::Dots { x, y }
252 | Curve::Impulses { x, y }
253 | Curve::Lines { x, y }
254 | Curve::LinesPoints { x, y }
255 | Curve::Points { x, y }
256 | Curve::Steps { x, y } => (x, y),
257 };
258
259 let mut props = CurveDefault::default(style);
260 configure(&mut props);
261
262 let (x_factor, y_factor) =
263 crate::scale_factor(&self.axes, props.axes.unwrap_or(crate::Axes::BottomXLeftY));
264
265 let data = Matrix::new(itertools::izip!(x, y), (x_factor, y_factor));
266 self.plots.push(Plot::new(data, &props));
267 self
268 }
269}