How to pass data and aesthetics across ggplot2 functions - r

I have to create a figure with ggplot2 that has roughly this structure:
p <- ggplot() +
geom_rect(data = regions,aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf),
fill = "yellow",alpha = 0.1) +
geom_line(data = data, aes(x=dt, y = y, color = case)) +
geom_point(data = data, aes(x=dt, y = y, color = case)) +
facet_grid(groups ~ ., scale="free_y")
geom_vline(x=as.numeric(dates_start), color = "orange3",linetype="dashed") +
geom_vline(x=as.numeric(dates_end), color = "orange3",linetype="dashed")
p
Is there anyway I can avoid having to pass all the details in geom_point? since they are the same as the one used in geom_line?

Related

extend ggplot `geom_ribbon()` in the x direction

library(tidyverse)
mQ <- quantile(mtcars$wt, c(0.025, 0.975))
mtcarsQ <- data.frame(x = c(min(as.numeric(diamonds$cut)),
max(as.numeric(diamonds$cut))),
ymin = rep(mQ[1], 2),
ymax = rep(mQ[2], 2))
ggplot() +
geom_blank(data = diamonds, aes(x = cut, y = y)) +
geom_ribbon(data = mtcarsQ, aes(x = x, ymin = ymin, ymax = ymax), alpha=0.2) +
geom_boxplot(data = diamonds, aes(x = cut, y = y, fill = cut, group = cut)) +
coord_cartesian(ylim = c(0, 12)) +
theme_bw()
I'd like to extend my geom_ribbon() from code chunk above in either direction on the x-axis. Something resembling the image below. My preferred geom_ribbon() would fully entend into the blue dotted line box.
How do I do this?
You could subtract/add 0.5 from mtcarsQ$x
mtcarsQ <- data.frame(x = c(min(as.numeric(diamonds$cut)) - 0.5,
max(as.numeric(diamonds$cut)) + 0.5),
ymin = rep(mQ[1], 2),
ymax = rep(mQ[2], 2))
ggplot() +
geom_blank(data = diamonds, aes(x = cut, y = y)) +
geom_ribbon(data = mtcarsQ, aes(x = x, ymin = ymin, ymax = ymax), alpha=0.2) +
geom_boxplot(data = diamonds, aes(x = cut, y = y, fill = cut, group = cut)) +
coord_cartesian(ylim = c(0, 12)) +
theme_bw()
Update
In response to your comment, here is an example
mtcars %>%
mutate(cyl = factor(cyl)) %>%
ggplot() +
geom_col(aes(cyl, mpg)) +
geom_rect(
data = data.frame(
xmin = min(as.integer(as.factor(mtcars$cyl))) - 0.5,
xmax = max(as.integer(as.factor(mtcars$cyl))) + 0.5,
ymin = 20,
ymax = 120),
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
alpha = 0.2, fill = "green")

geom_rect equivalent of vjust and hjust [duplicate]

I use an example from here. My question is how can I add a specific bounding box to this heatmap, such as add a red line box to the top left four tiles?
require(ggplot2)
require(reshape)
require(scales)
mydf <- data.frame(industry = c('all industries','steel','cars'),
'all regions' = c(250,150,100), americas = c(150,90,60),
europe = c(150,60,40), check.names = FALSE)
mydf
mymelt <- melt(mydf, id.var = c('industry'))
mymelt
ggplot(mymelt, aes(x = industry, y = variable, fill = value)) +
geom_tile() + geom_text(aes(fill = mymelt$value, label = mymelt$value))
A quick and dirty (some hard-coding) possibility is to use geom_rect, where the positions are given by the numerical values of the levels of x and y variables to be bound with a box, plus/minus an offset.
ggplot(mymelt, aes(x = industry, y = variable, fill = value, label = value)) +
geom_tile() +
geom_text() +
geom_rect(aes(xmin = 1 - 0.5, xmax = 2 + 0.5, ymin = 2 - 0.5, ymax = 3 + 0.5),
fill = "transparent", color = "red", size = 1.5)
A less hard-coded version:
# convert x and y variables to factors
ind <- as.factor(mymelt$industry)
vars <- as.factor(mymelt$variable)
# numeric version of the levels to be bound by a box
xmin <- unique(as.numeric(ind[ind == "all industries"]))
xmax <- unique(as.numeric(ind[ind == "cars"]))
ymin <- unique(as.numeric(vars[vars == "americas"]))
ymax <- unique(as.numeric(vars[vars == "europe"]))
# set offset
offset <- 0.5
ggplot(mymelt, aes(x = industry, y = variable, fill = value, label = value)) +
geom_tile() +
geom_text() +
geom_rect(aes(xmin = xmin - offset,
xmax = xmax + offset,
ymin = ymin - offset,
ymax = ymax + offset),
fill = "transparent", color = "red", size = 1.5)

Shade background of a ggplot chart using geom_rect with categorical variables

This is my dataset example:
df <- data.frame(group = rep(c("group1","group2","group3", "group4", "group5", "group6"), each=3),
X = paste(letters[1:18]),
Y = c(1:18))
As you can see, there are three variables, two of them categorical (group and X). I have constructed a line chart using ggplot2 where the X axis is X and Y axis is Y.
I want to shade the background using the group variable, so that 6 different colors must appear.
I tried this code:
ggplot(df, aes(x = X, y = Y)) +
geom_rect(xmin = 0, xmax = 3, ymin = -0.5, ymax = Inf,
fill = 'blue', alpha = 0.05) +
geom_point(size = 2.5)
But geom_rect() only colorize the area between 0 and 3, in the X axis.
I guess I can do it manually by replicating the the geom_rect() so many times as groups I have. But I am sure there must be a more beautiful code using the variable itself. Any idea?
To get shading for the entire graph, geom_rect needs the xmin and xmax locations for all the rectangles, so these need to be provided by mapping xmin and xmax to columns in the data, rather than hard-coding them.
ggplot(df, aes(x = X, y = Y)) +
geom_rect(aes(xmin = X, xmax = dplyr::lead(X), ymin = -0.5, ymax = Inf, fill = group),
alpha = 0.5) +
geom_point(size = 2.5) +
theme_classic()
Here is one way:
df2 <- df %>% mutate(Xn=as.numeric(X))
ggplot(df2) +
geom_rect(aes(xmin=Xn-.5, xmax=Xn+.5, ymin=-Inf, ymax=Inf, fill = group), alpha=0.5, stat="identity") +
geom_point(aes(x = Xn, y = Y), size = 2.5) + scale_x_continuous(breaks=df2$Xn, labels=df2$X)
This will get you close - need to add a couple columns to your data frame. Using dplyr here.
df <- df %>%
group_by(group) %>%
mutate(xmin = sort(X)[1],
xmax = sort(X, decreasing = T)[1])
ggplot(df, aes(x = X, y = Y)) +
geom_point(size = 2.5) +
geom_rect(aes(xmin=xmin, xmax = xmax, fill = group), ymin = -0.5, ymax = Inf,
alpha = 0.05)

alpha not working on facetted line graph with x-varying geom_rect()

I have a data frame in this kind of format:
df <- data.frame(
time = rep(seq(from = as.POSIXct("2016-08-10 11:00:00"),
to = as.POSIXct("2016-08-10 12:00:00"), by="sec"), 2),
value = c(diffinv(rnorm(3601)), diff(rnorm(3601))),
facets = c(rep("A",3601), rep("B", 3601)),
shading = rep(c(rep("x", 1500), rep("y", 750), rep("z", 1351)), 2),
stringsAsFactors = FALSE
)
I can plot the value time series on separate graphs sharing the x-axis using ggplot2's facet_grid function. I also want to include another dimension in my plot - the variable shading to shade the background.
I know I can do this by specifying the ranges of the x-axis the shaded regions will cover:
xRange1 <- range(df$time[df$shading=="x"])
xRange2 <- range(df$time[df$shading=="y"])
xRange3 <- range(df$time[df$shading=="z"])
yRange <- range(df$value)
When I first set this up I include alpha in each of my geom_rect
ggplot(df, aes(x = time, y = value)) +
geom_line() +
facet_grid(facets ~ ., scales = "free_y") +
geom_rect(aes(xmin = xRange1[1], xmax = xRange1[2]),
ymin = yRange[1], ymax = yRange[2],
alpha = 0.3, fill = "#EEF2BF") +
geom_rect(aes(xmin = xRange2[1], xmax = xRange2[2]),
ymin = yRange[1], ymax = yRange[2],
alpha = 0.3, fill = "#A3BAB6",) +
geom_rect(aes(xmin = xRange3[1], xmax = xRange3[2]),
ymin = yRange[1], ymax = yRange[2],
alpha = 0.3, fill = "#BFA67E")
Obviously the alpha didn't work.
One way to get around this is to put geom_line() at the end:
ggplot(df, aes(x = time, y = value)) +
facet_grid(facets ~ ., scales = "free_y") +
geom_rect(aes(xmin = xRange1[1], xmax = xRange1[2]),
ymin = yRange[1], ymax = yRange[2],
alpha = 0.3, fill = "#EEF2BF") +
geom_rect(aes(xmin = xRange2[1], xmax = xRange2[2]),
ymin = yRange[1], ymax = yRange[2],
alpha = 0.3, fill = "#A3BAB6",) +
geom_rect(aes(xmin = xRange3[1], xmax = xRange3[2]),
ymin = yRange[1], ymax = yRange[2],
alpha = 0.3, fill = "#BFA67E") +
geom_line()
But that hides the grid and doesn't solve the underlying problem.
I have looked at several posts and none of them address this directly. I have looked at using other functions in my plot including scale_fill_manual
(last example on page) and scale_alpha
Edit: I suspect the best solution also involves setting up the geom_rect in a less manual way. My actual data frame has more than 3 character values I want to shade with.

ggplot2 - Change `geom_rect` colour in a stacked barplot

I am trying to plot a stacked barplot using ggplot2::geom_bar with backgroud shading (using ggplot2::geom_rect()) according to a categorical variable as follows:
shading <- data.frame(min = seq(from = 0.5, to = max(as.numeric(as.factor(diamonds$clarity))), by = 1),
max = seq(from = 1.5, to = max(as.numeric(as.factor(diamonds$clarity))) + 0.5, by = 1),
col = c(0,1))
ggplot() +
theme(panel.background = element_rect(fill = "transparent")) +
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
geom_rect(data = shading,
aes(xmin = min, xmax = max, ymin = -Inf, ymax = Inf,
fill = factor(col), alpha = 0.1)) +
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
guides(alpha = FALSE)
How to change the colours of the shading?
I have tried scale_fill_manual(values = c("white", "gray53")), but it seems that multiple scale aesthetics are not possible in ggplot2 (https://github.com/hadley/ggplot2/issues/578). Is there another way to get the desired result ?
Yes, instead of putting your colours in the aes(), put them outside (so they are used as-is). Since it's outside the aes() call you will have to use an explicit fill=shading$col rather than fill=col, and shading$col should have the colour name you are after (rather than a variable interpreted as a factor).
shading$col <- ifelse(shading$col, 'white', 'gray53')
ggplot() +
theme(panel.background = element_rect(fill = "transparent")) +
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
geom_rect(data = shading,
aes(xmin = min, xmax = max, ymin = -Inf, ymax = Inf, alpha = 0.1),
fill=shading$col) + # <-- here
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
guides(alpha = FALSE)

Resources