1 //! "Candlestick" plots
2 
3 use std::borrow::Cow;
4 use std::iter::IntoIterator;
5 
6 use crate::data::Matrix;
7 use crate::traits::{self, Data, Set};
8 use crate::{Color, Default, Display, Figure, Label, LineType, LineWidth, Plot, Script};
9 
10 /// Properties common to candlestick plots
11 pub struct Properties {
12     color: Option<Color>,
13     label: Option<Cow<'static, str>>,
14     line_type: LineType,
15     linewidth: Option<f64>,
16 }
17 
18 impl Default for Properties {
default() -> Properties19     fn default() -> Properties {
20         Properties {
21             color: None,
22             label: None,
23             line_type: LineType::Solid,
24             linewidth: None,
25         }
26     }
27 }
28 
29 impl Script for Properties {
script(&self) -> String30     fn script(&self) -> String {
31         let mut script = String::from("with candlesticks ");
32 
33         script.push_str(&format!("lt {} ", self.line_type.display()));
34 
35         if let Some(lw) = self.linewidth {
36             script.push_str(&format!("lw {} ", lw))
37         }
38 
39         if let Some(color) = self.color {
40             script.push_str(&format!("lc rgb '{}' ", color.display()));
41         }
42 
43         if let Some(ref label) = self.label {
44             script.push_str("title '");
45             script.push_str(label);
46             script.push('\'')
47         } else {
48             script.push_str("notitle")
49         }
50 
51         script
52     }
53 }
54 
55 impl Set<Color> for Properties {
56     /// Sets the line color
set(&mut self, color: Color) -> &mut Properties57     fn set(&mut self, color: Color) -> &mut Properties {
58         self.color = Some(color);
59         self
60     }
61 }
62 
63 impl Set<Label> for Properties {
64     /// Sets the legend label
set(&mut self, label: Label) -> &mut Properties65     fn set(&mut self, label: Label) -> &mut Properties {
66         self.label = Some(label.0);
67         self
68     }
69 }
70 
71 impl Set<LineType> for Properties {
72     /// Changes the line type
73     ///
74     /// **Note** By default `Solid` lines are used
set(&mut self, lt: LineType) -> &mut Properties75     fn set(&mut self, lt: LineType) -> &mut Properties {
76         self.line_type = lt;
77         self
78     }
79 }
80 
81 impl Set<LineWidth> for Properties {
82     /// Changes the width of the line
83     ///
84     /// # Panics
85     ///
86     /// Panics if `width` is a non-positive value
set(&mut self, lw: LineWidth) -> &mut Properties87     fn set(&mut self, lw: LineWidth) -> &mut Properties {
88         let lw = lw.0;
89 
90         assert!(lw > 0.);
91 
92         self.linewidth = Some(lw);
93         self
94     }
95 }
96 
97 /// A candlestick consists of a box and two whiskers that extend beyond the box
98 pub struct Candlesticks<X, WM, BM, BH, WH> {
99     /// X coordinate of the candlestick
100     pub x: X,
101     /// Y coordinate of the end point of the bottom whisker
102     pub whisker_min: WM,
103     /// Y coordinate of the bottom of the box
104     pub box_min: BM,
105     /// Y coordinate of the top of the box
106     pub box_high: BH,
107     /// Y coordinate of the end point of the top whisker
108     pub whisker_high: WH,
109 }
110 
111 impl<X, WM, BM, BH, WH> traits::Plot<Candlesticks<X, WM, BM, BH, WH>> for Figure
112 where
113     BH: IntoIterator,
114     BH::Item: Data,
115     BM: IntoIterator,
116     BM::Item: Data,
117     WH: IntoIterator,
118     WH::Item: Data,
119     WM: IntoIterator,
120     WM::Item: Data,
121     X: IntoIterator,
122     X::Item: Data,
123 {
124     type Properties = Properties;
125 
plot<F>( &mut self, candlesticks: Candlesticks<X, WM, BM, BH, WH>, configure: F, ) -> &mut Figure where F: FnOnce(&mut Properties) -> &mut Properties,126     fn plot<F>(
127         &mut self,
128         candlesticks: Candlesticks<X, WM, BM, BH, WH>,
129         configure: F,
130     ) -> &mut Figure
131     where
132         F: FnOnce(&mut Properties) -> &mut Properties,
133     {
134         let (x_factor, y_factor) = crate::scale_factor(&self.axes, crate::Axes::BottomXLeftY);
135         let Candlesticks {
136             x,
137             whisker_min,
138             box_min,
139             box_high,
140             whisker_high,
141         } = candlesticks;
142 
143         let data = Matrix::new(
144             izip!(x, box_min, whisker_min, whisker_high, box_high),
145             (x_factor, y_factor, y_factor, y_factor, y_factor),
146         );
147         self.plots
148             .push(Plot::new(data, configure(&mut Default::default())));
149         self
150     }
151 }
152