David Z
David Z

Reputation: 7051

How to color facet_grid by group in ggplot2?

Here is an example:

library(ggplot2)
set.seed(123)
df<-data.frame(sid=letters[1:8], 
               groups=rep(1:4, each=2), 
               blp=abs(rnorm(8, 120, 5)),
               bmi=abs(rnorm(8, 25, 5)),
               gender=rep(c("F", "M"), each=4))

ggplot(df, aes(bmi, blp))+
    geom_point(size=2)+
facet_grid(sid~groups)

What I wanted is to color the sid by their gender. A desired figure would be: enter image description here

Upvotes: 3

Views: 6442

Answers (3)

Roman
Roman

Reputation: 4999

Data

library(ggplot2)
    set.seed(123)
    df<-data.frame(sid=letters[1:8], 
                   groups=rep(1:4, each=2), 
                   blp=abs(rnorm(8, 120, 5)),
                   bmi=abs(rnorm(8, 25, 5)),
                   gender=rep(c("F", "M"), each=4))

Method 1

ggplot(df, aes(bmi, blp, color = gender))+
    geom_point(size=2)+
    facet_grid(sid~groups)

enter image description here

edit: Method 2 after clarification in the comments

ggplot(df, aes(bmi, blp, color = gender))+
    geom_point(size=2)+
facet_grid(sid~groups)+
    geom_rect(data=subset(df, gender == "F"), 
              aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf), 
              fill="red", alpha=0.2)+
    geom_rect(data=subset(df, gender == "M"), 
              aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf), 
              fill="blue", alpha=0.2)

An even simpler solution is + geom_rect(aes(xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf, fill = gender), alpha=0.2) instead of the two geom_rect()s.

enter image description here

Caveat: As others pointed out, there are ways to do your style of plot, but those methods are quite messy. Above solution is easy and clean, but can obviously only fill facets which contain data.

Upvotes: 5

Anonymous coward
Anonymous coward

Reputation: 2091

Unfortunately, this is something that needs to be done with a workaround. It's not super difficult though, but you need to manually set colors.

library(ggplot2)
library(grid)
set.seed(123)
df<-data.frame(sid=letters[1:8], 
               groups=rep(1:4, each=2), 
               blp=abs(rnorm(8, 120, 5)),
               bmi=abs(rnorm(8, 25, 5)),
               gender=rep(c("F", "M"), each=4))

p <- ggplot(df, aes(bmi, blp))+
  geom_point(size=2)+
  facet_grid(sid~groups)
g <- ggplot_gtable(ggplot_build(p))
strip_right <- which(grepl('strip-r', g$layout$name))
fills <- c("blue","blue","blue","blue","red","red","red","red")
k <- 1
for (i in strip_right) {
  j <- which(grepl('rect', g$grobs[[i]]$grobs[[1]]$childrenOrder))
  g$grobs[[i]]$grobs[[1]]$children[[j]]$gp$fill <- fills[k]
  k <- k+1
}
grid.draw(g)

Upvotes: 1

Z.Lin
Z.Lin

Reputation: 29125

You can convert the ggplot to a grob, & make the changes there:

# convert to grob
gp <- ggplotGrob(p) # where p is the original ggplot object

# assign the first 4 right-side facet strips with blue fill
for(i in 1:4){
  grob.i <- grep("strip-r", gp$layout$name)[i]
  gp$grobs[[grob.i]]$grobs[[1]]$children[[1]]$gp$fill <- "blue"
}
# assign the next 4 right-side facet strips with red fill
for(i in 5:8){
  grob.i <- grep("strip-r", gp$layout$name)[i]
  gp$grobs[[grob.i]]$grobs[[1]]$children[[1]]$gp$fill <- "red"
}

grid::grid.draw(gp)

plot

Upvotes: 3

Related Questions