Skip to main content

plotlars_core/components/
direction.rs

1use crate::components::Rgb;
2
3/// A structure representing the styling for candlestick directions (increasing/decreasing).
4///
5/// The `Direction` struct allows customization of how candlestick lines appear when the closing price
6/// is higher (increasing) or lower (decreasing) than the opening price. This includes setting
7/// the line color and width for the candlesticks.
8///
9/// Note: Fill color is not currently supported by the underlying plotly library.
10///
11/// # Example
12///
13/// ```rust
14/// use plotlars::{CandlestickPlot, Direction, Plot, Rgb};
15/// use polars::prelude::*;
16///
17/// let dates = vec!["2024-01-01", "2024-01-02", "2024-01-03"];
18/// let open_prices = vec![100.0, 102.5, 101.0];
19/// let high_prices = vec![103.0, 104.0, 103.5];
20/// let low_prices = vec![99.0, 101.5, 100.0];
21/// let close_prices = vec![102.5, 101.0, 103.5];
22///
23/// let stock_data = df! {
24///     "date" => dates,
25///     "open" => open_prices,
26///     "high" => high_prices,
27///     "low" => low_prices,
28///     "close" => close_prices,
29/// }
30/// .unwrap();
31///
32/// let increasing = Direction::new()
33///     .line_color(Rgb(0, 150, 255))
34///     .line_width(2.0);
35///
36/// let decreasing = Direction::new()
37///     .line_color(Rgb(200, 0, 100))
38///     .line_width(2.0);
39///
40/// CandlestickPlot::builder()
41///     .data(&stock_data)
42///     .dates("date")
43///     .open("open")
44///     .high("high")
45///     .low("low")
46///     .close("close")
47///     .increasing(&increasing)
48///     .decreasing(&decreasing)
49///     .build()
50///     .plot();
51/// ```
52///
53/// ![Example](https://imgur.com/SygxOCm.png)
54#[derive(Clone, Default)]
55pub struct Direction {
56    pub line_color: Option<Rgb>,
57    pub line_width: Option<f64>,
58}
59
60impl Direction {
61    /// Creates a new `Direction` instance with default settings.
62    ///
63    /// # Returns
64    ///
65    /// A new `Direction` instance with no customizations applied.
66    pub fn new() -> Self {
67        Self::default()
68    }
69
70    /// Sets the line color for the candlestick outline and wicks.
71    ///
72    /// # Arguments
73    ///
74    /// * `color` - An `Rgb` color for the candlestick lines.
75    ///
76    /// # Returns
77    ///
78    /// The modified `Direction` instance for method chaining.
79    pub fn line_color(mut self, color: Rgb) -> Self {
80        self.line_color = Some(color);
81        self
82    }
83
84    /// Sets the line width for the candlestick outline and wicks.
85    ///
86    /// # Arguments
87    ///
88    /// * `width` - The width of the candlestick lines in pixels.
89    ///
90    /// # Returns
91    ///
92    /// The modified `Direction` instance for method chaining.
93    pub fn line_width(mut self, width: f64) -> Self {
94        self.line_width = Some(width);
95        self
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_default() {
105        let dir = Direction::new();
106        assert!(dir.line_color.is_none());
107        assert!(dir.line_width.is_none());
108    }
109
110    #[test]
111    fn test_line_color() {
112        let dir = Direction::new().line_color(Rgb(0, 255, 0));
113        let c = dir.line_color.unwrap();
114        assert_eq!(c.0, 0);
115        assert_eq!(c.1, 255);
116        assert_eq!(c.2, 0);
117    }
118
119    #[test]
120    fn test_line_width() {
121        let dir = Direction::new().line_width(2.0);
122        assert!((dir.line_width.unwrap() - 2.0).abs() < 1e-6);
123    }
124
125    #[test]
126    fn test_builder_chaining() {
127        let dir = Direction::new()
128            .line_color(Rgb(200, 0, 100))
129            .line_width(3.5);
130
131        let c = dir.line_color.unwrap();
132        assert_eq!(c.0, 200);
133        assert_eq!(c.1, 0);
134        assert_eq!(c.2, 100);
135        assert!((dir.line_width.unwrap() - 3.5).abs() < 1e-6);
136    }
137}