1use std::f64;
17
18use svg;
19
20use crate::axis;
21use crate::repr::CategoricalRepresentation;
22use crate::style::BoxStyle;
23use crate::svg_render;
24use crate::utils;
25
26enum BoxData<'a> {
27 Owned(Vec<f64>),
28 Ref(&'a [f64]),
29}
30
31pub struct BoxPlot<'a> {
32 data: BoxData<'a>,
33 label: String,
34 style: BoxStyle,
35}
36
37impl<'a> BoxPlot<'a> {
38 pub fn from_slice(v: &'a [f64]) -> Self {
39 BoxPlot {
40 data: BoxData::Ref(v),
41 style: BoxStyle::new(),
42 label: String::new(),
43 }
44 }
45
46 pub fn from_vec(v: Vec<f64>) -> Self {
47 BoxPlot {
48 data: BoxData::Owned(v),
49 style: BoxStyle::new(),
50 label: String::new(),
51 }
52 }
53
54 pub fn style(mut self, style: &BoxStyle) -> Self {
55 self.style.overlay(style);
56 self
57 }
58
59 pub fn get_style(&self) -> &BoxStyle {
60 &self.style
61 }
62
63 pub fn label<T>(mut self, label: T) -> Self
64 where
65 T: Into<String>,
66 {
67 self.label = label.into();
68 self
69 }
70
71 pub fn get_label(&self) -> &String {
72 &self.label
73 }
74
75 fn get_data(&'a self) -> &'a [f64] {
76 match self.data {
77 BoxData::Owned(ref v) => v,
78 BoxData::Ref(v) => v,
79 }
80 }
81
82 fn range(&self) -> (f64, f64) {
83 match self.data {
84 BoxData::Owned(ref v) => utils::range(v),
85 BoxData::Ref(v) => utils::range(v),
86 }
87 }
88}
89
90impl<'a> CategoricalRepresentation for BoxPlot<'a> {
91 fn range(&self) -> (f64, f64) {
93 self.range()
94 }
95
96 fn ticks(&self) -> Vec<String> {
98 vec![self.label.clone()]
99 }
100
101 fn to_svg(
102 &self,
103 x_axis: &axis::CategoricalAxis,
104 y_axis: &axis::ContinuousAxis,
105 face_width: f64,
106 face_height: f64,
107 ) -> svg::node::element::Group {
108 svg_render::draw_face_boxplot(
109 self.get_data(),
110 &self.label,
111 x_axis,
112 y_axis,
113 face_width,
114 face_height,
115 &self.style,
116 )
117 }
118
119 fn to_text(
120 &self,
121 _x_axis: &axis::CategoricalAxis,
122 _y_axis: &axis::ContinuousAxis,
123 _face_width: u32,
124 _face_height: u32,
125 ) -> String {
126 "".into()
127 }
128}