criterion_plot/
candlestick.rs

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}