1919# ' @param reverse If `TRUE`, will reverse the default stacking order.
2020# ' This is useful if you're rotating both the plot and legend.
2121# ' @family position adjustments
22+ # ' @eval rd_aesthetics("position", "dodge")
23+ # '
2224# ' @export
2325# ' @examples
2426# ' ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
@@ -104,7 +106,10 @@ PositionDodge <- ggproto("PositionDodge", Position,
104106 preserve = " total" ,
105107 orientation = " x" ,
106108 reverse = NULL ,
109+ default_aes = aes(order = NULL ),
110+
107111 setup_params = function (self , data ) {
112+
108113 flipped_aes <- has_flipped_aes(data , default = self $ orientation == " y" )
109114 check_required_aesthetics(
110115 if (flipped_aes ) " y|ymin" else " x|xmin" ,
@@ -139,9 +144,22 @@ PositionDodge <- ggproto("PositionDodge", Position,
139144
140145 setup_data = function (self , data , params ) {
141146 data <- flip_data(data , params $ flipped_aes )
147+
142148 if (! " x" %in% names(data ) && all(c(" xmin" , " xmax" ) %in% names(data ))) {
143149 data $ x <- (data $ xmin + data $ xmax ) / 2
144150 }
151+
152+ data $ order <- xtfrm( # xtfrm makes anything 'sortable'
153+ data $ order %|| % ave(data $ group , data $ x , data $ PANEL , FUN = match_sorted )
154+ )
155+ if (params $ reverse ) {
156+ data $ order <- - data $ order
157+ }
158+ if (is.null(params $ n )) { # preserve = "total"
159+ data $ order <- ave(data $ order , data $ x , data $ PANEL , FUN = match_sorted )
160+ } else { # preserve = "single"
161+ data $ order <- match_sorted(data $ order )
162+ }
145163 flip_data(data , params $ flipped_aes )
146164 },
147165
@@ -179,7 +197,7 @@ pos_dodge <- function(df, width, n = NULL) {
179197
180198 # Have a new group index from 1 to number of groups.
181199 # This might be needed if the group numbers in this set don't include all of 1:n
182- groupidx <- match( df $ group , unique0 (df $ group ) )
200+ groupidx <- df $ order % || % match_sorted (df $ group )
183201
184202 # Find the center for each group, then use that to calculate xmin and xmax
185203 df $ x <- df $ x + width * ((groupidx - 0.5 ) / n - 0.5 )
@@ -188,3 +206,7 @@ pos_dodge <- function(df, width, n = NULL) {
188206
189207 df
190208}
209+
210+ match_sorted <- function (x , y = x , ... ) {
211+ vec_match(x , vec_sort(unique0(y ), ... ))
212+ }
0 commit comments