1pub mod align;
2pub mod arcdiagram;
3pub mod bin;
4pub mod bin2d;
5pub mod bindot;
6pub mod binhex;
7pub mod boxplot;
8pub mod calendar;
9pub mod chord;
10#[cfg(feature = "ggpubr")]
11pub mod compare_means;
12pub mod connect;
13pub mod contour;
14pub mod contour_filled;
15#[cfg(feature = "ggpubr")]
16pub mod cor;
17pub mod count;
18pub mod density;
19pub mod density2d;
20pub mod dist;
21pub mod distribution;
22pub mod ecdf;
23pub mod ellipse;
24pub mod function;
25pub mod funnel;
26pub(crate) mod gam;
27pub mod heikin_ashi;
28pub mod identity;
29pub mod indicator;
30pub mod loess;
31pub mod manual;
32pub mod marching_squares;
33pub mod marimekko;
34pub mod network;
35pub mod pack;
36pub mod pareto;
37pub mod partition;
38pub mod qq;
39#[cfg(feature = "regression")]
40pub mod quantile;
41pub mod renko;
42pub mod sankey;
43#[cfg(feature = "sf")]
44pub mod sf_coordinates;
45pub mod smooth;
46pub mod sum;
47pub mod summary;
48pub mod summary2d;
49pub mod summary_bin;
50pub mod tree;
51pub mod treemap;
52pub mod unique;
53pub mod venn;
54pub mod waffle;
55pub mod waterfall;
56pub mod xdensity_ridges;
57pub mod ydensity;
58
59use crate::aes::{Aes, Aesthetic};
60use crate::data::DataFrame;
61use crate::scale::ScaleSet;
62
63pub trait Stat: Send + Sync {
65 fn compute_group(&self, data: &DataFrame, scales: &ScaleSet) -> DataFrame;
67
68 fn required_aes(&self) -> Vec<Aesthetic>;
70
71 fn default_aes(&self) -> Aes {
73 Aes::default()
74 }
75
76 fn panelwise(&self) -> bool {
81 false
82 }
83
84 fn computed_y(&self) -> bool {
88 false
89 }
90
91 fn name(&self) -> &str;
93
94 fn validate(&self, _warnings: &mut Vec<String>) {}
102}
103
104pub(crate) fn bw_nrd0(values: &[f64]) -> f64 {
108 let n = values.len();
109 if n < 2 {
110 return 1.0;
111 }
112 let nf = n as f64;
113 let mean = values.iter().sum::<f64>() / nf;
114 let sd = (values.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (nf - 1.0)).sqrt();
115 let mut sorted = values.to_vec();
116 sorted.sort_by(|a, b| a.total_cmp(b));
117 let q = |p: f64| {
118 let h = (n - 1) as f64 * p;
119 let lo = h.floor() as usize;
120 let hi = (lo + 1).min(n - 1);
121 sorted[lo] + (h - lo as f64) * (sorted[hi] - sorted[lo])
122 };
123 let iqr = q(0.75) - q(0.25);
124 let mut lo = sd.min(iqr / 1.34);
125 for fallback in [sd, values[0].abs(), 1.0] {
126 if lo > 0.0 && lo.is_finite() {
127 break;
128 }
129 lo = fallback;
130 }
131 0.9 * lo * nf.powf(-0.2)
132}