1pub mod align;
2pub mod bin;
3pub mod bin2d;
4pub mod bindot;
5pub mod binhex;
6pub mod boxplot;
7pub mod calendar;
8#[cfg(feature = "ggpubr")]
9pub mod compare_means;
10pub mod contour;
11pub mod contour_filled;
12#[cfg(feature = "ggpubr")]
13pub mod cor;
14pub mod count;
15pub mod density;
16pub mod density2d;
17pub mod dist;
18pub mod distribution;
19pub mod ecdf;
20pub mod ellipse;
21pub mod function;
22pub mod identity;
23pub mod loess;
24pub mod marching_squares;
25pub mod qq;
26#[cfg(feature = "regression")]
27pub mod quantile;
28pub mod smooth;
29pub mod sum;
30pub mod summary;
31pub mod summary2d;
32pub mod summary_bin;
33pub mod ydensity;
34
35use crate::aes::{Aes, Aesthetic};
36use crate::data::DataFrame;
37use crate::scale::ScaleSet;
38
39pub trait Stat: Send + Sync {
41 fn compute_group(&self, data: &DataFrame, scales: &ScaleSet) -> DataFrame;
43
44 fn required_aes(&self) -> Vec<Aesthetic>;
46
47 fn default_aes(&self) -> Aes {
49 Aes::default()
50 }
51
52 fn panelwise(&self) -> bool {
57 false
58 }
59
60 fn name(&self) -> &str;
62
63 fn validate(&self, _warnings: &mut Vec<String>) {}
71}
72
73pub(crate) fn bw_nrd0(values: &[f64]) -> f64 {
77 let n = values.len();
78 if n < 2 {
79 return 1.0;
80 }
81 let nf = n as f64;
82 let mean = values.iter().sum::<f64>() / nf;
83 let sd = (values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (nf - 1.0)).sqrt();
84 let mut sorted = values.to_vec();
85 sorted.sort_by(|a, b| a.total_cmp(b));
86 let q = |p: f64| {
87 let h = (n - 1) as f64 * p;
88 let lo = h.floor() as usize;
89 let hi = (lo + 1).min(n - 1);
90 sorted[lo] + (h - lo as f64) * (sorted[hi] - sorted[lo])
91 };
92 let iqr = q(0.75) - q(0.25);
93 let mut lo = sd.min(iqr / 1.34);
94 for fallback in [sd, values[0].abs(), 1.0] {
95 if lo > 0.0 && lo.is_finite() {
96 break;
97 }
98 lo = fallback;
99 }
100 0.9 * lo * nf.powf(-0.2)
101}