1pub mod area;
2pub mod bar;
3pub mod bin2d;
4pub mod blank;
5pub mod boxplot;
6pub mod bracket;
7pub mod candlestick;
8pub mod censor;
9pub mod col;
10pub mod contour;
11pub mod cooks;
12pub mod count;
13pub mod crossbar;
14pub mod curve;
15pub mod density;
16pub mod density2d;
17pub mod dotplot;
18pub mod errorbar;
19pub mod errorbarh;
20pub mod freqpoly;
21pub mod hex;
22pub mod histogram;
23pub mod jitter;
24pub mod line;
25pub mod linerange;
26pub mod path;
27pub mod point;
28pub mod pointrange;
29pub mod polygon;
30pub mod qq;
31pub mod raster;
32pub mod rect;
33pub mod refline;
34pub mod repel;
35pub mod ribbon;
36pub mod rug;
37pub mod segment;
38#[cfg(feature = "sf")]
39pub mod sf;
40pub mod smooth;
41pub mod spoke;
42pub mod step;
43pub(crate) mod support;
44pub mod text;
45pub mod tile;
46pub mod violin;
47
48use std::collections::HashMap;
49
50use crate::aes::Aesthetic;
51use crate::coord::Coord;
52use crate::data::DataFrame;
53use crate::position::Position;
54use crate::render::backend::DrawBackend;
55use crate::render::RenderError;
56use crate::scale::ScaleSet;
57use crate::stat::Stat;
58use crate::theme::Theme;
59
60#[derive(Clone, Debug, Default)]
62pub struct GeomParams {
63 pub values: HashMap<String, f64>,
64 pub color: Option<(u8, u8, u8)>,
65 pub fill: Option<(u8, u8, u8)>,
66 pub alpha: Option<f64>,
67}
68
69pub trait Geom: Send + Sync {
71 fn draw(
73 &self,
74 data: &DataFrame,
75 coord: &dyn Coord,
76 scales: &ScaleSet,
77 theme: &Theme,
78 backend: &mut dyn DrawBackend,
79 ) -> Result<(), RenderError>;
80
81 fn required_aes(&self) -> Vec<Aesthetic>;
83
84 fn default_stat(&self) -> Box<dyn Stat>;
86
87 fn default_position(&self) -> Box<dyn Position>;
89
90 fn default_params(&self) -> GeomParams;
92
93 fn name(&self) -> &str;
95
96 fn set_series_color(&mut self, _color: (u8, u8, u8)) {}
101
102 fn include_zero_baseline(&self) -> bool {
106 false
107 }
108
109 fn allows_infinite(&self) -> bool {
114 false
115 }
116
117 fn setup_data(&self, _data: &mut DataFrame) {}
122
123 fn inherit_aes(&self) -> bool {
128 true
129 }
130}
131
132pub(crate) fn tip_value(v: &crate::data::Value) -> String {
135 crate::format::format_value(v)
136}
137
138pub(crate) fn continuous_bar_half_width(
143 mapped_xs: impl Iterator<Item = f64>,
144 width: f64,
145 fallback: f64,
146) -> f64 {
147 let mut xs: Vec<f64> = mapped_xs.filter(|x| x.is_finite()).collect();
148 xs.sort_by(|a, b| a.total_cmp(b));
149 xs.dedup_by(|a, b| (*a - *b).abs() < 1e-12);
150 let gap = xs
151 .windows(2)
152 .map(|w| w[1] - w[0])
153 .fold(f64::INFINITY, f64::min);
154 if gap.is_finite() && gap > 0.0 {
155 gap * width / 2.0
156 } else {
157 fallback
158 }
159}
160
161pub(crate) fn raw_value(v: &crate::data::Value) -> Option<String> {
165 use crate::data::Value;
166 match v {
167 Value::Float(f) if f.is_finite() => Some(format!("{f}")),
168 Value::Float(_) | Value::Na => None,
169 Value::Integer(i) => Some(i.to_string()),
170 Value::DateTime(s) => Some(s.to_string()),
171 Value::Str(s) => Some(s.clone()),
172 Value::Bool(b) => Some(b.to_string()),
173 }
174}
175
176pub(crate) fn series_key(data: &DataFrame, i: usize) -> Option<String> {
179 ["color", "fill", "group"].iter().find_map(|c| {
180 data.column(c)
181 .and_then(|col| col.get(i))
182 .filter(|v| !v.is_na())
183 .map(tip_value)
184 .filter(|s| !s.is_empty())
185 })
186}
187
188pub(crate) fn measured_value(data: &DataFrame, i: usize) -> Option<String> {
191 data.column(crate::position::RAW_Y_COL)
192 .or_else(|| data.column("y"))
193 .and_then(|c| c.get(i))
194 .and_then(raw_value)
195}
196
197pub(crate) fn set_mark(
200 backend: &mut dyn DrawBackend,
201 tooltip: Option<String>,
202 x: Option<String>,
203 series: Option<String>,
204 value: Option<String>,
205) {
206 backend.set_tooltip(tooltip);
207 backend.set_mark_axis(x);
208 backend.set_mark_series(series);
209 backend.set_mark_value(value);
210}
211
212pub(crate) fn clear_mark(backend: &mut dyn DrawBackend) {
214 set_mark(backend, None, None, None, None);
215}