15

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

Mikko
  • 7,530
  • 8
  • 55
  • 92
  • 5
    +1!Why the downvote here!! – agstudy Mar 18 '13 at 08:22
  • 1
    Interesting question, you get alittle better results by specifying `Rep` as a grouping variable, `ggplot(dat, aes(x = Treatment, y = Meas, ymin = Meas - SD/2, ymax = Meas + SD/2, group = Rep))`, but still not quite optimal. Also you can simplify the call by using `geom_pointrange`, e.g. `geom_pointrange(aes(color = Temp, shape = Temp), position=position_dodge(width=c(0.6,0.4)), size = 1, alpha = 0.7)`. – Andy W Mar 18 '13 at 13:17

3 Answers3

5

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

user974514
  • 552
  • 1
  • 7
  • 19
  • I think, you can use `position_dodge` for `lineranges` as well. The point is that it'll dodge values (grouped by `colour`) by `Treatment` and the OP needs dodge within that as well. That is, if there were only 1 value each for `Temp=10` and `Temp=20`, `dodge` would work just fine. – Arun Mar 18 '13 at 09:34
  • There's no problem of using dodge for factor `Temp`. The problem is that all `lineranges` are merged together. To prevent this I used the different factor for each observation. When we're putting dodge on factor `Treatment` we set some spacing according to X coordinate of A and B on the both sides. Each line also have the exact X coordinate however you can't do dodge on second factor, even grouping with different factor for every line wont help. – user974514 Mar 18 '13 at 10:02
  • yes, i get that. I was just writing about your first and second lines. – Arun Mar 18 '13 at 10:04
2

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))
Didzis Elferts
  • 95,661
  • 14
  • 264
  • 201
1

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()  
Lily
  • 11
  • 2