I want to plot over a timecourse x with y values that are often repeated (integer scores 1-4) and I want to visualize many subjects at once.
Because there is so much overlap, a vertical position dodge would be ideal, such as position_dodgev from ggstance package. However, when I try to connect the dots with geom_line, the order of the connection gets messed up and is connected based on y values and not x values.
I tried a coordinate flip work-around which was not successful. And replacing geom_line with geom_path (making sure it was ordered on the x scale) also did not work.
Here is a reproducible example:
#data
df<-tibble(x=c(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5),
y=c(1,2,3,7,7,1,2,3,7,7,2,1,6,7,7),
group=c('a','a','a','a','a','b','b','b','b','b','c','c','c','c','c'))
#horizontal dodge masks groups
ggplot(df, aes(x=x, y=y,col=group,group=group)) +
geom_point(position=position_dodge(width=0.3))+
geom_line(position=position_dodge(width=0.3))
#line connection error with vertical dodge
library(ggstance)
ggplot(df, aes(x=x, y=y,col=group,group=group)) +
geom_point(position=position_dodgev(height=0.3))+
geom_line(position=position_dodgev(height=0.3))
Horizontal dodge works as expected but does not allow visualization of all the overlapped groups in a stretch of repeated y values. Vertical dodge from ggstance connected the dots in group c in the wrong order.

I am not sure what exactly causes the issue. Knowing that position_dodge is not intended to be used with geoms and it's been called a bug, I am surprised and not at the same time about this issue.
But in any case, I found a workaround by disassembling the plot using ggplot_build, rearranging the points for geom_line within that object and then reassembling the plot again; look below:
g <- ggplot(df, aes(x=x, y=y,col=group,group=group)) +
geom_point(position=position_dodgev(height=0.3)) +
geom_line(position=position_dodgev(height=0.3))
gg <- ggplot_build(g)
# -- look at gg$data to understand following lines --
#gg$data[[2]]: data associated with geom_line as it is the 2nd geom
#c(1,2) & c(2,1): I have $group==3 ...
# ... so just need to flip 1st and 2nd datapoints within that group
gg$data[[2]][gg$data[[2]]$group==3,][c(1,2),] <-
gg$data[[2]][gg$data[[2]]$group==3,][c(2,1),]
gt <- ggplot_gtable(gg)
plot(gt)

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With