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, RectStyle};
7use crate::render::RenderError;
8use crate::scale::ScaleSet;
9use crate::stat::identity::StatIdentity;
10use crate::stat::Stat;
11use crate::theme::Theme;
12
13use super::step::StepDirection;
14use super::{Geom, GeomParams};
15
16pub(crate) enum BandShape<'a> {
18 Linear,
20 Step(&'a StepDirection),
22}
23
24pub(crate) fn stepped(raw: &[(f64, f64)], direction: &StepDirection) -> Vec<(f64, f64)> {
26 let mut out = Vec::with_capacity(raw.len() * 2);
27 for (j, &(x, y)) in raw.iter().enumerate() {
28 if j > 0 {
29 let (px, py) = raw[j - 1];
30 match direction {
31 StepDirection::Hv => out.push((x, py)),
32 StepDirection::Vh => out.push((px, y)),
33 StepDirection::Mid => {
34 let m = 0.5 * (px + x);
35 out.push((m, py));
36 out.push((m, y));
37 }
38 }
39 }
40 out.push((x, y));
41 }
42 out
43}
44
45pub(crate) fn draw_bands(
49 data: &DataFrame,
50 coord: &dyn Coord,
51 scales: &ScaleSet,
52 backend: &mut dyn DrawBackend,
53 fill: (u8, u8, u8),
54 alpha: f64,
55 shape: BandShape<'_>,
56) -> Result<(), RenderError> {
57 let x_col = data
58 .column("x")
59 .ok_or(RenderError::MissingAesthetic("x".into()))?;
60 let ymin_col = data
61 .column("ymin")
62 .ok_or(RenderError::MissingAesthetic("ymin".into()))?;
63 let ymax_col = data
64 .column("ymax")
65 .ok_or(RenderError::MissingAesthetic("ymax".into()))?;
66 let plot_area = backend.plot_area();
67 let y_scale = scales.get(&Aesthetic::Y);
68 let xm = super::support::XMapper::new(data, scales);
69
70 for rows in super::support::row_groups(data) {
71 let mut pts: Vec<(f64, f64, f64)> = rows
72 .iter()
73 .map(|&i| {
74 (
75 xm.map(&x_col[i], i),
76 y_scale.map(|s| s.map(&ymin_col[i])).unwrap_or(0.0),
77 y_scale.map(|s| s.map(&ymax_col[i])).unwrap_or(0.0),
78 )
79 })
80 .filter(|(x, a, b)| x.is_finite() && a.is_finite() && b.is_finite())
81 .collect();
82 if pts.len() < 2 {
83 continue;
84 }
85 pts.sort_by(|a, b| a.0.total_cmp(&b.0));
86 let upper: Vec<(f64, f64)> = pts.iter().map(|p| (p.0, p.2)).collect();
87 let lower: Vec<(f64, f64)> = pts.iter().map(|p| (p.0, p.1)).collect();
88 let (upper, mut lower) = match shape {
89 BandShape::Linear => (upper, lower),
90 BandShape::Step(dir) => (stepped(&upper, dir), stepped(&lower, dir)),
91 };
92 lower.reverse();
93 let polygon: Vec<(f64, f64)> = upper
94 .into_iter()
95 .chain(lower)
96 .map(|p| coord.transform(p, &plot_area))
97 .collect();
98
99 let first = rows[0];
100 let band_fill = data
101 .column("fill")
102 .and_then(|c| scales.map_color(&Aesthetic::Fill, &c[first]))
103 .unwrap_or(fill);
104 let series = super::series_key(data, first);
105 super::set_mark(backend, series.clone(), None, series, None);
106 super::set_mark_formatted(backend, scales, None, &Aesthetic::Y, None);
107 backend.draw_polygon(
108 &polygon,
109 &RectStyle {
110 fill: Some(band_fill),
111 stroke: None,
112 stroke_width: 0.0,
113 alpha,
114 clip: true,
115 corner_radius: 0.0,
116 },
117 )?;
118 }
119 super::clear_mark(backend);
120 Ok(())
121}
122
123pub struct GeomRibbon {
125 pub fill: (u8, u8, u8),
126 pub alpha: f64,
127}
128
129impl Default for GeomRibbon {
130 fn default() -> Self {
131 GeomRibbon {
132 fill: (97, 156, 255),
133 alpha: 0.3,
134 }
135 }
136}
137
138impl Geom for GeomRibbon {
139 fn draw(
140 &self,
141 data: &DataFrame,
142 coord: &dyn Coord,
143 scales: &ScaleSet,
144 _theme: &Theme,
145 backend: &mut dyn DrawBackend,
146 ) -> Result<(), RenderError> {
147 draw_bands(
148 data,
149 coord,
150 scales,
151 backend,
152 self.fill,
153 self.alpha,
154 BandShape::Linear,
155 )
156 }
157
158 fn required_aes(&self) -> Vec<Aesthetic> {
159 vec![Aesthetic::X, Aesthetic::Ymin, Aesthetic::Ymax]
160 }
161
162 fn default_stat(&self) -> Box<dyn Stat> {
163 Box::new(StatIdentity)
164 }
165 fn default_position(&self) -> Box<dyn Position> {
166 Box::new(PositionIdentity)
167 }
168 fn default_params(&self) -> GeomParams {
169 GeomParams::default()
170 }
171 fn name(&self) -> &str {
172 "ribbon"
173 }
174
175 fn set_series_color(&mut self, color: (u8, u8, u8)) {
176 self.fill = color;
177 }
178}
179
180pub struct GeomStepribbon {
185 pub fill: (u8, u8, u8),
186 pub alpha: f64,
187 pub direction: StepDirection,
188}
189
190impl Default for GeomStepribbon {
191 fn default() -> Self {
192 GeomStepribbon {
193 fill: (97, 156, 255),
194 alpha: 0.3,
195 direction: StepDirection::Hv,
196 }
197 }
198}
199
200impl GeomStepribbon {
201 pub fn new(direction: StepDirection) -> Self {
203 GeomStepribbon {
204 direction,
205 ..Default::default()
206 }
207 }
208}
209
210impl Geom for GeomStepribbon {
211 fn draw(
212 &self,
213 data: &DataFrame,
214 coord: &dyn Coord,
215 scales: &ScaleSet,
216 _theme: &Theme,
217 backend: &mut dyn DrawBackend,
218 ) -> Result<(), RenderError> {
219 draw_bands(
220 data,
221 coord,
222 scales,
223 backend,
224 self.fill,
225 self.alpha,
226 BandShape::Step(&self.direction),
227 )
228 }
229
230 fn required_aes(&self) -> Vec<Aesthetic> {
231 vec![Aesthetic::X, Aesthetic::Ymin, Aesthetic::Ymax]
232 }
233
234 fn default_stat(&self) -> Box<dyn Stat> {
235 Box::new(StatIdentity)
236 }
237 fn default_position(&self) -> Box<dyn Position> {
238 Box::new(PositionIdentity)
239 }
240 fn default_params(&self) -> GeomParams {
241 GeomParams::default()
242 }
243 fn name(&self) -> &str {
244 "stepribbon"
245 }
246
247 fn allows_infinite(&self) -> bool {
248 true
249 }
250
251 fn set_series_color(&mut self, color: (u8, u8, u8)) {
252 self.fill = color;
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259
260 #[test]
261 fn step_corners() {
262 let raw = [(0.0, 1.0), (1.0, 2.0), (2.0, 3.0)];
263 assert_eq!(
264 stepped(&raw, &StepDirection::Hv),
265 vec![(0.0, 1.0), (1.0, 1.0), (1.0, 2.0), (2.0, 2.0), (2.0, 3.0)]
266 );
267 assert_eq!(
268 stepped(&raw, &StepDirection::Vh),
269 vec![(0.0, 1.0), (0.0, 2.0), (1.0, 2.0), (1.0, 3.0), (2.0, 3.0)]
270 );
271 assert_eq!(
272 stepped(&raw[..2], &StepDirection::Mid),
273 vec![(0.0, 1.0), (0.5, 1.0), (0.5, 2.0), (1.0, 2.0)]
274 );
275 }
276}