Conditionally Change Panel Background With Facet_Grid

Conditionally change panel background with facet_grid?

The general rule for doing anything in ggplot2 is to,

  1. Create a data frame that encodes the information you want to plot
  2. Pass that data frame to a geom

This is made a bit more complicated in this case because of the particular aspect of the plot you want to alter. The Powers That Be designed ggplot2 in a way that separates data elements of the plot (i.e. geom's) from non-data elements (i.e. theme's), and it so happens that the plot background falls under the "non-data" category.

There is always the option of modifying the underlying grid object manually but this is tedious and the details may change with different versions of ggplot2. Instead, we'll employ the "hack" that Hadley refers to in this question.

#Create a data frame with the faceting variables
# and some dummy data (that will be overwritten)
tp <- unique(tips[,c('sex','day')])
tp$total_bill <- tp$tip <- 1

#Just Fri
ggplot(tips,aes(x=total_bill, y = tip/total_bill)) +
geom_rect(data = subset(tp,day == 'Fri'),aes(fill = day),xmin = -Inf,xmax = Inf,
ymin = -Inf,ymax = Inf,alpha = 0.3) +
geom_point(shape=1) +
facet_grid(sex ~ day)

Sample Image

#Each panel
ggplot(tips,aes(x=total_bill, y = tip/total_bill)) +
geom_rect(data = tp,aes(fill = day),xmin = -Inf,xmax = Inf,
ymin = -Inf,ymax = Inf,alpha = 0.3) +
geom_point(shape=1) +
facet_grid(sex ~ day)

Sample Image

Change panel background color of specific ggplot facets

Perhaps you prefer a solution like this, no grob manipulation necessary:

ggplot(test) +
geom_rect(
aes(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf),
data.frame(rows = 'C', cols = 'A'),
fill = 'red', alpha = 0.5
) +
geom_point(aes(x = x, y = y)) +
facet_grid(vars(rows), vars(cols)) +
theme_minimal() +
theme(
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.background = element_rect(fill = NA, color = "grey60")
)

Sample Image

A downside is that the color is drawn on top of the grid lines. Some transparency as used above is usually a good solution. Alternatively, you can use theme(panel.ontop = TRUE) to draw the grid lines on top, but then they will also be plotted on top of the data.

Conditional formatting of panel background in GGplot2

This is not exactly a solution, but a work-around. But it seems to have come out good. Both the posts you linked to had each part of the solution. James' solution here tells you how to extract the fitted values from stat_smooth. Joran's solution here tells how to use geom_rect to fill the background.

# generating data: Usage of set.seed for reproducibility 
# also I changed the multiplication constant to 0.1 to have
# at least one negative slope.

require(ggplot2)
set.seed(12)
x <- rnorm(100)
y <- + .1*x + rnorm(100)
f1 <- as.factor(c(rep("A",50),rep("B",50)))
f2 <- as.factor(rep(c(rep("C",25),rep("D",25)),2))
df <- data.frame(cbind(x,y))
df$f1 <- f1
df$f2 <- f2

# first generate your plot in this manner and run it
# from James' post, the part outfit=fit<<-..y.. will store
# the output of fitted values in "fit"

g <- ggplot(df,aes(x=x,y=y)) + geom_point()+facet_grid(f1~f2)
g <- g + stat_smooth(aes(outfit=fit<<-..y..), method="lm",se=FALSE)
# now run g to generate "fit"
g

# now extract the slope for each facet and
# construct the data.frame for geom_rect (as per Joran's post)
# Edit: Just to add more info about "fit". By default it contains
# 80 values per facet. Hence the 80*4 = 320

slopes <- fit[seq(2, 320, by = 80)] - fit[seq(1, 320, by = 80)]
tp <- unique(df[, c('f1', 'f2')])
tp <- transform(tp, slopes=slopes, x=1, y=1)
tp$pos_neg <- ifelse(slopes > 0, 1, 0)
tp$pos_neg <- factor(tp$pos_neg)

# now plot again (but with geom_rect)
g <- ggplot(df,aes(x=x,y=y))
g <- g + geom_rect(data = tp, aes(fill = pos_neg), xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, alpha = 0.5)
g <- g + geom_point() + facet_grid(f1~f2) + stat_smooth(method = "lm",se = FALSE)
g

The output looks like this. I'm not sure if this is what you expect though.. Strictly speaking, you do calculate the fitted values twice, but both times you calculate it implicitly with stat_smooth. Like I said, its just a work-around.

Conditionally change background colour facet_grid with pie charts

You are not able to do this in R, especially when using polar coordinates, from what I have read.

I was trying this exact thing for a pie graph similar to the one you describe. The issue is what @MKBakker points out. Backgrounds are a non-data element and the solution from the link you posted won't work because you have polar coordinate and there is no way to plot your data in the corners to cover the background color.

I ended up just manually highlighting the facets after adding my plot to my document.

How to simulate passing an aesthetic to panel background in ggplot2?

pies <- data_frame(pie = c(rep("hawaiian", 3), rep("pepperoni", 2)), 
fraction = c(c(0.3, 0.2, 0.5), c(0.4, 0.6)),
ingredient = c("cheese", "pineapple", "ham",
"peperroni", "cheese"),
deepdish = c(rep(TRUE, 3), rep(FALSE, 2)))
library(ggplot2)
library(dplyr)
p <- pies %>%
ggplot() +
geom_bar(aes(x = factor(1), y = fraction, fill = ingredient),
width = 0.6, stat = "identity", position = "fill") +
facet_wrap(~ pie) + coord_polar(theta = "y")

g <- ggplotGrob(p)
# Set manually the background color for each panel
g$grobs[[2]]$children[[1]]$children[[1]]$gp$fill <- "#88334466"
g$grobs[[3]]$children[[1]]$children[[1]]$gp$fill <- "#44338866"

library(grid)
grid.draw(g)

Sample Image

Conditionally change ggplot facet background with date axis

The cause of your error message was that you tried to map an aesthetic to a column that doesn't exist in your data, in this line:

geom_rect(data = facetcond, aes(fill = "red"), 

You are not mapping an aesthetic, but telling ggplot to fill the rectangle with red. The line should be:

geom_rect(data = facetcond, fill = "red", 

Also, you will also save yourself some trouble by converting the original data frame dates to as.Date() prior to plotting. Note that I use colClasses to convert the data directly into the class I want, including "Date".

Here is the complete working solution.

library(ggplot2)

dat = read.table(text = "2014-01-25 1 A
2014-02-05 1 A
2014-09-01 1 A
2014-08-26 2 B
2014-12-12 2 C",
col.names = c("Date", "Vehicle", "Problem"),
colClasses = c("Date", "integer", "factor"))

facetcond = data.frame("Vehicle" = 2, "Problem" = "B")

ggplot(dat) +
theme_bw() +
geom_rect(data = facetcond, fill = "red",
xmin = -Inf, # I've also tried Inf and
xmax = Inf, # -Inf here
ymin = -Inf,
ymax = Inf, alpha = 0.3) +
geom_bar(aes(x = Date, fill = Vehicle), binwidth = 14) +
scale_x_date() +
facet_grid(Problem~Vehicle, margins = "Problem")

Sample Image

How to set background color for each plot in a facet grid using numeric values

So, with your help I found a solution. First, the dat_text$R2 column has to be numeric of cause. Adding the % sign converts it to character which is interpreted as discrete scale.

dat_text <- tibble(
name1 = rep(names(df), each = length(names(df))),
name2 = rep(names(df), length(names(df))),
R2 = round(as.vector(CM) * 100, 1)
)

The percent sign can be added within the geom_text call. Then, the scale_fill_gradient call works quiet fine. I cannot find to fix the scale from 0% to 100% but in the end this is probably better. Otherwise, there would be almost no difference between the background colors.

p <- ggplot()
p <- p + geom_point(data=FACET, aes(a1, a2), size = 0.5)
p <- p + stat_smooth(data=FACET, aes(a1, a2), method = "lm")
p <- p + facet_grid(vars(name1), vars(name2)) + coord_fixed()
p <- p + geom_rect(data = dat_text, aes(fill = R2), xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, alpha = 0.3)
p <- p + geom_text(data = dat_text, aes(x = 0.3, y = 1.2, label = paste0(R2,"%")))
p <- p + scale_fill_gradient(low = "black", high = "darkgreen", aesthetics = "fill")
p

This is how my final chart looks like:
Maybe I will use stronger colors

Conditionally change ggplot facet background with date axis

The cause of your error message was that you tried to map an aesthetic to a column that doesn't exist in your data, in this line:

geom_rect(data = facetcond, aes(fill = "red"), 

You are not mapping an aesthetic, but telling ggplot to fill the rectangle with red. The line should be:

geom_rect(data = facetcond, fill = "red", 

Also, you will also save yourself some trouble by converting the original data frame dates to as.Date() prior to plotting. Note that I use colClasses to convert the data directly into the class I want, including "Date".

Here is the complete working solution.

library(ggplot2)

dat = read.table(text = "2014-01-25 1 A
2014-02-05 1 A
2014-09-01 1 A
2014-08-26 2 B
2014-12-12 2 C",
col.names = c("Date", "Vehicle", "Problem"),
colClasses = c("Date", "integer", "factor"))

facetcond = data.frame("Vehicle" = 2, "Problem" = "B")

ggplot(dat) +
theme_bw() +
geom_rect(data = facetcond, fill = "red",
xmin = -Inf, # I've also tried Inf and
xmax = Inf, # -Inf here
ymin = -Inf,
ymax = Inf, alpha = 0.3) +
geom_bar(aes(x = Date, fill = Vehicle), binwidth = 14) +
scale_x_date() +
facet_grid(Problem~Vehicle, margins = "Problem")

Sample Image

Panel background color by column in plot matrix, ggplot2

Actually I got the same colors as you. The reason is that your elevation is an ordered factor. Therefore ggplot2 by default makes use of the viridis color palette.

  1. You can set the fill colors using scale_fill_manual and e.g. a named vector of colors.

  2. There are two options for the grid lines. You can simply add the grid lines manually using geom_h/vline. Or you could set the fill for the plot and panel background to NA and make use of panel.ontop which will plot the panel and the grid lines on top of the plot.

library(ggplot2)

cols <- rev(scales::hue_pal()(5))
cols <- setNames(cols, levels(climate$elevation))
cols
#> Alpine Montane Steppe Valley Coast
#> "#E76BF3" "#00B0F6" "#00BF7D" "#A3A500" "#F8766D"

base <- ggplot(data = climate, aes(hour, temperature)) +
geom_rect(aes(fill = elevation), xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf) +
scale_fill_manual(values = cols) +
geom_line(color = "steelblue", size = 1) +
geom_point(color = "steelblue") +
labs(
title = "Elevation by Region & Time of Day",
subtitle = "(Temperature)",
y = "Mean Temperature", x = "Hour of Day"
) +
facet_grid(region ~ elevation)

breaks_x <- seq(2.5, 10, 2.5)
breaks_y <- seq(10, 40, 10)

base +
geom_vline(xintercept = breaks_x, color = "white", size = 0.5) +
geom_hline(yintercept = breaks_y, color = "white", size = 0.5) +
scale_x_continuous(breaks = breaks_x) +
scale_y_continuous(breaks = breaks_y)

Sample Image

# Trying to add gridlines (does not work)
base + theme(
panel.background = element_rect(fill = NA, colour = NA),
plot.background = element_rect(fill = NA, colour = NA),
panel.grid.major = element_line(
size = 0.5, linetype = "solid",
colour = "white"
),
panel.ontop = TRUE,
panel.grid.minor = element_blank()
)

Sample Image



Related Topics



Leave a reply



Submit