ggplot_rs/geom/
errorbarh.rs1use crate::aes::Aesthetic;
6use crate::coord::Coord;
7use crate::data::DataFrame;
8use crate::position::identity::PositionIdentity;
9use crate::position::Position;
10use crate::render::backend::{DrawBackend, LineStyle, Linetype};
11use crate::render::RenderError;
12use crate::scale::ScaleSet;
13use crate::stat::identity::StatIdentity;
14use crate::stat::Stat;
15use crate::theme::Theme;
16
17use super::{Geom, GeomParams};
18
19pub struct GeomErrorbarh {
21 pub color: (u8, u8, u8),
22 pub width: f64,
24 pub cap_height: f64,
27 pub alpha: f64,
28}
29
30impl Default for GeomErrorbarh {
31 fn default() -> Self {
32 GeomErrorbarh {
33 color: (0, 0, 0),
34 width: 1.0,
35 cap_height: 0.02,
36 alpha: 1.0,
37 }
38 }
39}
40
41impl Geom for GeomErrorbarh {
42 fn draw(
43 &self,
44 data: &DataFrame,
45 coord: &dyn Coord,
46 scales: &ScaleSet,
47 _theme: &Theme,
48 backend: &mut dyn DrawBackend,
49 ) -> Result<(), RenderError> {
50 let y_col = data
51 .column("y")
52 .ok_or(RenderError::MissingAesthetic("y".into()))?;
53 let xmin_col = data
54 .column("xmin")
55 .ok_or(RenderError::MissingAesthetic("xmin".into()))?;
56 let xmax_col = data
57 .column("xmax")
58 .ok_or(RenderError::MissingAesthetic("xmax".into()))?;
59 let plot_area = backend.plot_area();
60 let x_scale = scales.get(&Aesthetic::X);
61 let y_scale = scales.get(&Aesthetic::Y);
62
63 for i in 0..data.nrows() {
64 let ny = y_scale.map(|s| s.map(&y_col[i])).unwrap_or(0.0);
65 let nx0 = x_scale.map(|s| s.map(&xmin_col[i])).unwrap_or(0.0);
66 let nx1 = x_scale.map(|s| s.map(&xmax_col[i])).unwrap_or(0.0);
67 if !(ny.is_finite() && nx0.is_finite() && nx1.is_finite()) {
68 continue;
69 }
70 let color = data
71 .column("color")
72 .and_then(|c| scales.map_color(&Aesthetic::Color, &c[i]))
73 .unwrap_or(self.color);
74 let style = LineStyle {
75 color,
76 alpha: self.alpha,
77 width: self.width,
78 linetype: Linetype::Solid,
79 };
80 let series = super::series_key(data, i);
81 let range = format!(
82 "[{}, {}]",
83 super::tip_value(&xmin_col[i]),
84 super::tip_value(&xmax_col[i])
85 );
86 let tip = Some(match &series {
87 Some(s) => format!("{s}: {}: {range}", super::tip_value(&y_col[i])),
88 None => format!("{}: {range}", super::tip_value(&y_col[i])),
89 });
90 super::set_mark(
91 backend,
92 tip,
93 Some(super::tip_value(&y_col[i])),
94 series,
95 super::raw_value(&xmin_col[i])
96 .zip(super::raw_value(&xmax_col[i]))
97 .map(|(a, b)| format!("{a} {b}")),
98 );
99 let h = self.cap_height;
100 let t = |p: (f64, f64)| coord.transform(p, &plot_area);
101 backend.draw_line(
104 &[
105 t((nx0, ny - h)),
106 t((nx0, ny + h)),
107 t((nx0, ny)),
108 t((nx1, ny)),
109 t((nx1, ny + h)),
110 t((nx1, ny - h)),
111 ],
112 &style,
113 )?;
114 }
115 super::clear_mark(backend);
116 Ok(())
117 }
118
119 fn required_aes(&self) -> Vec<Aesthetic> {
120 vec![Aesthetic::Y, Aesthetic::Xmin, Aesthetic::Xmax]
121 }
122 fn default_stat(&self) -> Box<dyn Stat> {
123 Box::new(StatIdentity)
124 }
125 fn default_position(&self) -> Box<dyn Position> {
126 Box::new(PositionIdentity)
127 }
128 fn default_params(&self) -> GeomParams {
129 GeomParams::default()
130 }
131 fn name(&self) -> &str {
132 "errorbarh"
133 }
134 fn set_series_color(&mut self, color: (u8, u8, u8)) {
135 self.color = color;
136 }
137}