tidyverse/ggplot2

position_dodge(perserve="single") shifts everything left

alistaire47 opened this issue · 2 comments

The new preserve parameter of position_dodge is awesome (#1935, I think), but when applied to stat_count or stat_boxplot (maybe more), with missing levels that aren't the final one, it shifts groups to the left to fill the empty level:

library(ggplot2)

df <- data.frame(x = rep(letters[1:3], each = 3), 
                 fill = factor(c(2,2,3, 1:3, 3,3,3)))

ggplot(df, aes(x, fill = fill)) + 
    geom_bar(position = position_dodge(preserve = 'single'))

plot with left-shifted bars

ggplot(mtcars, aes(factor(vs), mpg, fill = factor(cyl, c(8,6,4)))) + 
    geom_boxplot(position = position_dodge(preserve = 'single'))

boxplot example

While that behavior makes sense given that these stats previously didn't care about empty groups didn't need drawing or spacing, I suspect most users would expect bars to keep their group position à la geom_col/stat_identity (which has 0s to keep things in place):

ggplot(data.frame(table(df)), aes(x, Freq, fill = fill)) + 
    geom_col(position = 'dodge'))

plot with normally-arranged bars

Is this desired behavior or a bug?

I encountered this "feature" and I think it is hard to fix. At the instant when the dodging is done, the group information is insufficient. I think you would have to change/add another a group/sub-group that can be used by the position aesthetics. That would be a significant change to the underlying data model that has been constant and sufficient for a very long time.

May be there is another way, I may look at it again.

The new position_dodge2() function improves this by centering each group of bars (or boxes, etc.) at their x position.