Add transparent block bands to ggplot for a y-range - r

I am trying to add four transparent bands to my ggplot for the following y ranges:
y<2 & y>1.5
y<1.5 & y>1
y<1 & y>0.5
y<0.5 & y>0
I don't want the ranges to overlap as that changes the colour that I'm assigning each band (as they're transparent).
I can sort of get the effect I'm after using geom_area (see code below), but they overlap, which changes the colour.
I'm wondering if there is a better way to get the bands specifically in the areas I want?
df <- data.frame(y1=rep(1.99, 100),
y2=rep(1.49, 100),
y3=rep(0.99, 100),
y4=rep(0.49, 100),
x =1:100)
ggplot(aes(x=x), data = df) +
geom_area(aes(y=ifelse(y1<2 & y1>1.5, y1, 0)), data=df, fill="yellow", alpha = 0.3) +
geom_area(aes(y=ifelse(y2<1.5 & y2>1, y2, 0)), data=df, fill="darkgoldenrod1", alpha = 0.3) +
geom_area(aes(y=ifelse(y3<1 & y3>0.5, y3, 0)), data=df, fill="darkorange1", alpha = 0.3) +
geom_area(aes(y=ifelse(y4<0.5 & y4>0, y4, 0)), data=df, fill="darkred", alpha = 0.3) +
theme_classic()
Also, potentially separate question, is there a way to make the fill color go all the way to the axis rather than just leaving a white buffer space around it?

Use geom_rect before plotting any points
ggplot() +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 1.5, ymax = 2), fill="yellow", alpha = 0.3) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 1, ymax = 1.5), fill="darkgoldenrod1", alpha = 0.3) +
geom_point(data = df, aes(x = x, y = y1)) +
theme_classic()
See geom_rect and alpha - does this work with hard coded values? for getting alpha to work correctly with the rectangles.

Related

trouble combining geom_rect and facet_grid in ggplot

I want to shade part of the background in each facet of a simple plot. If I omit faceting and run geom_rect + geom_point, the expected results appear as shown in the MRE below. If I omit the rectangle and run geom_point + facet_grid, the expected 4 panels have each point in the correct facet. But when I combine geom_rect + geom_point + and facet_grid, the points in the first category and only those get plotted in every facet. What is going on please???
library(ggplot2)
set.seed(42)
syn.dat <- data.frame(
category.1 = as.factor(rep(c("1A", "1B"), each = 8)),
category.2 = as.factor(rep(rep(c("2A", "2B"), times = 2), each = 4)),
x = rep(-1:2, each = 4) + runif(8, max = .4),
y = rep(-1:2, each = 4) + runif(8, max = .4))
ggplot() +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = .5,
ymax = Inf), fill = "lightyellow") +
geom_point(data = syn.dat, aes(x = x, y = y)) +
facet_grid(cols = vars(category.1),
rows = vars(category.2))
I'm not totally sure about this, but it may be that you need to explicitly provide the data argument to ggplot itself, in order for facet_grid to correctly pick up all the values?
ggplot(syn.dat) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 0.5, ymax = Inf), fill = "lightyellow") +
geom_point(aes(x = x, y = y)) +
facet_grid(rows = vars(category.2), vars(cols = category.1))

Overlay histogram and density with varying alpha

I am trying to create a ggplot histogram with a density overlay, where the alpha changes past the number 1. An example can be seen on 538 under the Every outcome in our simulations section. The alpha differs based on the electoral vote count. I am close to getting a similar graph but I cannot figure out how to get the density and histogram to work together.
Code
library(data.table)
library(ggplot2)
dt <- data.table(ratio = rnorm(10000, mean = .5, sd = 1))
dt[, .(ratio,
al = (ratio >= 1))] %>%
ggplot(aes(x = ratio, alpha = al)) +
geom_histogram(aes(), bins = 100,
fill = 'red') +
geom_density(aes(),size = 1.5,
color = 'blue') +
geom_vline(xintercept = 1,
color = '#0080e2',
size = 1.2) +
scale_alpha_discrete(range = c(.65, .9))
This attempt correctly changes alpha past 1 as desired but the density estimate is not scaled.
dt[, .(ratio,
al = (ratio >= 1))] %>%
ggplot(aes(x = ratio)) +
geom_histogram(aes(y = ..density.., alpha = al), bins = 100,
fill = 'red') +
geom_density(aes(y = ..scaled..),size = 1.5,
color = 'blue',) +
geom_vline(xintercept = 1,
color = '#0080e2',
size = 1.2) +
scale_alpha_discrete(range = c(.65, .9))
This attempt correctly scales the density curve, but now the geom_histogram is calculated separately for values under 1 and above 1. I want them calculated as one group.
What am I missing?
The reason why knowing your theme is important is that there's an easy shortcut to this, which is not using alpha, but just drawing a semitransparent rectangle over the left half of your plot:
library(data.table)
library(ggplot2)
library(dplyr)
data.table(ratio = rnorm(10000, mean = .5, sd = 1)) %>%
ggplot(aes(x = ratio)) +
geom_histogram(aes(y = ..density..), bins = 100,
fill = 'red') +
geom_line(aes(), stat = "density", size = 1.5,
color = 'blue') +
geom_vline(xintercept = 1,
color = '#0080e2',
size = 1.2) +
annotate("rect", xmin = -Inf, xmax = 1, ymin = 0, ymax = Inf, fill = "white",
alpha = 0.5) +
theme_bw()
Splitting into two groups and using alpha is possible, but it basically requires you to precalculate the histogram and the density curve. That's fine, but it would be an awful lot of extra effort for very little visual gain.
Of course, if theme_josh has a custom background color and zany gridlines, this approach may not be quite so effective. As long as you set the fill color to the panel background you should get a decent result. (the default ggplot panel is "gray90" or "gray95" I think)

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.

shade regions in R plot

I have a plot in R to analyse the functional behaviour of this function :
-2.5*log10(x) in different regions , the inputs are like this
curve(-2.5*log10(x),0,5,main="Behaviour of magnification function",col=2)
abline(v=0,col=3)
abline(v=1,col=4)
abline(h=0,col=8)
Now I would like to shade those regions on the right of the v=1 line and left with two different shades, but can't figure it out how to do. the polygon function not giving the shade , please help
thanks,
Ayan
You can use the panel.first argument to draw in the background.
Define a function to do the drawing:
fnShade = function(v,colL,colR) {
p = par("usr") # limits of the plot
rect(p[1],p[3],v,p[4],col=colL,border=NA)
rect(v,p[3],p[2],p[4],col=colR,border=NA)
abline(v=v,col=4)
}
Then use it
curve(-2.5*log10(x),0,5,main="Behaviour of magnification function",col=2,
panel.first=fnShade(1,5,"grey80"))
You can add your other ablines into the function if you like. And it should be easy to extend to draw 4 rectangles - one for each quardant - if desired.
Here is a ggplot solution to the problem, using annotate:
First, save the results from curve in df:
df <- curve(-2.5*log10(x),0,5,main="Behaviour of magnification function",col=2)
Then use geom_vline to add the vertical lines, and annotate to add a rect geom to the data for the shaded areas. We use annotate, because we do not want to use data from the original data frame as suggested in this answer.
plot <- ggplot(data.frame(df)) +
geom_line(aes(x, y), size = 1) +
geom_vline(xintercept = 1, color = "blue", size = 1) +
geom_hline(yintercept = 0, color ="grey", size = 1) +
geom_vline(xintercept = 0, color = "green", size = 1) +
annotate("rect", xmin = 1, xmax = Inf, ymax = Inf, ymin = -Inf, fill = "blue", alpha = 0.2) +
annotate("rect", xmin = -Inf, xmax = 1, ymax = Inf, ymin = -Inf, fill = "green", alpha = 0.2) +
labs(title = "Behaviour of magnification function\n") +
theme_bw()
plot

Resources