ggplot_rs/position/
dodge2.rs1use crate::data::{DataFrame, Value};
2
3use super::{Position, PositionParams};
4
5pub struct PositionDodge2 {
7 pub padding: f64,
8}
9
10impl PositionDodge2 {
11 pub fn new(padding: f64) -> Self {
12 PositionDodge2 { padding }
13 }
14}
15
16impl Default for PositionDodge2 {
17 fn default() -> Self {
18 PositionDodge2 { padding: 0.1 }
19 }
20}
21
22impl Position for PositionDodge2 {
23 fn compute(&self, data: &mut DataFrame, params: &PositionParams) {
24 let x_col = match data.column("x") {
25 Some(c) => c.to_vec(),
26 None => return,
27 };
28
29 let group_col = data
30 .column("fill")
31 .or_else(|| data.column("color"))
32 .or_else(|| data.column("group"));
33
34 let group_keys: Vec<String> = match group_col {
35 Some(col) => col.iter().map(|v| v.to_group_key()).collect(),
36 None => return,
37 };
38
39 let mut unique_groups: Vec<String> = Vec::new();
40 for g in &group_keys {
41 if !unique_groups.contains(g) {
42 unique_groups.push(g.clone());
43 }
44 }
45
46 let n_groups = unique_groups.len() as f64;
47 if n_groups <= 1.0 {
48 return;
49 }
50
51 let width = params.width;
52 let group_width = width / n_groups;
54 let element_width = group_width * (1.0 - self.padding);
55
56 let mut new_x = x_col.clone();
57 let has_xmin = data.has_column("xmin");
58
59 let xmin_col = data.column("xmin").map(|c| c.to_vec());
60 let xmax_col = data.column("xmax").map(|c| c.to_vec());
61
62 let mut new_xmin = xmin_col.clone();
63 let mut new_xmax = xmax_col.clone();
64
65 for (i, (x, group)) in x_col.iter().zip(group_keys.iter()).enumerate() {
66 let group_idx = unique_groups.iter().position(|g| g == group).unwrap() as f64;
67 let offset = (group_idx - (n_groups - 1.0) / 2.0) * group_width;
68
69 if let Some(x_val) = x.as_f64() {
70 new_x[i] = Value::Float(x_val + offset);
71
72 if has_xmin {
74 if let Some(ref mut xmin) = new_xmin {
75 let center = x_val + offset;
76 xmin[i] = Value::Float(center - element_width / 2.0);
77 }
78 if let Some(ref mut xmax) = new_xmax {
79 let center = x_val + offset;
80 xmax[i] = Value::Float(center + element_width / 2.0);
81 }
82 }
83 }
84 }
85
86 if let Some(col) = data.column_mut("x") {
87 *col = new_x;
88 }
89 if let Some(xmin) = new_xmin {
90 if let Some(col) = data.column_mut("xmin") {
91 *col = xmin;
92 }
93 }
94 if let Some(xmax) = new_xmax {
95 if let Some(col) = data.column_mut("xmax") {
96 *col = xmax;
97 }
98 }
99 }
100
101 fn name(&self) -> &str {
102 "dodge2"
103 }
104}