1use super::{generate_list, generate_nested_list, matrix_to_array, AsMatrix, GraphMaker};
2use num_traits::Num;
3use std::fmt::Write;
4
5pub struct Boxplot {
90 symbol: String, horizontal: bool, whisker: Option<f64>, positions: Vec<f64>, width: Option<f64>, no_fliers: bool, patch_artist: bool, median_props: String, box_props: String, whisker_props: String, extra: String, buffer: String, }
103
104impl Boxplot {
105 pub fn new() -> Self {
107 Boxplot {
108 symbol: String::new(),
109 horizontal: false,
110 whisker: None,
111 positions: Vec::new(),
112 width: None,
113 no_fliers: false,
114 patch_artist: false,
115 median_props: String::new(),
116 box_props: String::new(),
117 whisker_props: String::new(),
118 extra: String::new(),
119 buffer: String::new(),
120 }
121 }
122
123 pub fn draw<T>(&mut self, data: &Vec<Vec<T>>)
130 where
131 T: std::fmt::Display + Num,
132 {
133 generate_nested_list(&mut self.buffer, "x", data);
134 if self.positions.len() > 0 {
135 generate_list(&mut self.buffer, "positions", self.positions.as_slice());
136 }
137 let opt = self.options();
138 write!(&mut self.buffer, "p=plt.boxplot(x{})\n", &opt).unwrap();
139 }
140
141 pub fn draw_mat<'a, T, U>(&mut self, data: &'a T)
148 where
149 T: AsMatrix<'a, U>,
150 U: 'a + std::fmt::Display + Num,
151 {
152 matrix_to_array(&mut self.buffer, "x", data);
153 if self.positions.len() > 0 {
154 generate_list(&mut self.buffer, "positions", self.positions.as_slice());
155 }
156 let opt = self.options();
157 write!(&mut self.buffer, "p=plt.boxplot(x{})\n", &opt).unwrap();
158 }
159
160 pub fn set_symbol(&mut self, symbol: &str) -> &mut Self {
162 self.symbol = symbol.to_string();
163 self
164 }
165
166 pub fn set_horizontal(&mut self, flag: bool) -> &mut Self {
168 self.horizontal = flag;
169 self
170 }
171
172 pub fn set_whisker(&mut self, whisker: f64) -> &mut Self {
178 self.whisker = Some(whisker);
179 self
180 }
181
182 pub fn set_positions(&mut self, positions: &[f64]) -> &mut Self {
184 self.positions = positions.to_vec();
185 self
186 }
187
188 pub fn set_width(&mut self, width: f64) -> &mut Self {
190 self.width = Some(width);
191 self
192 }
193
194 pub fn set_no_fliers(&mut self, flag: bool) -> &mut Self {
196 self.no_fliers = flag;
197 self
198 }
199
200 pub fn set_patch_artist(&mut self, flag: bool) -> &mut Self {
202 self.patch_artist = flag;
203 self
204 }
205
206 pub fn set_medianprops(&mut self, props: &str) -> &mut Self {
210 self.median_props = props.to_string();
211 self
212 }
213
214 pub fn set_boxprops(&mut self, props: &str) -> &mut Self {
216 self.box_props = props.to_string();
217 self
218 }
219
220 pub fn set_whiskerprops(&mut self, props: &str) -> &mut Self {
222 self.whisker_props = props.to_string();
223 self
224 }
225
226 pub fn set_extra(&mut self, extra: &str) -> &mut Self {
236 self.extra = extra.to_string();
237 self
238 }
239
240 fn options(&self) -> String {
242 let mut opt = String::new();
243 if self.symbol != "" {
244 write!(&mut opt, ",sym=r'{}'", self.symbol).unwrap();
245 }
246 if self.horizontal {
247 write!(&mut opt, ",vert=False").unwrap();
248 }
249 if self.whisker != None {
250 write!(&mut opt, ",whis={}", self.whisker.unwrap()).unwrap();
251 }
252 if self.positions.len() > 0 {
253 write!(&mut opt, ",positions=positions").unwrap();
254 }
255 if self.width != None {
256 write!(&mut opt, ",widths={}", self.width.unwrap()).unwrap();
257 }
258 if self.no_fliers {
259 write!(&mut opt, ",showfliers=False").unwrap();
260 }
261 if self.patch_artist {
262 write!(&mut opt, ",patch_artist=True").unwrap();
263 }
264 if self.median_props != "" {
265 write!(&mut opt, ",medianprops={}", self.median_props).unwrap();
266 }
267 if self.box_props != "" {
268 write!(&mut opt, ",boxprops={}", self.box_props).unwrap();
269 }
270 if self.whisker_props != "" {
271 write!(&mut opt, ",whiskerprops={}", self.whisker_props).unwrap();
272 }
273 if self.extra != "" {
274 write!(&mut opt, ",{}", self.extra).unwrap();
275 }
276 opt
277 }
278}
279
280impl GraphMaker for Boxplot {
281 fn get_buffer<'a>(&'a self) -> &'a String {
282 &self.buffer
283 }
284 fn clear_buffer(&mut self) {
285 self.buffer.clear();
286 }
287}
288
289#[cfg(test)]
292mod tests {
293 use super::Boxplot;
294 use crate::GraphMaker;
295
296 #[test]
297 fn new_works() {
298 let boxes = Boxplot::new();
299 assert_eq!(boxes.symbol.len(), 0);
300 assert_eq!(boxes.horizontal, false);
301 assert_eq!(boxes.whisker, None);
302 assert_eq!(boxes.positions.len(), 0);
303 assert_eq!(boxes.width, None);
304 assert_eq!(boxes.no_fliers, false);
305 assert_eq!(boxes.patch_artist, false);
306 assert_eq!(boxes.median_props.len(), 0);
307 assert_eq!(boxes.box_props.len(), 0);
308 assert_eq!(boxes.whisker_props.len(), 0);
309 assert_eq!(boxes.extra.len(), 0);
310 assert_eq!(boxes.buffer.len(), 0);
311 }
312
313 #[test]
314 fn draw_works_1() {
315 let x = vec![
316 vec![1, 2, 3], vec![2, 3, 4, 5, 6], vec![6, 7], ];
320 let mut boxes = Boxplot::new();
321 boxes.draw(&x);
322 let b: &str = "x=[[1,2,3,],[2,3,4,5,6,],[6,7,],]\n\
323 p=plt.boxplot(x)\n";
324 assert_eq!(boxes.buffer, b);
325 boxes.clear_buffer();
326 assert_eq!(boxes.buffer, "");
327 }
328
329 #[test]
330 fn draw_works_2() {
331 let x = vec![
332 vec![1, 2, 3], vec![2, 3, 4, 5, 6], vec![6, 7], ];
336 let mut boxes = Boxplot::new();
337 boxes
338 .set_symbol("b+")
339 .set_no_fliers(true)
340 .set_horizontal(true)
341 .set_whisker(1.5)
342 .set_positions(&[1.0, 2.0, 3.0])
343 .set_width(0.5)
344 .set_patch_artist(true)
345 .set_boxprops("{'facecolor': 'C0', 'edgecolor': 'white','linewidth': 0.5}")
346 .draw(&x);
347 let b: &str = "x=[[1,2,3,],[2,3,4,5,6,],[6,7,],]\n\
348 positions=[1,2,3,]\n\
349 p=plt.boxplot(x,sym=r'b+',vert=False,whis=1.5,positions=positions,widths=0.5,showfliers=False,patch_artist=True,boxprops={'facecolor': 'C0', 'edgecolor': 'white','linewidth': 0.5})\n";
350 assert_eq!(boxes.buffer, b);
351 boxes.clear_buffer();
352 assert_eq!(boxes.buffer, "");
353 }
354
355 #[test]
356 fn draw_mat_works_1() {
357 let x = vec![
358 vec![1, 2, 3, 4, 5],
360 vec![2, 3, 4, 5, 6],
361 vec![3, 4, 5, 6, 7],
362 vec![4, 5, 6, 7, 8],
363 vec![5, 6, 7, 8, 9],
364 vec![6, 7, 8, 9, 10],
365 ];
366 let mut boxes = Boxplot::new();
367 boxes.draw_mat(&x);
368 let b: &str = "x=np.array([[1,2,3,4,5,],[2,3,4,5,6,],[3,4,5,6,7,],[4,5,6,7,8,],[5,6,7,8,9,],[6,7,8,9,10,],],dtype=float)\n\
369 p=plt.boxplot(x)\n";
370 assert_eq!(boxes.buffer, b);
371 boxes.clear_buffer();
372 assert_eq!(boxes.buffer, "");
373 }
374
375 #[test]
376 fn draw_mat_works_2() {
377 let x = vec![
378 vec![1, 2, 3, 4, 5],
380 vec![2, 3, 4, 5, 6],
381 vec![3, 4, 5, 6, 7],
382 vec![4, 5, 6, 7, 8],
383 vec![5, 6, 7, 8, 9],
384 vec![6, 7, 8, 9, 10],
385 ];
386 let mut boxes = Boxplot::new();
387 boxes
388 .set_symbol("b+")
389 .set_no_fliers(true)
390 .set_horizontal(true)
391 .set_whisker(1.5)
392 .set_positions(&[1.0, 2.0, 3.0, 4.0, 5.0])
393 .set_width(0.5)
394 .draw_mat(&x);
395 let b: &str = "x=np.array([[1,2,3,4,5,],[2,3,4,5,6,],[3,4,5,6,7,],[4,5,6,7,8,],[5,6,7,8,9,],[6,7,8,9,10,],],dtype=float)\n\
396 positions=[1,2,3,4,5,]\n\
397 p=plt.boxplot(x,sym=r'b+',vert=False,whis=1.5,positions=positions,widths=0.5,showfliers=False)\n";
398 assert_eq!(boxes.buffer, b);
399 boxes.clear_buffer();
400 assert_eq!(boxes.buffer, "");
401 }
402}