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