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