Reputation: 454
I am drawing a chart using ggplot2 in R. I want to colour the panel background using one colour, and a rectangle within the panel using a different colour. I want the grid lines to overlay both the panel and the rectangle.
If I do not colour the panel background, I have a good solution thanks to AF7 and zx8754 here. But if I try to colour the panel background as well, it does not work.
Here is a reprex :
library(ggplot2)
t <- c(1,2,3)
a <- c(5,4,1)
b <- c(3,2,4)
df <- data.frame(t,a,b)
ggplot(df) +
geom_rect(xmin=2,xmax=3,ymin=-Inf,ymax=Inf,fill="gray") +
# The code works fine without this next line, but the panel colour is the default (white)
# I want the background colour to be lightblue except for the rectangle
theme(panel.background = element_rect(fill = "lightblue")) +
# Changing NA to "lightblue" in the line below does not work either
theme(panel.background = element_rect(fill = NA),panel.ontop = TRUE) +
theme(panel.grid.minor=element_line(colour="hotpink",size=0.5)) +
theme(panel.grid.major=element_line(colour="green",size=0.5)) +
geom_line(aes(x=t,y=a),colour="red") +
geom_line(aes(x=t,y=b),colour="blue")
Upvotes: 2
Views: 752
Reputation: 29085
In ggplot, the panel background & grid layers are contained within the same grob. So either both stay below the geom layers (default panel.ontop = FALSE
) or both go over them (panel.ontop = TRUE
). Here are two possible workarounds for consideration:
panel.ontop = TRUE
, keep panel background transparent, and colour the entire plot background with your desired colour instead:ggplot(df) +
geom_rect(xmin=2,xmax=3,ymin=-Inf,ymax=Inf,fill="gray") +
geom_line(aes(x=t,y=a),colour="red") +
geom_line(aes(x=t,y=b),colour="blue")+
theme(plot.background = element_rect(fill = "lightblue"), # change this line to plot.background
panel.background = element_rect(fill = NA),
panel.ontop = TRUE,
panel.grid.minor=element_line(colour="hotpink",size=0.5),
panel.grid.major=element_line(colour="green",size=0.5))
panel.ontop = FALSE
, then hack the underlying grobs to move the grid lines to the top:p <- ggplot(df) +
geom_rect(xmin=2,xmax=3,ymin=-Inf,ymax=Inf,fill="gray") +
geom_line(aes(x=t,y=a),colour="red") +
geom_line(aes(x=t,y=b),colour="blue")+
theme(panel.background = element_rect(fill = "lightblue"),
panel.grid.minor=element_line(colour="hotpink",size=0.5),
panel.grid.major=element_line(colour="green",size=0.5))
# convert from ggplot object to grob object
gp <- ggplotGrob(p)
# make a copy of the grob that contains the panel background (first child) & panel grids (all subsequent children),
# then drop the panel background grob (i.e. only keep the grobs for grids)
panel.grid.grob <- gp$grobs[[6]]$children[[1]]
panel.grid.grob$children[[1]] <- zeroGrob()
# leave only the panel background grob in its original slot
gp$grobs[[6]]$children[[1]] <- gp$grobs[[6]]$children[[1]]$children[[1]]
# add back grid grobs on top of panel
gp <- gtable::gtable_add_grob(gp, panel.grid.grob, t = 7, l = 5)
# plot result
grid::grid.draw(gp)
The first approach is simpler to implement, but the panel background colour would 'spill out' over the entire plot, including the axes labels. You may find one or the other more useful, depending on your use case.
Upvotes: 4