2

I have yet another question about ggplot2... but this time I am not even sure what I want to do would be possible... Let's start with a simple example; this is what I have so far:

library(reshape2)
library(ggplot2)

a.df <- data.frame(
  id=c('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y'),
  var1=c(25,35,46,19,35,68,78,23,65,78,98,32,65,74,24,56,78,12,34,76,87,12,54,87,34), 
  group1=c(1,2,'NONE','NONE',1,2,2,1,3,4,3,'NONE','NONE',4,4,3,1,1,2,3,4,'NONE','NONE',2,3), 
  group2=c(1,'NONE',1,1,2,2,'NONE',2,'NONE',2,3,4,3,4,1,'NONE',1,3,4,'NONE',4,4,3,'NONE',2)
)

ggplot(data=subset(a.df,group1!='NONE'), aes(x=var1)) + 
  geom_density() +
  facet_grid(. ~ group1)
ggplot(data=subset(a.df,group1=='NONE'), aes(x=var1)) + 
  geom_density()

ggplot(data=subset(a.df,group2!='NONE'), aes(x=var1)) + 
  geom_density() +
  facet_grid(. ~ group2)
ggplot(data=subset(a.df,group2=='NONE'), aes(x=var1)) + 
  geom_density()

So what I would like to do here are the following:

1-First, just divide the facets in 2x2, instead of 4x1 (I have tried with ncol=2, but did not work)

2-Plot the 2nd plot (subset(a.df,group1=='NONE')) along with each of the 4 facets of the 1st plot. Do the same for 3rd and 4th.

3-If possible, what would be great would be to have the 2 resulting plots (1st+2nd in 4 facets, and 3rd+4th in 4 facets as well) in one, but the problem I see here is that the facets depend on 2 grouping variables... would it be possible??

So all in all, I feel the input data.frame needs some remodeling, but I have no idea how to... Many thanks!!

DaniCee
  • 2,397
  • 6
  • 36
  • 59

2 Answers2

2

Adding a single density curve to each facet is fairly straightforward following this post here. I think is this what you want to do, but I could be wrong. Notice that facet_wrap allows you to chose the number of columns, not facet_grid.

ggplot(data=subset(a.df,group1!='NONE'), aes(x=var1)) + 
    geom_density() +
    facet_wrap( ~ group1, ncol = 2) +
    geom_density(data=subset(a.df,group1=='NONE', var1), aes(var1, color = "NONE")) +
    scale_color_manual(name = "Baseline", values = "blue")

It seemed fairly straightforward to do the same kind of thing for both groups after melting the dataset into a long format, but it only worked with facet_grid and so the number of columns couldn't be controlled.

require(reshape2)
dat2 = melt(a.df, measure.vars = c("group1", "group2"), variable.name = "group")

ggplot(data=subset(dat2, value != "NONE"), aes(x=var1)) +
    geom_density() + facet_grid(group ~ value) +
    geom_density(data=subset(dat2,value=='NONE', c(var1, group)), aes(var1), color = "blue")

I had to use more of a "brute-force" method to make this work with facet_wrap. Essentially I had to create a sort of dummy dataset with the values of var1 from the NONE category repeated for levels 1-4 for each group. See the output of datnone for a better explanation. Hopefully someone else will have a nicer way to go about this, as this may get the job done but it's certainly not pretty.

datnone = cbind(dat2[dat2$value == "NONE", 2:3], 
             value = rep(1:4, each = nrow(dat2[dat2$value == "NONE",])) )

ggplot(data=subset(dat2, value != "NONE"), aes(x=var1)) +
    geom_density() + facet_wrap(group ~ value, ncol = 2) +
    geom_density(data = datnone, aes(var1), color = "blue")

Edit to add legends with two lines, two colors

Here is one way to add a legend and control both linetype and color. You can control the names and labels of the legend, as well, to make this nicer.

ggplot(data=subset(a.df,group1!='NONE'), aes(x=var1, color = "GROUP", linetype = "GROUP")) + 
    geom_density() +
    facet_wrap( ~ group1, ncol = 2) +
    geom_density(data=subset(a.df,group1=='NONE', var1), 
               aes(var1, color = "NONE", linetype = "NONE")) +
    scale_linetype_manual(values = c("solid", "dotted") ) +
    scale_color_manual(values = c("black", "red") )
Community
  • 1
  • 1
aosmith
  • 34,856
  • 9
  • 84
  • 118
  • That's better. I was thinking 'along with' was 'alongside'. Last call to `ggplot` can't find `dat4`, could you edit to include... – dardisco Oct 04 '13 at 23:33
  • Whoops, that was a bad copy and paste job. I can't quite picture exactly what you mean by along side. But it looks like @dardisco might have what you are looking for. – aosmith Oct 04 '13 at 23:52
  • Many thanks! I think I am going to keep the 2 groups separated, so your first solution just overlaying the !='NONE' line is what I'm going to apply. Thanks again! Just one little thing: How would I add a legend to the plot (your first solution) manually? – DaniCee Oct 07 '13 at 13:35
  • [This link](http://stackoverflow.com/questions/18060116/adding-legend-to-ggplot-when-lines-were-added-manually) walks you through adding a legend in a case like yours. Edited first example above to show how you could do this. – aosmith Oct 07 '13 at 15:29
  • Thanks, everything works perfectly except for one silly thing... I want the 2 lines in the legend (which I can do), and the second one dotted (which I can do too), but then the legend has the 2 squares dotted, instead of just the first... – DaniCee Oct 07 '13 at 16:13
  • Did you add `linetype` into both `aes` and then use `scale_linetype_manual` to set the values as c("solid", "dotted")? That works for me (I get two lines of two different types). – aosmith Oct 07 '13 at 16:41
  • but if I specify values=c(solid, dotted) I cannot specify values=c(black, red), can I? And if I specify lty inside aes I get: Error: A continuous variable can not be mapped to linetype – DaniCee Oct 07 '13 at 16:46
  • I added an edit for one way to do this. I'm not sure what code you were trying so it might not solve your problem. If you continue to have legend problems after doing some internet searches you might consider asking a new question. – aosmith Oct 07 '13 at 16:55
1

Here's an approach which avoids faceting and simply saves each individual plot in a list, followed by a call to grid.arrange to get the desired result.

Having multiple copies of the same plot doesn't readily lead itself to facet_grid. Also, facet_grid is not really designed for 2x2 plots where there is only one facet-ing variable.

### no. levels of factor group1 not equal to 'NONE' = 4
sum(!levels(a.df$group1)=="NONE")
### define list to store results
list1 <- vector("list", 8)
### subset to remove "none"
df1 <- a.df[!a.df$group1=="NONE", ]
for (i in 1:4){
### subset per level
    df2 <- df1[df1$group1==unique(df1$group1)[i], ]
### plot and title
    g1 <- ggplot(df2, aes(x=var1)) + 
        geom_density() +
            ggtitle(unique(df1$group1)[i])
        list1[[2*i-1]] <- g1
}
### plots of NONE
df1 <- a.df[a.df$group1=="NONE", ] 
g2 <- ggplot(df1, aes(x=var1)) +
    geom_density() +
    ggtitle("NONE")
list1[[2]] <- list1[[4]] <- list1[[6]] <- list1[[8]] <- g2
### 
library(gridExtra)
do.call(grid.arrange, c(list1, list(nrow=2, ncol=4)))

giving

enter image description here

You should be able to tweak this and do the same for the additional plots of interest.

dardisco
  • 5,086
  • 2
  • 39
  • 54