Search code examples
rggplot2geom-pointaestheticsposition-dodge

Dodge geom_points based on only a single grouping variable when there are multiple grouping variables


I am having an issue with trying to dodge points only by the color aesthetic when I am also using another aesthetic for shape. When I add the option to dodge, it dodges the points such that each shape+color option is dodged. Is there a way to specify the dodge such that a single aesthetic is being dodged? The only way I can think is to have two datasets for two separate geom_point's where the shape is manually set but unsure how that might work with the legend.

Geom_point with color and shape aesthetics being dodged

Example code

ggplot(dat,aes(x = c,y = Mean,color = Group,shape = Interval)) +
  geom_point(position = position_dodge2(width = 0.5)) +
  labs(y = "Item Average") +
  theme(legend.position = "top",
        axis.title.y = element_blank(),
        axis.text.y = element_text(size = 8)) +
  coord_flip()

Tried to specify a group aesthetic within geom_point function itself that would use only that to dodge the points by Group.


Solution

  • You need to use position_dodge instead of position_dodge2, and use group = Group inside aes to get the points dodging according to the same variable as color:

    library(ggplot2)
    
    ggplot(dat, aes(x = c, y = Mean, color = Group, shape = Interval)) +
      geom_point(aes(group = Group), position = position_dodge(width = 0.5),
                 size = 3) +
      labs(y = "Item Average") +
      theme(legend.position = "top",
            axis.title.y = element_blank(),
            axis.text.y = element_text(size = 8)) +
      coord_flip()
    

    Or, to dodge by the same variable as shape, use group = Interval

    ggplot(dat, aes(x = c, y = Mean, color = Group, shape = Interval)) +
      geom_point(aes(group = Interval), position = position_dodge(width = 0.5),
                 size = 3) +
      labs(y = "Item Average") +
      theme(legend.position = "top",
            axis.title.y = element_blank(),
            axis.text.y = element_text(size = 8)) +
      coord_flip()
    

    If I might make a suggestion, your plot might be easier to understand if you did:

    ggplot(dat, aes(x = Interval, y = Mean, color = Group)) +
      geom_point(size = 3) +
      geom_line(aes(group = Group)) +
      labs(y = "Item Average") +
      theme(legend.position = "top") +
      theme_minimal(base_size = 16) +
      scale_color_brewer(palette = "Set1") +
      theme(legend.position = "top")
    

    enter image description here

    Created on 2023-08-31 with reprex v2.0.2


    Data inferred from plot in picture

    dat <- data.frame(
      c = "View1",
      Mean = c(3.91, 3.96, 4, 4.07, 4.14, 4.29),
      Group = factor(c("No Coach", "No Coach", "Email","Coach", "Coach", "Email"),
                     levels = c("Email", "Coach", "No Coach")),
      Interval = factor(c("Post", "Pre", "Pre", "Pre", "Post", "Post"), 
                        levels = c("Pre", "Post"))
    )