Conditionally change panel background with facet_grid?
The general rule for doing anything in ggplot2 is to,
- Create a data frame that encodes the information you want to plot
- 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)
#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)
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")
)
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 . 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)
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")
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:
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")
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.
You can set the fill colors using
scale_fill_manual
and e.g. a named vector of colors.There are two options for the grid lines. You can simply add the grid lines manually using
geom_h/vline
. Or you could set thefill
for the plot and panel background toNA
and make use ofpanel.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)
# 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()
)
Related Topics
Incomplete Final Line' Warning When Trying to Read a .Csv File into R
Reshaping Wide to Long With Multiple Values Columns
Pasting Two Vectors With Combinations of All Vectors' Elements
How to Use Grep()/Gsub() to Find Exact Match
Lapply VS For Loop - Performance R
Compute Mean and Standard Deviation by Group For Multiple Variables in a Data.Frame
Select Subset of Columns in Data.Table R
Convert Type of Multiple Columns of a Dataframe At Once
Addressing X and Y in Aes by Variable Number
How to Insert Elements into a Vector
Define and Apply Custom Bins on a Dataframe