Skip to main content

ggplot_rs/geom/
rug.rs

1use crate::aes::Aesthetic;
2use crate::coord::Coord;
3use crate::data::DataFrame;
4use crate::position::identity::PositionIdentity;
5use crate::position::Position;
6use crate::render::backend::{DrawBackend, LineStyle, Linetype};
7use crate::render::RenderError;
8use crate::scale::ScaleSet;
9use crate::stat::identity::StatIdentity;
10use crate::stat::Stat;
11use crate::theme::Theme;
12
13use super::{Geom, GeomParams};
14
15/// Rug geometry — tick marks along axis margins.
16pub struct GeomRug {
17    pub color: (u8, u8, u8),
18    pub alpha: f64,
19    pub length: f64,
20    pub sides: String,
21}
22
23impl Default for GeomRug {
24    fn default() -> Self {
25        GeomRug {
26            color: (0, 0, 0),
27            alpha: 0.5,
28            length: 0.03,
29            sides: "bl".to_string(),
30        }
31    }
32}
33
34impl Geom for GeomRug {
35    fn draw(
36        &self,
37        data: &DataFrame,
38        coord: &dyn Coord,
39        scales: &ScaleSet,
40        _theme: &Theme,
41        backend: &mut dyn DrawBackend,
42    ) -> Result<(), RenderError> {
43        let x_col = data.column("x");
44        let y_col = data.column("y");
45
46        let plot_area = backend.plot_area();
47        let x_scale = scales.get(&Aesthetic::X);
48        let y_scale = scales.get(&Aesthetic::Y);
49
50        let style = LineStyle {
51            color: self.color,
52            alpha: self.alpha,
53            width: 0.5,
54            linetype: Linetype::Solid,
55            ..Default::default()
56        };
57
58        let len = self.length;
59
60        if self.sides.contains('b') {
61            if let Some(xc) = x_col {
62                for val in xc {
63                    let nx = x_scale.map(|s| s.map(val)).unwrap_or(0.0);
64                    let (px, py_bottom) = coord.transform((nx, 0.0), &plot_area);
65                    let (_, py_up) = coord.transform((nx, len), &plot_area);
66                    backend.draw_line(&[(px, py_bottom), (px, py_up)], &style)?;
67                }
68            }
69        }
70
71        if self.sides.contains('t') {
72            if let Some(xc) = x_col {
73                for val in xc {
74                    let nx = x_scale.map(|s| s.map(val)).unwrap_or(0.0);
75                    let (px, py_top) = coord.transform((nx, 1.0), &plot_area);
76                    let (_, py_down) = coord.transform((nx, 1.0 - len), &plot_area);
77                    backend.draw_line(&[(px, py_top), (px, py_down)], &style)?;
78                }
79            }
80        }
81
82        if self.sides.contains('l') {
83            if let Some(yc) = y_col {
84                for val in yc {
85                    let ny = y_scale.map(|s| s.map(val)).unwrap_or(0.0);
86                    let (px_left, py) = coord.transform((0.0, ny), &plot_area);
87                    let (px_right, _) = coord.transform((len, ny), &plot_area);
88                    backend.draw_line(&[(px_left, py), (px_right, py)], &style)?;
89                }
90            }
91        }
92
93        if self.sides.contains('r') {
94            if let Some(yc) = y_col {
95                for val in yc {
96                    let ny = y_scale.map(|s| s.map(val)).unwrap_or(0.0);
97                    let (px_right, py) = coord.transform((1.0, ny), &plot_area);
98                    let (px_left, _) = coord.transform((1.0 - len, ny), &plot_area);
99                    backend.draw_line(&[(px_right, py), (px_left, py)], &style)?;
100                }
101            }
102        }
103
104        Ok(())
105    }
106
107    fn required_aes(&self) -> Vec<Aesthetic> {
108        vec![Aesthetic::X]
109    }
110
111    fn default_stat(&self) -> Box<dyn Stat> {
112        Box::new(StatIdentity)
113    }
114    fn default_position(&self) -> Box<dyn Position> {
115        Box::new(PositionIdentity)
116    }
117    fn default_params(&self) -> GeomParams {
118        GeomParams::default()
119    }
120    fn name(&self) -> &str {
121        "rug"
122    }
123
124    fn apply_element_geom(&mut self, el: &crate::theme::elements::ElementGeom) {
125        if let (true, Some(ink)) = (self.color == (0, 0, 0), el.ink) {
126            self.color = ink;
127        }
128    }
129
130    fn set_series_color(&mut self, color: (u8, u8, u8)) {
131        self.color = color;
132    }
133}