Coverage Report

Created: 2025-11-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/plotters-0.3.7/src/data/quartiles.rs
Line
Count
Source
1
/// The quartiles
2
#[derive(Clone, Debug)]
3
pub struct Quartiles {
4
    lower_fence: f64,
5
    lower: f64,
6
    median: f64,
7
    upper: f64,
8
    upper_fence: f64,
9
}
10
11
impl Quartiles {
12
    // Extract a value representing the `pct` percentile of a
13
    // sorted `s`, using linear interpolation.
14
0
    fn percentile_of_sorted<T: Into<f64> + Copy>(s: &[T], pct: f64) -> f64 {
15
0
        assert!(!s.is_empty());
16
0
        if s.len() == 1 {
17
0
            return s[0].into();
18
0
        }
19
0
        assert!(0_f64 <= pct);
20
0
        let hundred = 100_f64;
21
0
        assert!(pct <= hundred);
22
0
        if (pct - hundred).abs() < f64::EPSILON {
23
0
            return s[s.len() - 1].into();
24
0
        }
25
0
        let length = (s.len() - 1) as f64;
26
0
        let rank = (pct / hundred) * length;
27
0
        let lower_rank = rank.floor();
28
0
        let d = rank - lower_rank;
29
0
        let n = lower_rank as usize;
30
0
        let lo = s[n].into();
31
0
        let hi = s[n + 1].into();
32
0
        lo + (hi - lo) * d
33
0
    }
34
35
    /// Create a new quartiles struct with the values calculated from the argument.
36
    ///
37
    /// - `s`: The array of the original values
38
    /// - **returns** The newly created quartiles
39
    ///
40
    /// ```rust
41
    /// use plotters::prelude::*;
42
    ///
43
    /// let quartiles = Quartiles::new(&[7, 15, 36, 39, 40, 41]);
44
    /// assert_eq!(quartiles.median(), 37.5);
45
    /// ```
46
0
    pub fn new<T: Into<f64> + Copy + PartialOrd>(s: &[T]) -> Self {
47
0
        let mut s = s.to_owned();
48
0
        s.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
49
50
0
        let lower = Quartiles::percentile_of_sorted(&s, 25_f64);
51
0
        let median = Quartiles::percentile_of_sorted(&s, 50_f64);
52
0
        let upper = Quartiles::percentile_of_sorted(&s, 75_f64);
53
0
        let iqr = upper - lower;
54
0
        let lower_fence = lower - 1.5 * iqr;
55
0
        let upper_fence = upper + 1.5 * iqr;
56
0
        Self {
57
0
            lower_fence,
58
0
            lower,
59
0
            median,
60
0
            upper,
61
0
            upper_fence,
62
0
        }
63
0
    }
64
65
    /// Get the quartiles values.
66
    ///
67
    /// - **returns** The array [lower fence, lower quartile, median, upper quartile, upper fence]
68
    ///
69
    /// ```rust
70
    /// use plotters::prelude::*;
71
    ///
72
    /// let quartiles = Quartiles::new(&[7, 15, 36, 39, 40, 41]);
73
    /// let values = quartiles.values();
74
    /// assert_eq!(values, [-9.0, 20.25, 37.5, 39.75, 69.0]);
75
    /// ```
76
0
    pub fn values(&self) -> [f32; 5] {
77
0
        [
78
0
            self.lower_fence as f32,
79
0
            self.lower as f32,
80
0
            self.median as f32,
81
0
            self.upper as f32,
82
0
            self.upper_fence as f32,
83
0
        ]
84
0
    }
85
86
    /// Get the quartiles median.
87
    ///
88
    /// - **returns** The median
89
    ///
90
    /// ```rust
91
    /// use plotters::prelude::*;
92
    ///
93
    /// let quartiles = Quartiles::new(&[7, 15, 36, 39, 40, 41]);
94
    /// assert_eq!(quartiles.median(), 37.5);
95
    /// ```
96
0
    pub fn median(&self) -> f64 {
97
0
        self.median
98
0
    }
99
}
100
101
#[cfg(test)]
102
mod test {
103
    use super::*;
104
105
    #[test]
106
    #[should_panic]
107
    fn test_empty_input() {
108
        let empty_array: [i32; 0] = [];
109
        Quartiles::new(&empty_array);
110
    }
111
112
    #[test]
113
    fn test_low_inputs() {
114
        assert_eq!(
115
            Quartiles::new(&[15.0]).values(),
116
            [15.0, 15.0, 15.0, 15.0, 15.0]
117
        );
118
        assert_eq!(
119
            Quartiles::new(&[10, 20]).values(),
120
            [5.0, 12.5, 15.0, 17.5, 25.0]
121
        );
122
        assert_eq!(
123
            Quartiles::new(&[10, 20, 30]).values(),
124
            [0.0, 15.0, 20.0, 25.0, 40.0]
125
        );
126
    }
127
}