1//! "Candlestick" plots
2
3use std::borrow::Cow;
4use std::iter::IntoIterator;
5
6use crate::data::Matrix;
7use crate::traits::{self, Data, Set};
8use crate::{Color, Default, Display, Figure, Label, LineType, LineWidth, Plot, Script};
9
10/// Properties common to candlestick plots
11pub struct Properties {
12 color: Option<Color>,
13 label: Option<Cow<'static, str>>,
14 line_type: LineType,
15 linewidth: Option<f64>,
16}
17
18impl Default for Properties {
19 fn default() -> Properties {
20 Properties {
21 color: None,
22 label: None,
23 line_type: LineType::Solid,
24 linewidth: None,
25 }
26 }
27}
28
29impl 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)]
33 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
58impl Set<Color> for Properties {
59 /// Sets the line color
60 fn set(&mut self, color: Color) -> &mut Properties {
61 self.color = Some(color);
62 self
63 }
64}
65
66impl Set<Label> for Properties {
67 /// Sets the legend label
68 fn set(&mut self, label: Label) -> &mut Properties {
69 self.label = Some(label.0);
70 self
71 }
72}
73
74impl Set<LineType> for Properties {
75 /// Changes the line type
76 ///
77 /// **Note** By default `Solid` lines are used
78 fn set(&mut self, lt: LineType) -> &mut Properties {
79 self.line_type = lt;
80 self
81 }
82}
83
84impl Set<LineWidth> for Properties {
85 /// Changes the width of the line
86 ///
87 /// # Panics
88 ///
89 /// Panics if `width` is a non-positive value
90 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
101pub 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
114impl<X, WM, BM, BH, WH> traits::Plot<Candlesticks<X, WM, BM, BH, WH>> for Figure
115where
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
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