Reputation: 55420
There is now a great package, ggh4x
by @teunbrand
See this answer to the related the question
Can there be more than one color for facet backgrounds?
I am using facet_grid
(not facet_wrap
) with multiple layers.
## Sample data
dat <- mtcars
## Add in some colors based on the data
dat$facet_fill_color <- c("red", "green", "blue", "yellow", "orange")[dat$gear]
## Create main plot
library(ggplot2)
P <-
ggplot(dat, aes(x = cyl, y = wt)) +
geom_point(aes(fill = hp)) +
facet_grid(gear + carb ~ .)
The background of ALL of the strips can be changed using:
P + theme(strip.background = element_rect(fill="red"))
However, I would like to change the color differently for different groups.
Something like the following (which of course does not work)
P + theme(strip.background = element_rect(fill=dat$facet_fill_color))
P + theme(strip.background = element_rect(aes(fill=facet_fill_color)))
related, but not an actual answer to this current question ggplot2: facet_wrap strip color based on variable in data set)
Upvotes: 12
Views: 14061
Reputation: 96
There's a very nice and simple answer that is buried in the similar question ggplot2: facet_wrap strip color based on variable in data set that avoids the hacks, although you still have to manually specify the colors you want in strip_themed().
library(ggh4x)
#> Loading required package: ggplot2
# Only colour strips in x-direction
strip <- strip_themed(background_x = elem_list_rect(fill = rainbow(7)))
# Wrap variant
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
facet_wrap2(~ class, strip = strip)
Upvotes: 3
Reputation: 77124
Alternative search-and-replace strategy inspired by @SimonO'Hanlon's solution,
strips <- grep(pattern="strip-right", Pg$layout$name)
refill <- function(strip, colour){
strip[["children"]][[1]][["gp"]][["fill"]] <- colour
strip
}
cols <- rep_len(rep.int(c("blue", "green", "red"), c(4,3,4)), length(strips))
Pg$grobs[strips] <- mapply(refill,
strip = Pg$grobs[strips],
colour = cols,
SIMPLIFY = FALSE)
grid.newpage()
grid.draw(Pg)
Upvotes: 4
Reputation: 60000
This feels like a horrible hacky thing to do (to the extent that I am almost embarrassed to post this as an answer), but it is possible...
require(ggplot2);require(grid)
# Facet strip colours
cols <- rep( c("red", "green", "blue", "yellow", "orange")[rep( c(4,3,5),times=c(4,3,4))] , 2 )
# Make a grob object
Pg <- ggplotGrob(P)
# To keep track of strip.background grobs
idx <- 0
# Find each strip.background and alter its backround colour...
for( g in 1:length(Pg$grobs) ){
if( grepl( "strip.absoluteGrob" , Pg$grobs[[g]]$name ) ){
idx <- idx + 1
sb <- which( grepl( "strip\\.background" , names( Pg$grobs[[g]]$children ) ) )
Pg$grobs[[g]]$children[[sb]][]$gp$fill <- cols[idx]
}
}
# Plot
grid.newpage()
grid.draw(Pg)
Upvotes: 4
Reputation: 77124
For what it's worth, it's pretty straight-forward to adapt that previous gtable hack.
## Sample data
require(ggplot2)
dat <- mtcars
## Add in some colors based on the data
dat$facet_fill_color <- c("red", "green", "blue", "yellow", "orange")[dat$gear]
## Create main plot
p <- ggplot(dat, aes(x=cyl, y=wt)) +
geom_point(aes(fill=hp)) + facet_grid(gear+carb ~ .) +
theme(strip.background=element_blank())
dummy <- p
dummy$layers <- NULL
dummy <- dummy + geom_rect(data=dat, xmin=-Inf, ymin=-Inf, xmax=Inf, ymax=Inf,
aes(fill = facet_fill_color))
library(gtable)
g1 <- ggplotGrob(p)
g2 <- ggplotGrob(dummy)
gtable_select <- function (x, ...)
{
matches <- c(...)
x$layout <- x$layout[matches, , drop = FALSE]
x$grobs <- x$grobs[matches]
x
}
panels <- grepl(pattern="panel", g2$layout$name)
strips <- grepl(pattern="strip-right", g2$layout$name)
g2$grobs[strips] <- replicate(sum(strips), nullGrob(), simplify = FALSE)
g2$layout$l[panels] <- g2$layout$l[panels] + 1
g2$layout$r[panels] <- g2$layout$r[panels] + 2
new_strips <- gtable_select(g2, panels | strips)
grid.newpage()
grid.draw(new_strips)
gtable_stack <- function(g1, g2){
g1$grobs <- c(g1$grobs, g2$grobs)
g1$layout <- rbind(g1$layout, g2$layout)
g1
}
## ideally you'd remove the old strips, for now they're just covered
new_plot <- gtable_stack(g1, new_strips)
grid.newpage()
grid.draw(new_plot)
Upvotes: 14