plotly_fork/traces/
candlestick.rs

1//! Candlestick trace
2
3use plotly_derive::FieldSetter;
4use serde::Serialize;
5
6use crate::{
7    color::NamedColor,
8    common::{
9        Calendar, Dim, Direction, HoverInfo, Label, LegendGroupTitle, Line, PlotType, Visible,
10    },
11    Trace,
12};
13
14/// Construct a candlestick trace.
15///
16/// # Examples
17///
18/// ```
19/// use plotly::Candlestick;
20///
21/// let x = vec!["2020-05-22", "2020-05-23"];
22/// let open = vec![5, 6];
23/// let high = vec![9, 10];
24/// let low = vec![3, 5];
25/// let close = vec![6, 9];
26///
27/// let trace = Candlestick::new(x, open, high, low, close)
28///     .name("trace_1")
29///     .show_legend(true);
30///
31/// let expected = serde_json::json!({
32///     "type": "candlestick",
33///     "x": ["2020-05-22", "2020-05-23"],
34///     "open": [5, 6],
35///     "high": [9, 10],
36///     "low": [3, 5],
37///     "close": [6, 9],
38///     "increasing": {"line": {"color": "green", "width": 1.0}},
39///     "decreasing": {"line": {"color": "red", "width": 1.0}},
40///     "name": "trace_1",
41///     "showlegend": true
42/// });
43///
44/// assert_eq!(serde_json::to_value(trace).unwrap(), expected);
45/// ```
46#[serde_with::skip_serializing_none]
47#[derive(Serialize, Debug, Clone, FieldSetter)]
48pub struct Candlestick<T, O>
49where
50    T: Serialize + Clone,
51    O: Serialize + Clone,
52{
53    #[field_setter(default = "PlotType::Candlestick")]
54    r#type: PlotType,
55    x: Option<Vec<T>>,
56    open: Option<Vec<O>>,
57    high: Option<Vec<O>>,
58    low: Option<Vec<O>>,
59    close: Option<Vec<O>>,
60    name: Option<String>,
61    visible: Option<Visible>,
62    #[serde(rename = "showlegend")]
63    show_legend: Option<bool>,
64    #[serde(rename = "legendgroup")]
65    legend_group: Option<String>,
66    #[serde(rename = "legendgrouptitle")]
67    legend_group_title: Option<LegendGroupTitle>,
68    opacity: Option<f64>,
69    text: Option<Dim<String>>,
70    #[serde(rename = "hovertext")]
71    hover_text: Option<Dim<String>>,
72    #[serde(rename = "hoverinfo")]
73    hover_info: Option<HoverInfo>,
74    #[serde(rename = "xaxis")]
75    x_axis: Option<String>,
76    #[serde(rename = "yaxis")]
77    y_axis: Option<String>,
78    line: Option<Line>,
79    #[serde(rename = "whiskerwidth")]
80    whisker_width: Option<f64>,
81    increasing: Option<Direction>,
82    decreasing: Option<Direction>,
83    #[serde(rename = "hoverlabel")]
84    hover_label: Option<Label>,
85    #[serde(rename = "xcalendar")]
86    x_calendar: Option<Calendar>,
87}
88
89impl<T, O> Candlestick<T, O>
90where
91    T: Serialize + Clone,
92    O: Serialize + Clone,
93{
94    pub fn new(x: Vec<T>, open: Vec<O>, high: Vec<O>, low: Vec<O>, close: Vec<O>) -> Box<Self> {
95        let iline = Line::new().width(1.0).color(NamedColor::Green);
96        let dline = Line::new().width(1.0).color(NamedColor::Red);
97        Box::new(Candlestick {
98            x: Some(x),
99            open: Some(open),
100            high: Some(high),
101            low: Some(low),
102            close: Some(close),
103            increasing: Some(Direction::Increasing { line: iline }),
104            decreasing: Some(Direction::Decreasing { line: dline }),
105            ..Default::default()
106        })
107    }
108}
109
110impl<X, Y> Trace for Candlestick<X, Y>
111where
112    X: Serialize + Clone,
113    Y: Serialize + Clone,
114{
115    fn to_json(&self) -> String {
116        serde_json::to_string(self).unwrap()
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use serde_json::{json, to_value};
123
124    use super::*;
125
126    #[test]
127    fn test_default_candlestick() {
128        let trace: Candlestick<i32, i32> = Candlestick::default();
129        let expected = json!({"type": "candlestick"}).to_string();
130
131        assert_eq!(trace.to_json(), expected);
132    }
133
134    #[test]
135    fn test_serialize_candlestick() {
136        let trace = Candlestick::new(
137            vec!["2020-05-20", "2020-05-21"],
138            vec![5, 6],
139            vec![9, 11],
140            vec![2, 3],
141            vec![6, 5],
142        )
143        .name("candlestick_trace")
144        .visible(Visible::True)
145        .show_legend(false)
146        .legend_group("group_1")
147        .legend_group_title(LegendGroupTitle::new("Legend Group Title"))
148        .opacity(0.3)
149        .text_array(vec!["text", "here"])
150        .text("text here")
151        .hover_text_array(vec!["hover", "text"])
152        .hover_text("hover text")
153        .hover_info(HoverInfo::Skip)
154        .x_axis("x1")
155        .y_axis("y1")
156        .line(Line::new())
157        .whisker_width(0.4)
158        .increasing(Direction::Increasing { line: Line::new() })
159        .decreasing(Direction::Decreasing { line: Line::new() })
160        .hover_label(Label::new())
161        .x_calendar(Calendar::DiscWorld);
162
163        let expected = json!({
164            "type": "candlestick",
165            "x": ["2020-05-20", "2020-05-21"],
166            "open": [5, 6],
167            "high": [9, 11],
168            "low": [2, 3],
169            "close": [6, 5],
170            "name": "candlestick_trace",
171            "visible": true,
172            "showlegend": false,
173            "legendgroup": "group_1",
174            "legendgrouptitle": {"text": "Legend Group Title"},
175            "opacity": 0.3,
176            "text": "text here",
177            "hovertext": "hover text",
178            "hoverinfo": "skip",
179            "xaxis": "x1",
180            "yaxis": "y1",
181            "line": {},
182            "whiskerwidth": 0.4,
183            "increasing": {"line": {}},
184            "decreasing": {"line": {}},
185            "hoverlabel": {},
186            "xcalendar": "discworld"
187        });
188
189        assert_eq!(to_value(trace).unwrap(), expected);
190    }
191}