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, PointShape, PointStyle};
7use crate::render::RenderError;
8use crate::scale::ScaleSet;
9use crate::stat::qq::{StatQQ, StatQQBand, StatQQLine};
10use crate::stat::Stat;
11use crate::theme::Theme;
12
13use super::{Geom, GeomParams};
14
15pub struct GeomQQ {
17 pub size: f64,
18 pub color: (u8, u8, u8),
19 pub alpha: f64,
20}
21
22impl Default for GeomQQ {
23 fn default() -> Self {
24 GeomQQ {
25 size: 3.0,
26 color: (0, 0, 0),
27 alpha: 1.0,
28 }
29 }
30}
31
32impl Geom for GeomQQ {
33 fn draw(
34 &self,
35 data: &DataFrame,
36 coord: &dyn Coord,
37 scales: &ScaleSet,
38 _theme: &Theme,
39 backend: &mut dyn DrawBackend,
40 ) -> Result<(), RenderError> {
41 let x_col = data
42 .column("x")
43 .ok_or(RenderError::MissingAesthetic("x".into()))?;
44 let y_col = data
45 .column("y")
46 .ok_or(RenderError::MissingAesthetic("y".into()))?;
47 let color_col = data.column("color");
48
49 let plot_area = backend.plot_area();
50 let x_scale = scales.get(&Aesthetic::X);
51 let y_scale = scales.get(&Aesthetic::Y);
52
53 for i in 0..data.nrows() {
54 let nx = x_scale.map(|s| s.map(&x_col[i])).unwrap_or(0.0);
55 let ny = y_scale.map(|s| s.map(&y_col[i])).unwrap_or(0.0);
56 let (px, py) = coord.transform((nx, ny), &plot_area);
57
58 let pt_color = color_col
59 .and_then(|cc| scales.map_color(&Aesthetic::Color, &cc[i]))
60 .unwrap_or(self.color);
61
62 let xy = format!(
65 "({}, {})",
66 super::tip_value(&x_col[i]),
67 super::tip_value(&y_col[i])
68 );
69 let series = super::series_key(data, i);
70 let tip = Some(match &series {
71 Some(s) => format!("{s}: {xy}"),
72 None => xy,
73 });
74 super::set_mark(
75 backend,
76 tip,
77 Some(super::tip_value(&x_col[i])),
78 series,
79 super::raw_value(&y_col[i]),
80 );
81 super::set_mark_formatted(
82 backend,
83 scales,
84 Some(&x_col[i]),
85 &Aesthetic::Y,
86 Some(&y_col[i]),
87 );
88
89 backend.draw_shape(
90 (px, py),
91 self.size,
92 &PointStyle {
93 color: pt_color,
94 alpha: self.alpha,
95 filled: true,
96 shape: PointShape::Circle,
97 },
98 )?;
99 }
100 super::clear_mark(backend);
101
102 Ok(())
103 }
104
105 fn required_aes(&self) -> Vec<Aesthetic> {
106 vec![Aesthetic::Y]
107 }
108
109 fn default_stat(&self) -> Box<dyn Stat> {
110 Box::new(StatQQ)
111 }
112
113 fn default_position(&self) -> Box<dyn Position> {
114 Box::new(PositionIdentity)
115 }
116
117 fn default_params(&self) -> GeomParams {
118 GeomParams::default()
119 }
120
121 fn name(&self) -> &str {
122 "qq"
123 }
124
125 fn set_series_color(&mut self, color: (u8, u8, u8)) {
126 self.color = color;
127 }
128}
129
130pub struct GeomQQLine {
132 pub color: (u8, u8, u8),
133 pub width: f64,
134 pub alpha: f64,
135}
136
137impl Default for GeomQQLine {
138 fn default() -> Self {
139 GeomQQLine {
140 color: (255, 0, 0),
141 width: 1.0,
142 alpha: 1.0,
143 }
144 }
145}
146
147impl Geom for GeomQQLine {
148 fn draw(
149 &self,
150 data: &DataFrame,
151 coord: &dyn Coord,
152 scales: &ScaleSet,
153 _theme: &Theme,
154 backend: &mut dyn DrawBackend,
155 ) -> Result<(), RenderError> {
156 let x_col = data
157 .column("x")
158 .ok_or(RenderError::MissingAesthetic("x".into()))?;
159 let y_col = data
160 .column("y")
161 .ok_or(RenderError::MissingAesthetic("y".into()))?;
162
163 let plot_area = backend.plot_area();
164 let x_scale = scales.get(&Aesthetic::X);
165 let y_scale = scales.get(&Aesthetic::Y);
166
167 for rows in super::support::row_groups(data) {
169 let points: Vec<(f64, f64)> = rows
170 .iter()
171 .map(|&i| {
172 let nx = x_scale.map(|s| s.map(&x_col[i])).unwrap_or(0.0);
173 let ny = y_scale.map(|s| s.map(&y_col[i])).unwrap_or(0.0);
174 coord.transform((nx, ny), &plot_area)
175 })
176 .collect();
177 let first = rows[0];
178 let color = data
179 .column("color")
180 .and_then(|c| scales.map_color(&Aesthetic::Color, &c[first]))
181 .unwrap_or(self.color);
182 let series = super::series_key(data, first);
183 super::set_mark(backend, series.clone(), None, series, None);
184 super::set_mark_formatted(backend, scales, None, &Aesthetic::Y, None);
185 if points.len() >= 2 {
186 backend.draw_line(
187 &points,
188 &LineStyle {
189 color,
190 alpha: self.alpha,
191 width: self.width,
192 linetype: Linetype::Dashed,
193 ..Default::default()
194 },
195 )?;
196 }
197 }
198 super::clear_mark(backend);
199
200 Ok(())
201 }
202
203 fn required_aes(&self) -> Vec<Aesthetic> {
204 vec![Aesthetic::Y]
205 }
206
207 fn default_stat(&self) -> Box<dyn Stat> {
208 Box::new(StatQQLine)
209 }
210
211 fn default_position(&self) -> Box<dyn Position> {
212 Box::new(PositionIdentity)
213 }
214
215 fn default_params(&self) -> GeomParams {
216 GeomParams::default()
217 }
218
219 fn name(&self) -> &str {
220 "qq_line"
221 }
222
223 fn set_series_color(&mut self, color: (u8, u8, u8)) {
224 self.color = color;
225 }
226}
227
228pub struct GeomQQBand {
233 pub fill: (u8, u8, u8),
234 pub alpha: f64,
235}
236
237impl Default for GeomQQBand {
238 fn default() -> Self {
239 GeomQQBand {
241 fill: (153, 153, 153),
242 alpha: 0.5,
243 }
244 }
245}
246
247impl Geom for GeomQQBand {
248 fn draw(
249 &self,
250 data: &DataFrame,
251 coord: &dyn Coord,
252 scales: &ScaleSet,
253 _theme: &Theme,
254 backend: &mut dyn DrawBackend,
255 ) -> Result<(), RenderError> {
256 super::ribbon::draw_bands(
257 data,
258 coord,
259 scales,
260 backend,
261 self.fill,
262 self.alpha,
263 super::ribbon::BandShape::Linear,
264 )
265 }
266
267 fn required_aes(&self) -> Vec<Aesthetic> {
268 vec![Aesthetic::Y]
269 }
270
271 fn default_stat(&self) -> Box<dyn Stat> {
272 Box::new(StatQQBand::default())
273 }
274
275 fn default_position(&self) -> Box<dyn Position> {
276 Box::new(PositionIdentity)
277 }
278
279 fn default_params(&self) -> GeomParams {
280 GeomParams::default()
281 }
282
283 fn name(&self) -> &str {
284 "qq_band"
285 }
286
287 fn allows_infinite(&self) -> bool {
288 true
289 }
290
291 fn set_series_color(&mut self, color: (u8, u8, u8)) {
292 self.fill = color;
293 }
294}