5

I've tried several suggestions based on several posts on here, as well as reading through the ggplot2 documentation, but this question is slightly different, and I haven't found a solution yet.

Here's a snippet of code to make a melted dataframe similar to the one I'm working with:

a <- c(1,2,3,4,5,6,1,2,3,4,5,6)
b <- c("loss", "draw", "win", "draw", "loss", "win", "loss", "draw", "win", "draw", "loss", "win")
c <- c(2,3,5,4,4,5,4,4,3,5,2,4)
d <- c(rep("x", 6), rep("y", 6))
temp <- data.frame(a,b,c,d)

What I want is to create a dot plot with b on the x-axis, c on the y-axis, with the points on the x-axis grouped by d, and lines between them grouped by a. If we start by just putting the points on the graph like so, it comes out fine:

ggplot(temp, aes(x=b, y=c, fill=d, colour=d))+
  geom_point(position=position_jitterdodge())

This is the dot plot I get, which is how I want it to look. The points are colour-coded according to factor d, and moreover they're jitterdodged to one side so that x is on the left and y is on the right.

Now, all I want is to connect the points with lines according to factor a. This is a mocked-up version I made in MS Paint of how it should look. Adding a geom_line and setting the geom_line group to a should work...

ggplot(temp, aes(x=b, y=c, fill=d, colour=d))+
  geom_point(position=position_jitterdodge())+
  geom_line(aes(group=a),position=position_jitterdodge())

...but it doesn't come out right. The lines it creates are the right length to connect the correct points, but they barely even touch them, it looks like they're on the graph at random. I would add another screenshot, but don't have the privileges yet.

Moreover, if I change the group aesthetic to be in the overall aesthetic like so:

ggplot(temp, aes(x=b, y=c, fill=d, colour=d, aes(group=a)))+
  geom_point(position=position_jitterdodge())+
  geom_line(position=position_jitterdodge())

...then the points are switched around so that they're in the wrong position. And in any case, the lines still don't join up with the points fully.

I have also tried specifying width and jitter.width values in the position_jitterdodge() part, and the lines and points still don't join up properly. I have also read through the ggplot2 documentation, several previous stackoverflow questions, and tried out most combinations of position_jitter, position_dodge, geom_jitter, etc., but no luck so far.

Any help would be greatly appreciated.

tjebo
  • 21,977
  • 7
  • 58
  • 94
GFL
  • 75
  • 7

2 Answers2

3

You can use the interaction between d and b:

p <- ggplot(temp, aes(x=interaction(d, b), y=c, fill=d, colour=d))+ theme_classic()+
    geom_point()
p + geom_line(aes(group=a),colour=1)

with correct x axis. Convert the x to numeric and set new labels

p <- ggplot(temp, aes(x=as.numeric(interaction(d,b)), y=c, fill=d, colour=d))+ theme_classic()+
     geom_point()
p <- p + geom_line(aes(group=a),colour=1)
p +  scale_x_continuous(breaks = c(1.5,3.5,5.5), labels = levels(temp$b))

enter image description here

Roman
  • 17,008
  • 3
  • 36
  • 49
  • Hi Jimbou, this is a great answer, thanks a lot! One small amendment to your code was needed to make it work for me - changing d1$b to temp$b in the last line to get the labels on the x-axis: `p + scale_x_continuous(breaks = c(1.5,3.5,5.5), labels = levels(temp$b)) ` – GFL May 04 '16 at 09:12
  • 1
    @GFL fixed that. Thanks. – Roman May 04 '16 at 09:52
1

One possible solution - specifying jitter values manualy:

library(ggplot2)

a <- c(1,2,3,4,5,6,1,2,3,4,5,6)
# b <- c("loss", "draw", "win", "draw", "loss", "win", "loss", "draw", "win", "draw", "loss", "win")
b <- c(2, 1, 3, 1, 2, 3, 2, 1, 3, 1, 2, 3)
c <- c(2, 3, 5, 4, 4, 5, 4, 4, 3, 5, 2, 4)
d <- c(rep("x", 6), rep("y", 6))
temp <- data.frame(a,b,c,d)

set.seed(2016)
jitterVal <- runif(12, max = 0.25)
jitterVal <- jitterVal * ifelse(temp$d == "x", -1, +1)

ggplot(temp, aes(x = b + jitterVal, y = c, fill = d, colour = d)) +
  geom_point() +
  geom_line(aes(group = a)) +
  scale_x_continuous(breaks = c(1, 2, 3), labels = c("draw", "loss", "win")) +
  xlab(NULL) +
  expand_limits(x = c(0.5, 3.5))
m-dz
  • 2,342
  • 17
  • 29
  • Thanks, this works perfectly. It's not ideal to do this each time, but it's definitely better than having the points and lines all over the place. – GFL May 04 '16 at 19:00
  • 1
    You can wrap this into a function, simple `jitterVal <- runif(nrow(temp), max = 0.25)` plus breaks and lables for `scale_x_continuous` should be enough to have it working automatically. – m-dz May 04 '16 at 19:05