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 {
30     // Allow clippy::format_push_string even with older versions of rust (<1.62) which
31     // don't have it defined.
32     #[allow(clippy::all)]
script(&self) -> String33     fn script(&self) -> String {
34         let mut script = String::from("with candlesticks ");
35 
36         script.push_str(&format!("lt {} ", self.line_type.display()));
37 
38         if let Some(lw) = self.linewidth {
39             script.push_str(&format!("lw {} ", lw))
40         }
41 
42         if let Some(color) = self.color {
43             script.push_str(&format!("lc rgb '{}' ", color.display()));
44         }
45 
46         if let Some(ref label) = self.label {
47             script.push_str("title '");
48             script.push_str(label);
49             script.push('\'')
50         } else {
51             script.push_str("notitle")
52         }
53 
54         script
55     }
56 }
57 
58 impl Set<Color> for Properties {
59     /// Sets the line color
set(&mut self, color: Color) -> &mut Properties60     fn set(&mut self, color: Color) -> &mut Properties {
61         self.color = Some(color);
62         self
63     }
64 }
65 
66 impl Set<Label> for Properties {
67     /// Sets the legend label
set(&mut self, label: Label) -> &mut Properties68     fn set(&mut self, label: Label) -> &mut Properties {
69         self.label = Some(label.0);
70         self
71     }
72 }
73 
74 impl Set<LineType> for Properties {
75     /// Changes the line type
76     ///
77     /// **Note** By default `Solid` lines are used
set(&mut self, lt: LineType) -> &mut Properties78     fn set(&mut self, lt: LineType) -> &mut Properties {
79         self.line_type = lt;
80         self
81     }
82 }
83 
84 impl Set<LineWidth> for Properties {
85     /// Changes the width of the line
86     ///
87     /// # Panics
88     ///
89     /// Panics if `width` is a non-positive value
set(&mut self, lw: LineWidth) -> &mut Properties90     fn set(&mut self, lw: LineWidth) -> &mut Properties {
91         let lw = lw.0;
92 
93         assert!(lw > 0.);
94 
95         self.linewidth = Some(lw);
96         self
97     }
98 }
99 
100 /// A candlestick consists of a box and two whiskers that extend beyond the box
101 pub struct Candlesticks<X, WM, BM, BH, WH> {
102     /// X coordinate of the candlestick
103     pub x: X,
104     /// Y coordinate of the end point of the bottom whisker
105     pub whisker_min: WM,
106     /// Y coordinate of the bottom of the box
107     pub box_min: BM,
108     /// Y coordinate of the top of the box
109     pub box_high: BH,
110     /// Y coordinate of the end point of the top whisker
111     pub whisker_high: WH,
112 }
113 
114 impl<X, WM, BM, BH, WH> traits::Plot<Candlesticks<X, WM, BM, BH, WH>> for Figure
115 where
116     BH: IntoIterator,
117     BH::Item: Data,
118     BM: IntoIterator,
119     BM::Item: Data,
120     WH: IntoIterator,
121     WH::Item: Data,
122     WM: IntoIterator,
123     WM::Item: Data,
124     X: IntoIterator,
125     X::Item: Data,
126 {
127     type Properties = Properties;
128 
plot<F>( &mut self, candlesticks: Candlesticks<X, WM, BM, BH, WH>, configure: F, ) -> &mut Figure where F: FnOnce(&mut Properties) -> &mut Properties,129     fn plot<F>(
130         &mut self,
131         candlesticks: Candlesticks<X, WM, BM, BH, WH>,
132         configure: F,
133     ) -> &mut Figure
134     where
135         F: FnOnce(&mut Properties) -> &mut Properties,
136     {
137         let (x_factor, y_factor) = crate::scale_factor(&self.axes, crate::Axes::BottomXLeftY);
138         let Candlesticks {
139             x,
140             whisker_min,
141             box_min,
142             box_high,
143             whisker_high,
144         } = candlesticks;
145 
146         let data = Matrix::new(
147             izip!(x, box_min, whisker_min, whisker_high, box_high),
148             (x_factor, y_factor, y_factor, y_factor, y_factor),
149         );
150         self.plots
151             .push(Plot::new(data, configure(&mut Default::default())));
152         self
153     }
154 }
155