Skip to main content

ggplot_rs/stat/
unique.rs

1use crate::aes::Aesthetic;
2use crate::data::DataFrame;
3use crate::scale::ScaleSet;
4
5use super::Stat;
6
7/// Drops duplicate rows (identical in every column) before drawing — ggplot2's
8/// `stat_unique()`, e.g. to avoid overplotting repeated observations.
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
10pub struct StatUnique;
11
12impl Stat for StatUnique {
13    fn compute_group(&self, data: &DataFrame, _scales: &ScaleSet) -> DataFrame {
14        let names = data.column_names();
15        let cols: Vec<_> = names.iter().map(|n| data.column(n).unwrap()).collect();
16        let mut seen = std::collections::HashSet::new();
17        let keep: Vec<usize> = (0..data.nrows())
18            .filter(|&i| {
19                let key: Vec<String> = cols.iter().map(|c| c[i].to_group_key()).collect();
20                seen.insert(key)
21            })
22            .collect();
23        let mut out = DataFrame::new();
24        for (name, col) in names.into_iter().zip(cols) {
25            out.add_column(
26                name.to_string(),
27                keep.iter().map(|&i| col[i].clone()).collect(),
28            );
29        }
30        out
31    }
32
33    fn required_aes(&self) -> Vec<Aesthetic> {
34        Vec::new()
35    }
36
37    fn name(&self) -> &str {
38        "unique"
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45    use crate::data::Value;
46
47    #[test]
48    fn drops_exact_duplicates_only() {
49        let mut df = DataFrame::new();
50        df.add_column("x".into(), [1.0, 1.0, 1.0, 2.0].map(Value::Float).to_vec());
51        df.add_column("y".into(), [5.0, 5.0, 6.0, 5.0].map(Value::Float).to_vec());
52        let out = StatUnique.compute_group(&df, &ScaleSet::new());
53        assert_eq!(out.nrows(), 3);
54    }
55}