Mikko
Mikko

Reputation: 7755

How to dodge pointrange ggplots on two levels?

I would like to make a point range plot where points of groups are not stacked on each other. The plot should look like this:enter image description here:

My best attempt to do the dodging is to use a vector in dodge argument:

library(ggplot2)

dat <- structure(list(Treatment = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L, 2L, 2L), .Label = c("A", "B"), class = "factor"), 
    Temp = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 
    2L, 2L), .Label = c("10", "20"), class = "factor"), Rep = c(1L, 
    2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Meas = c(3L, 
    2L, 2L, 2L, 6L, 4L, 4L, 3L, 5L, 1L, 2L, 3L), SD = c(2L, 3L, 
    2L, 2L, 2L, 3L, 2L, 3L, 3L, 3L, 2L, 1L)), .Names = c("Treatment", 
"Temp", "Rep", "Meas", "SD"), row.names = c(NA, -12L), class = "data.frame")

ggplot(dat, aes(x = Treatment, y = Meas, ymin = Meas - SD/2, ymax = Meas + SD/2)) +
geom_linerange(aes(color = Temp), position=position_dodge(width=c(0.6,0.4)), size = 1, alpha = 0.5) +
geom_point(aes(color = Temp, shape = Temp), position=position_dodge(width=c(0.6,0.4)), size = 3) +
theme_bw()

Which leads to a plot shown below. However, all of the points are not dodged and I have to move the dots and error bars in Illustrator to get a plot show above. Is there a way to use dodge argument in ggplot2 on two levels? enter image description here

Upvotes: 15

Views: 10381

Answers (3)

Lily
Lily

Reputation: 11

Way overdue but should someone be looking for an answer like I was, a colleague showed me to make a group aesthetic with an interaction like so:

dat <- structure(list(Treatment = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 
                                              2L, 2L, 2L, 2L, 2L, 2L), .Label = c("A", "B"), class = "factor"), 
                      Temp = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 
                                         2L, 2L), .Label = c("10", "20"), class = "factor"), Rep = c(1L, 
                                                                                                     2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Meas = c(3L, 
                                                                                                                                                           2L, 2L, 2L, 6L, 4L, 4L, 3L, 5L, 1L, 2L, 3L), SD = c(2L, 3L, 
                                                                                                                                                                                                               2L, 2L, 2L, 3L, 2L, 3L, 3L, 3L, 2L, 1L)), .Names = c("Treatment", 
                                                                                                                                                                                                                                                                    "Temp", "Rep", "Meas", "SD"), row.names = c(NA, -12L), class = "data.frame")

ggplot(dat, aes(x = Treatment, y = Meas, ymin = Meas - SD/2, ymax = Meas + SD/2)) +
  geom_linerange(aes(color = Temp, group = interaction(Rep, Temp)), position=position_dodge(width=c(0.6)), size = 1, alpha = 0.5) +
  geom_point(aes(color = Temp, shape = Temp, group = interaction(Rep, Temp)), position=position_dodge(width=c(0.6)), size = 3) +
  theme_bw()  

Upvotes: 1

user974514
user974514

Reputation: 552

Thinking logically, position_dodge is more suitable for bars. It does work with lineranges on one factor level, however on the second level it's hard to define the minimum distance between the lines. Though you can make a numerical distinction between factors and then add proper position for labels.

dat1<-cbind(dat,aux=rep(1,length(dat[,1]))) 
dat1<-within(dat1, {aux = unlist(by(aux,Treatment,cumsum))})
dat1$aux<-dat1$aux+as.numeric(dat1$Treatment)*10
ggplot(dat1, aes( x=aux, y = Meas, ymin = Meas - SD/2, ymax = Meas + SD/2)) +
geom_linerange(aes(color = Temp), size = 1, alpha = 0.5) +geom_point(aes(color = Temp, shape = Temp))+
scale_x_continuous("Treatment",breaks=c(13.5,23.5), labels=c("A","B")) + # here you define coordinates for A and B 
theme_bw()

enter image description here

Upvotes: 5

Didzis Elferts
Didzis Elferts

Reputation: 98429

This will not solve the problem with position_dodge() but will be workaround for this problem.

Added new variable x to your original data frame. It contains x coordinates for points/lineranges. Values in data frame should be in order you want to plot them.

dat$x<-c(0.85,0.9,0.95,1.05,1.1,1.15,1.85,1.9,1.95,2.05,2.1,2.15)

Now use this new variable as x values and with scale_x_continuos() set breaks and labels to get A and B on scale.

ggplot(dat, aes(x = x, y = Meas, ymin = Meas - SD/2, ymax = Meas + SD/2)) +
  geom_linerange(aes(color = Temp), size = 1, alpha = 0.5) +
  geom_point(aes(color = Temp, shape = Temp), size = 3) +
  theme_bw()+
  scale_x_continuous("Treatment",breaks=c(1,2),labels=c("A","B"),limits=c(0.5,2.5))

Upvotes: 2

Related Questions