Skip to main content

ggplot_rs/position/
dodge2.rs

1use crate::data::DataFrame;
2
3use super::dodge::{dedup_order, dodge_rows, group_keys};
4use super::{Position, PositionParams};
5
6/// Like position_dodge but preserves total width and adds padding between
7/// groups (ggplot2's `position_dodge2(width, padding, reverse)`). Elements
8/// are centred exactly as [`PositionDodge`](struct@super::dodge::PositionDodge)
9/// places them; on a continuous axis `xmin`/`xmax` shrink to
10/// `(1 − padding)` of each group's share.
11#[derive(Clone, Debug, PartialEq)]
12pub struct PositionDodge2 {
13    pub padding: f64,
14    /// Total dodge width; `None` = the layer default (0.9).
15    pub width: Option<f64>,
16    /// Reverse the group order.
17    pub reverse: bool,
18}
19
20impl PositionDodge2 {
21    pub fn new(padding: f64) -> Self {
22        PositionDodge2 {
23            padding,
24            ..Default::default()
25        }
26    }
27
28    /// Set the total dodge width.
29    pub fn with_width(mut self, width: f64) -> Self {
30        self.width = Some(width);
31        self
32    }
33
34    /// Reverse the order of the dodged groups (`reverse = TRUE`).
35    pub fn with_reverse(mut self, reverse: bool) -> Self {
36        self.reverse = reverse;
37        self
38    }
39}
40
41impl Default for PositionDodge2 {
42    fn default() -> Self {
43        PositionDodge2 {
44            padding: 0.1,
45            width: None,
46            reverse: false,
47        }
48    }
49}
50
51impl Position for PositionDodge2 {
52    fn compute(&self, data: &mut DataFrame, params: &PositionParams) {
53        dodge_rows(
54            data,
55            self.width.unwrap_or(params.width),
56            Some(self.padding),
57            self.reverse,
58            params.group_order.as_deref(),
59        );
60    }
61
62    fn name(&self) -> &str {
63        "dodge2"
64    }
65
66    /// Same per-panel rule as `PositionDodge` (#153): `dodge_rows` is
67    /// shared between the two.
68    fn per_panel(&self) -> bool {
69        true
70    }
71
72    /// Same whole-layer group ranking as `PositionDodge` (review #167
73    /// finding 2): `dodge_rows` is shared between the two.
74    fn group_order(&self, data: &DataFrame) -> Option<Vec<String>> {
75        group_keys(data).map(|keys| dedup_order(&keys))
76    }
77}