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
15pub 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 };
56
57 let len = self.length;
58
59 if self.sides.contains('b') {
60 if let Some(xc) = x_col {
61 for val in xc {
62 let nx = x_scale.map(|s| s.map(val)).unwrap_or(0.0);
63 let (px, py_bottom) = coord.transform((nx, 0.0), &plot_area);
64 let (_, py_up) = coord.transform((nx, len), &plot_area);
65 backend.draw_line(&[(px, py_bottom), (px, py_up)], &style)?;
66 }
67 }
68 }
69
70 if self.sides.contains('t') {
71 if let Some(xc) = x_col {
72 for val in xc {
73 let nx = x_scale.map(|s| s.map(val)).unwrap_or(0.0);
74 let (px, py_top) = coord.transform((nx, 1.0), &plot_area);
75 let (_, py_down) = coord.transform((nx, 1.0 - len), &plot_area);
76 backend.draw_line(&[(px, py_top), (px, py_down)], &style)?;
77 }
78 }
79 }
80
81 if self.sides.contains('l') {
82 if let Some(yc) = y_col {
83 for val in yc {
84 let ny = y_scale.map(|s| s.map(val)).unwrap_or(0.0);
85 let (px_left, py) = coord.transform((0.0, ny), &plot_area);
86 let (px_right, _) = coord.transform((len, ny), &plot_area);
87 backend.draw_line(&[(px_left, py), (px_right, py)], &style)?;
88 }
89 }
90 }
91
92 if self.sides.contains('r') {
93 if let Some(yc) = y_col {
94 for val in yc {
95 let ny = y_scale.map(|s| s.map(val)).unwrap_or(0.0);
96 let (px_right, py) = coord.transform((1.0, ny), &plot_area);
97 let (px_left, _) = coord.transform((1.0 - len, ny), &plot_area);
98 backend.draw_line(&[(px_right, py), (px_left, py)], &style)?;
99 }
100 }
101 }
102
103 Ok(())
104 }
105
106 fn required_aes(&self) -> Vec<Aesthetic> {
107 vec![Aesthetic::X]
108 }
109
110 fn default_stat(&self) -> Box<dyn Stat> {
111 Box::new(StatIdentity)
112 }
113 fn default_position(&self) -> Box<dyn Position> {
114 Box::new(PositionIdentity)
115 }
116 fn default_params(&self) -> GeomParams {
117 GeomParams::default()
118 }
119 fn name(&self) -> &str {
120 "rug"
121 }
122
123 fn set_series_color(&mut self, color: (u8, u8, u8)) {
124 self.color = color;
125 }
126}