Search code examples
rggplot2groupingr-forestplot

How to use position_dodge with 2 levels of groupings in ggplot2


I would like to group a series of lines by 2 factors using group = interaction in ggplot. Here is some sample code:

set.seed(123)
N <- 18
means <- rnorm(N,0,1)
ses <- rexp(N,2)
upper<- means+qnorm(0.975)*ses
lower<- means+qnorm(0.025)*ses
fruit <- rep(c("Apples","Bananas","Pears"), each=6)
size <- rep(rep(c("Small","Medium","Big"), each=2),3)
GMO <- rep(c("Yes","No"), 9)
d<- data.frame(means,upper,lower,fruit,size,GMO)


ggplot(data=d,
       aes(x = fruit,y = means, ymin = lower, ymax = upper, col=size,linetype=GMO,group=interaction(GMO, size)))+
  geom_hline(aes(fill=size),yintercept =1, linetype=2)+
  xlab('labels')+ ylab("Parameter estimates (95% Confidence Interval)")+
  geom_pointrange(position=position_dodge(width = 0.6)) +
  scale_x_discrete(name="Fruits")+
  coord_flip()-> fplot
dev.new()
fplot

Here's a link to the resulting graph: https://i.sstatic.net/5YF4F.png

I would like to bring the same coloured lines for each of the three groups closer together. In other words I would like the lines to cluster not only by the 'Fruit' variable but also the 'Size' variable for each of the fruits. poisition_dodge seems to only work for one of the interacting groups.

Thanks for your advice.


Solution

  • As far as I know that is not possible with position_dodge, i.e. it dodges according to the categories of the group aes. And it does not matter whether you map one variable on the group aes or an interaction of two or more. The groups are simply placed equidistant from one another.

    One option to achieve your desired result would be to use the "facets that don't look like facets" trick which means faceting by fruit, mapping size on x and afterwards using theme options to get rid of the facet look plus some tweaking of the x scale:

    set.seed(123)
    N <- 18
    means <- rnorm(N, 0, 1)
    ses <- rexp(N, 2)
    upper <- means + qnorm(0.975) * ses
    lower <- means + qnorm(0.025) * ses
    fruit <- rep(c("Apples", "Bananas", "Pears"), each = 6)
    size <- rep(rep(c("Small", "Medium", "Big"), each = 2), 3)
    GMO <- rep(c("Yes", "No"), 9)
    d <- data.frame(means, upper, lower, fruit, size, GMO)
    
    
    library(ggplot2)
    
    ggplot(data = d, aes(x = size, y = means, ymin = lower, ymax = upper, col = size, linetype = GMO, group = GMO)) +
      geom_hline(yintercept = 1, linetype = 2) +
      xlab("labels") +
      ylab("Parameter estimates (95% Confidence Interval)") +
      geom_pointrange(position = position_dodge(width = 0.6)) +
      scale_x_discrete(name = "Fruits", breaks = "Medium", labels = NULL, expand = c(0, 1)) +
      coord_flip() +
      facet_grid(fruit ~ ., switch = "y") +
      theme(strip.placement = "outside", 
            strip.background.y = element_blank(),
            strip.text.y.left = element_text(angle = 0),
            panel.spacing.y = unit(0, "pt"))