Make the background of a graph different colours in different regions - r

I'm making a straightforward barchart in R using the ggplot2 package. Rather than the grey default I'd like to divide the background into five regions, each a different (but similarly understated) colour. How do I do this?
More specifically, I'd like the five coloured regions to run from 0-25, 25-45, 45-65, 65-85 and 85-100 where the colours represent worse-than-bronze, bronze, silver, gold and platinum respectively. Suggestions for a colour scheme very welcome too.

Here's an example to get you started:
#Fake data
dat <- data.frame(x = 1:100, y = cumsum(rnorm(100)))
#Breaks for background rectangles
rects <- data.frame(xstart = seq(0,80,20), xend = seq(20,100,20), col = letters[1:5])
#As Baptiste points out, the order of the geom's matters, so putting your data as last will
#make sure that it is plotted "on top" of the background rectangles. Updated code, but
#did not update the JPEG...I think you'll get the point.
ggplot() +
geom_rect(data = rects, aes(xmin = xstart, xmax = xend, ymin = -Inf, ymax = Inf, fill = col), alpha = 0.4) +
geom_line(data = dat, aes(x,y))

I wanted to move the line⎯or the bars of the histogram⎯to the foreground, as suggested by baptiste above and fix the background with
+ theme(panel.background = element_rect(), panel.grid.major = element_line( colour = "white") ), unfortunately I could only do it by sending the geom_bar twice, hopefully someone can improve the code and make the answer complete.
background <- data.frame(lower = seq( 0 , 3 , 1.5 ),
upper = seq( 1.5, 4.5, 1.5 ),
col = letters[1:3])
ggplot() +
geom_bar( data = mtcars , aes( factor(cyl) ) ) +
geom_rect( data = background ,
mapping = aes( xmin = lower ,
xmax = upper ,
ymin = 0 ,
ymax = 14 ,
fill = col ) ,
alpha = .5 ) +
geom_bar(data = mtcars,
aes(factor(cyl))) +
theme(panel.background = element_rect(),
panel.grid.major = element_line( colour = "white"))
Produces this,
Take a look at this site for colour scheme suggestions.

Since you are after vertical (or horizontal) area highlighting, geom_rect() might be an overshoot. Consider geom_ribbon() instead:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
geom_ribbon(aes(xmin=3, xmax=4.2), alpha=0.25) +
theme_minimal()

Related

Can't get errorbar to work with position_dodge with geom_point

I am trying to build a plot with several different data points. The first lot of data I am trying to display are the means with the confidence intervals. The second lot of data will be all the points as a jitter. The issue I am encountering is that I can't get the errorbars to position_dodge along with the geom_point, it just remains centered.
I've created other plots with no trouble, the only difference I can tell is that I am trying to specify the geom_point shape, so that I can have a black outline around the point for easier identification.
ggplot(NULL, aes(x, y)) +
geom_errorbar(
watervol.time,
mapping = aes(
x = Date.Order,
y = water.vol.mean,
ymin = LCI,
ymax = UCI
),
colour = "black", width = 10,
position = position_dodge()
) +
geom_point(
watervol.time,
mapping = aes(
x = Date.Order,
y = water.vol.mean,
fill = Site, group = Site
),
size = 3.5, shape = 21,
position = position_dodge(11)
)
Output that I'm getting:
EDIT: sorry, I couldn't figure out any other way to share the data. Values have been changed due to privacy:
Site Date.Order water.vol.mean LCI UCI
Quartz 28/09/2021 27.52666667 23.86938796 31.18394537
Quartz 29/11/2021 44.23333333 40.57605463 47.89061204
Quartz 18/07/2022 45.23666667 41.57938796 48.89394537
Quartz 27/09/2022 40.46 36.80272129 44.11727871
Hematite 28/09/2021 33.18666667 29.52938796 36.84394537
Hematite 29/11/2021 45.65 41.99272129 49.30727871
Hematite 19/07/2022 45.50333333 41.84605463 49.16061204
Hematite 27/09/2022 42.14 38.48272129 45.79727871
Olivine 28/09/2021 26.21333333 22.55605463 29.87061204
Olivine 29/11/2021 43.84333333 40.18605463 47.50061204
Olivine 18/07/2022 44.58066667 40.92338796 48.23794537
Olivine 27/09/2022 39.778 36.12072129 43.43527871
Plagioclase 28/09/2021 32.81666667 29.15938796 36.47394537
Plagioclase 29/11/2021 46.18166667 42.52438796 49.83894537
Plagioclase 19/07/2022 47.66633333 44.00905463 51.32361204
Plagioclase 27/09/2022 44.89196667 41.23468796 48.54924537
Both geoms need to have the same grouping and dodge width. This is best done when you initialise the plot using ggplot()
I can't confirm this without a reproducible example, but my guess is:
ggplot(watervol.time,
aes(x = Date.Order,
y = water.vol.mean,
ymin = LCI,
ymax = UCI,
group = Site)) +
geom_errorbar(position = position_dodge(width = 11),
colour = "black", width = 10) +
geom_point(aes(fill = Site),
position = position_dodge(width = 11),
size = 3.5, shape = 21)
I figured it out. I had to put group into both the geom_errorbar and geom_point:
ggplot(NULL, aes(x, y)) +
geom_jitter(SWC, mapping = aes(x = Date.Order, y = Water_Vol, colour = Site),
width = 5) +
geom_errorbar(watervol.time, mapping = aes(Date.Order, y = water.vol.mean,
ymin = LCI, ymax = UCI, group = Site), width = 10,
position = position_dodge(10)) +
geom_point(data = watervol.time, mapping = aes(Date.Order, y = water.vol.mean,
fill = Site, group = Site), shape = 21, size = 3.5,
position = position_dodge(10)) +
scale_fill_manual(values = c('blue', 'green', 'yellow', 'red')) +
scale_colour_manual(values = c('blue', 'green', 'yellow', 'red'))

Reproduce a plot using ggplot

I am trying to reproduce a plot using ggplot.
The code I got from the textbook:
skeptic<-c(1,1.171,1.4,1.8,2.2,2.6,3,3.4,3.8,3.934,4.2,
4.6,5,5.4,5.8,6.2,6.6,7,7.4,7.8,8.2,8.6,9)
effect<-c(-.361,-.327,-.281,-.200,-.120,-.039,.041,.122,.202,.229,.282,
.363,.443,.524,.604,.685,.765,.846,.926,1.007,1.087,1.168,1.248)
llci<-c(-.702,-.654,-.589,-.481,-.376,-.276,-.184,-.099,-.024,0,.044,.105,
.161,.212,.261,.307,.351,.394,.436,.477,.518,.558,.597)
ulci<-c(-.021,0,.028,.080,.136,.197,.266,.343,.428,.458,.521,.621,.726,.836,
.948,1.063,1.180,1.298,1.417,1.537,1.657,1.778,1.899)
plot(x=skeptic,y=effect,type="l",pch=19,ylim=c(-1,1.5),xlim=c(1,6),lwd=3,
ylab="Conditional effect of disaster frame",
xlab="Climate Change Skepticism (W)")
points(skeptic,llci,lwd=2,lty=2,type="l")
points(skeptic,ulci,lwd=2,lty=2,type="l")
abline(h=0, untf=FALSE,lty=3,lwd=1)
abline(v=1.171,untf=FALSE,lty=3,lwd=1)
abline(v=3.934,untf=FALSE,lty=3,lwd=1)
text(1.171,-1,"1.171",cex=0.8)
text(3.934,-1,"3.934",cex=0.8)
The exemplary plot is
I have tried ggplot but I am struggling with the vertical and horizontal dashed line. Could anybody reproduce the plot using ggplot? And I have a follow-up question. How can I mark the area of x < 3.934 and x > 1.171? Thank you!
Here is a way to reproduce the posted graph.
library(ggplot2)
library(magrittr)
library(tidyr)
df1 <- data.frame(skeptic, effect, llci, ulci)
vlines <- data.frame(x = c(0, 1.171, 3.934))
vertices <- data.frame(xmin = 1.171, xmax = 3.934,
ymin = -Inf, ymax = Inf)
brks <- names(df1)[-1]
df1 %>%
pivot_longer(-skeptic, names_to = "line") %>%
ggplot(aes(skeptic, value)) +
geom_rect(data = vertices,
mapping = aes(xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax),
fill = "blue", alpha = 0.2,
inherit.aes = FALSE) +
geom_line(aes(size = line, linetype = line)) +
geom_hline(yintercept = 0, linetype = "dotted") +
geom_vline(data = vlines,
mapping = aes(xintercept = x),
linetype = "dotted") +
geom_text(data = subset(vlines, x != 0),
mapping = aes(x = x, label = x),
y = -0.75,
hjust = 0, vjust = 1) +
scale_size_manual(breaks = brks, values = c(1, 0.5, 0.5)) +
scale_linetype_manual(breaks = brks, values = c("solid", "dashed", "dashed")) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
Constructing on your specific question (horizontal and vertical lines and area) as you said you got already the remaining parts right.
Use geom_hline for horizontal line and geom_vline for vertical one. linetype="dashed" will render dashed lines. As you didn't tell how you want the area rendered, here is my guess, a vertical grayed area extending horizontally from abcissa of your vertical lines and vertically from min effect to max effect (Inf values) drawn using a geom_rect.
ggplot(data.frame(skeptic,effect))+
geom_line(aes(skeptic,effect))+
geom_rect(aes(xmin=1.171,xmax=3.934,ymin=-Inf,ymax=Inf),fill="lightgray")+
geom_hline(yintercept=0,linetype="dashed") +
geom_vline(xintercept=c(1.171,3.934),linetype="dashed")

ggplot outline jitter datapoints

I'm trying to create a scatterplot where the points are jittered (geom_jitter), but I also want to create a black outline around each point. Currently I'm doing it by adding 2 geom_jitters, one for the fill and one for the outline:
beta <- paste("beta == ", "0.15")
ggplot(aes(x=xVar, y = yVar), data = data) +
geom_jitter(size=3, alpha=0.6, colour=my.cols[2]) +
theme_bw() +
geom_abline(intercept = 0.0, slope = 0.145950, size=1) +
geom_vline(xintercept = 0, linetype = "dashed") +
annotate("text", x = 2.5, y = 0.2, label=beta, parse=TRUE, size=5)+
xlim(-1.5,4) +
ylim(-2,2)+
geom_jitter(shape = 1,size = 3,colour = "black")
However, that results in something like this:
Because jitter randomly offsets the data, the 2 geom_jitters are not in line with each other. How do I ensure the outlines are in the same place as the fill points?
I've see threads about this (e.g. Is it possible to jitter two ggplot geoms in the same way?), but they're pretty old and not sure if anything new has been added to ggplot that would solve this issue
The code above works if, instead of using geom_jitter, I use the regular geom_point, but I have too many overlapping points for that to be useful
EDIT:
The solution in the posted answer works. However, it doesn't quite cooperate for some of my other graphs where I'm binning by some other variable and using that to plot different colours:
ggplot(aes(x=xVar, y = yVar, color=group), data = data) +
geom_jitter(size=3, alpha=0.6, shape=21, fill="skyblue") +
theme_bw() +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_colour_brewer(name = "Title", direction = -1, palette = "Set1") +
xlim(-1.5,4) +
ylim(-2,2)
My group variable has 3 levels, and I want to colour each group level by a different colour in the brewer Set1 palette. The current solution just colours everything skyblue. What should I fill by to ensure I'm using the correct colour palette?
You don't actually have to use two layers; you can just use the fill aesthetic of a plotting character with a hole in it:
# some random data
set.seed(47)
df <- data.frame(x = rnorm(100), y = runif(100))
ggplot(aes(x = x, y = y), data = df) + geom_jitter(shape = 21, fill = 'skyblue')
The colour, size, and stroke aesthetics let you customize the exact look.
Edit:
For grouped data, set the fill aesthetic to the grouping variable, and use scale_fill_* functions to set color scales:
# more random data
set.seed(47)
df <- data.frame(x = runif(100), y = rnorm(100), group = sample(letters[1:3], 100, replace = TRUE))
ggplot(aes(x=x, y = y, fill=group), data = df) +
geom_jitter(size=3, alpha=0.6, shape=21) +
theme_bw() +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_fill_brewer(name = "Title", direction = -1, palette = "Set1")

In ggplot2, how can I change the border of selected facets?

Taking the graph from ggplot2 help pages:
ggplot(mtcars, aes(factor(cyl))) + geom_bar() + facet_grid(. ~ vs)
Is it possible to change the border (colour and/or thickness) of only selected panels? I'd like to, for instance, change the border of the facet of '1' of faceting variable vs.
I tried adding
theme(panel.border = element_rect(size = 3, colour = "red", fill = NA))
but that solution changes all borders.
I was also thinking about using geom_rect or geom_polygon but am not sure how to limit it to one plot either.
I stumbled upon this thread on R help list, but the solutions didn't work for me
Any suggestions on how to move forward will be much appreciated.
How about filling it with a colour like this?
dd <- data.frame(vs = c(0,1), ff = factor(0:1))
ggplot() + geom_rect(data=dd, aes(fill=ff),
xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf, alpha=0.15) +
geom_bar(data = mtcars, aes(factor(cyl))) + facet_grid(. ~ vs) +
scale_fill_manual(values=c(NA, "red"), breaks=NULL)
I was trying to implement a facet border as well. I did just a little tweaking of the answer supplied by Hadley in the thread mentioned in the question as follows:
# Outline colours
outline <- data.frame(
cyl = c(4, 6, 8),
outline_color = c('green', 'orange', 'red')
)
# Points defining square region for background
square <- with(mtcars, data.frame(
x = c(-Inf, Inf, Inf, -Inf),
y = c(-Inf, -Inf, Inf, Inf)
))
ggplot(mtcars, aes(x = mpg, y = wt)) +
geom_polygon(aes(x = x,y = y, color = outline_color, fill = NA), data = merge(outline, square)) +
geom_point() +
scale_fill_identity() +
facet_grid(. ~ cyl)
Produces the following graph with differing facet borders:

How can I have two different scale_fill_manual active in a ggplot command

This question follows on from my earlier one about background colours in ggplot2.
From the answers there, I am now able to use geom_rect to give a background to my plot that has five different colours. On top of that I'd like to plot a barchart that uses two different colours. I can do each of these tasks separately, but when I try to combine them the scale_fill_manual commands clash.
Here's what I'm trying:
scores = data.frame(category = 1:4, percentage = c(34,62,41,44), type = c("a","a","a","b"))
rects <- data.frame(ystart = c(0,25,45,65,85), yend = c(25,45,65,85,100), col = letters[1:5])
labels = c("ER", "OP", "PAE", "Overall")
medals = c("navy","goldenrod4","darkgrey","gold","cadetblue1")
ggplot() +
geom_rect(data = rects, aes(xmin = -Inf, xmax = Inf, ymin = ystart, ymax = yend, fill=col), alpha = 0.3) +
scale_fill_manual(values=medals) +
opts(legend.position="none") +
geom_bar(data=scores, aes(x=category, y=percentage, fill=type), stat="identity") +
#scale_fill_manual(values = c("indianred1", "indianred4")) +
scale_x_continuous(breaks = 1:4, labels = labels)
As written, this makes the two barchart colours the same as the first two background colours. Removing the "#" on the second scale_fill_manual command (penultimate line) overrides the background colour commands to make the bars the colours I want but makes the background have just the two colours I want in the barchart.
How can I have one scale_fill_manual command applying to the geom_rect background and the other to the geom_bar barchart (or how can I achieve the same effect by other means)?
The problem is that you are using "a" and "b" in both rects and scores, so they get mapped to the same color. Since the rectangles seem to be placeholder values, change them to something distinct that sorts later than anything in scores.
rects$col <- c("Z1","Z2","Z3","Z4","Z5")
Now you can make one scale_fill_manual with all (7) colors.
ggplot() +
geom_rect(data = rects, aes(xmin = -Inf, xmax = Inf, ymin = ystart,
ymax = yend, fill=col), alpha = 0.3) +
opts(legend.position="none") +
geom_bar(data=scores, aes(x=category, y=percentage, fill=type), stat="identity") +
scale_fill_manual(values=c("indianred1", "indianred4", medals)) +
scale_x_continuous(breaks = 1:4, labels = labels)

Resources