1use std::io;
2use backend::Backend;
3
4#[derive(Debug, Default)]
6pub struct Axes2D<'a> {
7 plot_data: Vec<PlotData<'a>>,
8 xlabel: Option<String>,
9 ylabel: Option<String>,
10 grid: bool,
11 legend: Option<String>,
12 xlim: Option<(f64, f64)>,
13 ylim: Option<(f64, f64)>,
14}
15
16impl<'a> Axes2D<'a> {
17 pub fn new() -> Self {
21 Default::default()
22 }
23
24 pub fn add<P: Into<PlotData<'a>>>(mut self, p: P) -> Self {
26 self.plot_data.push(p.into());
27 self
28 }
29
30 pub fn xlabel(mut self, text: &str) -> Self {
32 self.xlabel = Some(text.to_owned());
33 self
34 }
35
36 pub fn ylabel(mut self, text: &str) -> Self {
38 self.ylabel = Some(text.to_owned());
39 self
40 }
41
42 pub fn grid(mut self, enabled: bool) -> Self {
44 self.grid = enabled;
45 self
46 }
47
48 pub fn legend(mut self, loc: &str) -> Self {
52 self.legend = if loc.trim() != "" {
53 Some(loc.to_owned())
54 } else {
55 None
56 };
57 self
58 }
59
60 pub fn xlim(mut self, lb: f64, ub: f64) -> Self {
62 self.xlim = Some((lb, ub));
63 self
64 }
65
66 pub fn ylim(mut self, lb: f64, ub: f64) -> Self {
68 self.ylim = Some((lb, ub));
69 self
70 }
71
72 pub fn apply<B: Backend>(&self, mpl: &mut B) -> io::Result<()> {
73 for ref plot in &self.plot_data {
74 plot.apply(mpl)?;
75 }
76 mpl.grid(self.grid)?;
77 if let Some(ref loc) = self.legend {
78 mpl.legend(loc)?;
79 }
80 if let Some(ref xlim) = self.xlim {
81 mpl.xlim(xlim)?;
82 }
83 if let Some(ref ylim) = self.ylim {
84 mpl.ylim(ylim)?;
85 }
86 Ok(())
87 }
88}
89
90
91#[derive(Debug)]
93pub enum PlotData<'a> {
94 Scatter(Scatter<'a>),
95 Line2D(Line2D<'a>),
96 FillBetween(FillBetween<'a>),
97}
98
99impl<'a> PlotData<'a> {
100 pub fn apply<B: Backend>(&self, mpl: &mut B) -> io::Result<()> {
101 match *self {
102 PlotData::Scatter(ref s) => s.apply(mpl),
103 PlotData::Line2D(ref l) => l.apply(mpl),
104 PlotData::FillBetween(ref f) => f.apply(mpl),
105 }
106 }
107}
108
109#[derive(Debug, Default)]
110pub struct Scatter<'a> {
111 xdata: &'a [f64],
112 ydata: &'a [f64],
113 label: Option<String>,
114 color: Option<String>,
115 marker: Option<String>,
116}
117
118impl<'a> Scatter<'a> {
119 pub fn new(name: &str) -> Scatter<'a> {
120 Scatter::default().label(name)
121 }
122
123 pub fn data(mut self, xdata: &'a [f64], ydata: &'a [f64]) -> Self {
124 self.xdata = xdata;
125 self.ydata = ydata;
126 self
127 }
128
129 pub fn label(mut self, text: &str) -> Self {
130 self.label = Some(text.to_owned());
131 self
132 }
133
134 pub fn color(mut self, color: &str) -> Self {
135 self.color = Some(color.to_owned());
136 self
137 }
138
139 pub fn marker(mut self, marker: &str) -> Self {
140 self.marker = Some(marker.to_owned());
141 self
142 }
143
144 pub fn apply<B: Backend>(&self, mpl: &mut B) -> io::Result<()> {
145 mpl.scatter(self.xdata,
146 self.ydata,
147 &self.label,
148 &self.color,
149 &self.marker)?;
150 Ok(())
151 }
152}
153
154impl<'a> From<Scatter<'a>> for PlotData<'a> {
155 fn from(data: Scatter) -> PlotData {
156 PlotData::Scatter(data)
157 }
158}
159
160
161#[derive(Debug, Default)]
162pub struct Line2D<'a> {
163 xdata: &'a [f64],
164 ydata: &'a [f64],
165 label: Option<String>,
166 color: Option<String>,
167 marker: Option<String>,
168 linestyle: Option<String>,
169 linewidth: Option<f64>,
170}
171
172impl<'a> Line2D<'a> {
173 pub fn new(name: &str) -> Line2D<'a> {
174 Line2D::default().label(name)
175 }
176
177 pub fn data(mut self, xdata: &'a [f64], ydata: &'a [f64]) -> Self {
178 self.xdata = xdata;
179 self.ydata = ydata;
180 self
181 }
182
183 pub fn label(mut self, text: &str) -> Self {
184 self.label = Some(text.to_owned());
185 self
186 }
187
188 pub fn color(mut self, color: &str) -> Self {
189 self.color = Some(color.to_owned());
190 self
191 }
192
193 pub fn marker(mut self, marker: &str) -> Self {
194 self.marker = Some(marker.to_owned());
195 self
196 }
197
198 pub fn linestyle(mut self, style: &str) -> Self {
199 self.linestyle = Some(style.to_owned());
200 self
201 }
202
203 pub fn linewidth(mut self, width: f64) -> Self {
204 self.linewidth = Some(width);
205 self
206 }
207
208 pub fn apply<B: Backend>(&self, mpl: &mut B) -> io::Result<()> {
209 mpl.plot(self.xdata,
210 self.ydata,
211 &self.label,
212 &self.color,
213 &self.marker,
214 &self.linestyle,
215 &self.linewidth)?;
216 Ok(())
217 }
218}
219
220impl<'a> From<Line2D<'a>> for PlotData<'a> {
221 fn from(data: Line2D<'a>) -> PlotData<'a> {
222 PlotData::Line2D(data)
223 }
224}
225
226
227#[derive(Debug, Default)]
228pub struct FillBetween<'a> {
229 x: &'a [f64],
230 y1: &'a [f64],
231 y2: &'a [f64],
232 where_: Option<&'a [bool]>,
233 interpolate: bool,
234 step: Option<String>,
235}
236
237impl<'a> FillBetween<'a> {
238 pub fn new() -> FillBetween<'a> {
239 FillBetween::default()
240 }
241
242 pub fn data(mut self, x: &'a [f64], y1: &'a [f64], y2: &'a [f64]) -> Self {
243 self.x = x;
244 self.y1 = y1;
245 self.y2 = y2;
246 self
247 }
248
249 pub fn where_(mut self, where_: &'a [bool]) -> Self {
250 self.where_ = Some(where_);
251 self
252 }
253
254 pub fn interpolate(mut self, interpolate: bool) -> Self {
255 self.interpolate = interpolate;
256 self
257 }
258
259 pub fn step(mut self, step: &str) -> Self {
260 self.step = Some(step.to_owned());
261 self
262 }
263
264 pub fn apply<B: Backend>(&self, mpl: &mut B) -> io::Result<()> {
265 mpl.fill_between(self.x,
266 self.y1,
267 self.y2,
268 &self.where_,
269 self.interpolate,
270 &self.step)?;
271 Ok(())
272 }
273}
274
275impl<'a> From<FillBetween<'a>> for PlotData<'a> {
276 fn from(data: FillBetween<'a>) -> PlotData<'a> {
277 PlotData::FillBetween(data)
278 }
279}