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}