geom_rect: background color repeated per season - r

I have a dataframe like this:
df<-data.frame(Category= c("a","b","a","b"), Value = c(25,90,40,10), Date= c("2016-02-13", "2016-05-13", "2016-08-13", "2016-11-13"))
In reality it is more complex, has several years and several observed objects so that it should be a faceted plot in the end, but I think this has nothing to do with the question.
I want to have a ggplot (line plot), where every season got it's own background color.
e.g.: spring from March to May in yellow,
summer from June to August in red
autumn from September to November in blue
and winter from December to February in grey.
This should be repeated, regardless the year as it goes through several years and the database will be updated with time.
I tried a lot with geom_rect but didn't find a working solution.
Thanks for any advice!

If I understand your goal correctly, I think you can achieve it by creating two additional variables, say Season and Color that correspond to Date column, and then supply the columns as necessary to geom_line.
To make the steps and the results clearer, I create a dummy data by expanding your data to another year (2017) with similar date and category but slightly different values:
1. The data
df<-data.frame(Category= c("a","b","a","b"), Value = c(25,90,40,10), Date= c("2016-02-13", "2016-05-13", "2016-08-13", "2016-11-13"))
df2<-data.frame(Category= c("a","b","a","b"), Value = c(30,95,45,15), Date= c("2017-02-13", "2017-05-13", "2017-08-13", "2017-11-13"))
dat <- rbind.data.frame(df,df2)
dat
Category Value Date
1 a 25 2016-02-13
2 b 90 2016-05-13
3 a 40 2016-08-13
4 b 10 2016-11-13
5 a 30 2017-02-13
6 b 95 2017-05-13
7 a 45 2017-08-13
8 b 15 2017-11-13
2. Creating Season and Color columns
dat.season <- dat %>%
mutate(Date = as.Date(Date)) %>%
mutate(Month = months(Date)) %>%
mutate(Season = case_when(Month %in% c("March", "April", "May") ~ "spring",
Month %in% c("June", "July", "August") ~ "summer",
Month %in% c("September", "October", "November") ~ "autumn",
Month %in% c("December", "January", "February")~ "winter")) %>%
mutate(Color = case_when(Season == "spring"~ "yellow",
Season == "summer"~ "red",
Season == "autumn"~ "blue",
Season == "winter"~ "grey"))
dat.season
Category Value Date Month Season Color
1 a 25 2016-02-13 February winter grey
2 b 90 2016-05-13 May spring yellow
3 a 40 2016-08-13 August summer red
4 b 10 2016-11-13 November autumn blue
5 a 30 2017-02-13 February winter grey
6 b 95 2017-05-13 May spring yellow
7 a 45 2017-08-13 August summer red
8 b 15 2017-11-13 November autumn blue
Supplying the columns to geom_line()
dat.season %>% ggplot() +
geom_line(aes(x = Date, y = Value),
colour = dat.season$Color) +
theme_bw()
The result
Update to add coloured background
Here is the line plot along with coloured backgrounds for each season.
dat.season %>%
ggplot() +
geom_rect(aes(xmin = Date[1], xmax = Date[2],
ymin = Value[1], ymax = Value[2]),
fill = dat.season$Color[1])+
geom_rect(aes(xmin = Date[2], xmax = Date[3],
ymin = Value[2], ymax = Value[3]),
fill = dat.season$Color[2])+
geom_rect(aes(xmin = Date[3], xmax = Date[4],
ymin = Value[3], ymax = Value[4]),
fill = dat.season$Color[3])+
geom_rect(aes(xmin = Date[4], xmax = Date[5],
ymin = Value[4], ymax = Value[5]),
fill = dat.season$Color[4])+
geom_rect(aes(xmin = Date[5], xmax = Date[6],
ymin = Value[5], ymax = Value[6]),
fill = dat.season$Color[5])+
geom_rect(aes(xmin = Date[6], xmax = Date[7],
ymin = Value[6], ymax = Value[7]),
fill = dat.season$Color[6])+
geom_rect(aes(xmin = Date[7], xmax = Date[8],
ymin = Value[7], ymax = Value[8]),
fill = dat.season$Color[7])+
geom_line(aes(x = Date, y = Value)) +
theme_bw()
The result

Related

How to set specific date as the beginning date of the year

I want to plot the average annual value of the stream flow data using
WATER YEAR which starts at October and ends at September (say 10/01/1983 to 09/30/1984, this is defined as 1984 water year)
I tried to find solutions elsewhere but I have failed.
Now I'm using the following script to plot the annual average flow
library(tidyverse)
library(lubridate)
library(ggplot2)
#df <- read_csv('dataframe.csv')
df <- df %>%
mutate(date = mdy(df$date))
df <- df %>%
mutate(year = floor_date(date, "year")) %>%
group_by(year) %>%
summarize(avg = mean(flow))
y <- df$avg
x <- as.Date(df$year, format = "Y")
d <- data.frame(x = x, y = y)
# interpolate values from zero to y and create corresponding number of x values
vals <- lapply(d$y, function(y) seq(0, y, by = 0.1))
y <- unlist(vals)
mid <- rep(d$x, lengths(vals))
d2 <- data.frame(x = mid - 100,
xend = mid + 100,
y = y,
yend = y)
ggplot(data = d2, aes(x = x, xend = xend, y = y, yend = yend, color = y)) +
geom_segment(size = 2) +
scale_color_gradient2(low = "midnightblue", mid = "deepskyblue", high = "aquamarine",
midpoint = max(d2$y)/2)+
scale_x_date(date_breaks = "1 year",date_labels = "%Y", expand = c(0,0)) +
theme(axis.text.x = element_text(angle=90, vjust=.5))+
labs(x = "Years", y = "Mean Annual Flow (cms)")+
ggtitle("Mean Annual Flow, Rancho River at ELdorado (1983-2020)")+
theme(plot.title = element_text(hjust = 0.5))
For this I got the following results using calendar year
If I used Water Year there will be no results for 1983
The data frame can be found in the following link
https://drive.google.com/file/d/11PVub9avzMFhUz02cHfceGh9DrlVQDbD/view?usp=sharing
Kindly assist.
If date is superior to 10/01/year(date) it means that this is the next year (in water years):
df %>%
mutate(date=mdy(date), year=year(date), year = year + (date >= mdy(paste0("10/01/", year))))
# A tibble: 5,058 x 3
date flow year
<date> <dbl> <dbl>
1 1983-10-01 3.31 1984
2 1983-10-02 3.19 1984
3 1983-10-03 3.7 1984
4 1983-10-04 3.83 1984
5 1983-10-05 3.44 1984
6 1983-10-06 4.37 1984
7 1983-10-07 6.78 1984
8 1983-10-08 6.3 1984
9 1983-10-09 6.46 1984
10 1983-10-10 6.62 1984
# … with 5,048 more rows

R pivot_longer and ggplot errorbar with two name/key columns

Let's assume we have the following artifical data:
df <- data.frame(Year = c(2015,2016,2017,2018),
GPP_mean = c(1700,1800,1750,1850),
Reco_mean = c(-1700,-1800,-1750,-1850),
GPP_min = c(1600,1700,1650,1750),
GPP_max = c(1800,1900,1850,1950),
Reco_min = c(-1600,-1700,-1650,-1750),
Reco_max = c(-1800,-1900,-1850,-1950))
I'd like to plot bars for each mean value and use the min/max columns for the errorbar.
This is what I've achieved so far:
df %>%
pivot_longer(cols = -Year,
names_to = c("variable", "stats"),
names_sep = "_")
Which gives us:
# A tibble: 24 x 4
Year variable stats value
<dbl> <chr> <chr> <dbl>
1 2015 GPP mean 1700
2 2015 Reco mean -1700
3 2015 GPP min 1600
4 2015 GPP max 1800
5 2015 Reco min -1600
6 2015 Reco max -1800
7 2016 GPP mean 1800
8 2016 Reco mean -1800
9 2016 GPP min 1700
10 2016 GPP max 1900
# … with 14 more rows
So far, so good (I guess?).
From here on, I have no clue of how I can tell ggplot to plot the mean values as the bars and use min/max for the errorbars. Any help appreciated, thanks.
additional solution using tidyverse
library(tidyverse)
out <- df %>%
pivot_longer(-Year, names_sep = "_", names_to = c("index", ".value"))
ggplot(out, aes(Year, mean, fill = index)) +
geom_col() +
geom_errorbar(aes(ymin = min, ymax = max), width = 0.5)
You should stick with your original data frame. There's no need to pivot longer for this:
ggplot(df, aes(Year, GPP_mean)) +
geom_col(fill = "forestgreen", colour = "black") +
geom_errorbar(aes(ymin = GPP_min, ymax = GPP_max), width = 0.5) +
geom_col(aes(y = Reco_mean), fill = "red", colour = "black", position = "dodge") +
geom_errorbar(aes(ymin = Reco_max, ymax = Reco_min), width = 0.5)

R plot months for the first 2 years

I have a data frame with data for max 2 years period on different objects:
ISBN Date Quantity
3457 2004-06-15 10
3457 2004-08-16 6
3457 2004-08-19 10
3457 2005-04-19 7
3457 2005-04-20 12
9885 2013-01-15 10
9885 2013-03-16 6
9855 2013-08-19 10
9885 2014-09-19 7
9885 2014-09-20 12
How can I plot Jan to Dec for the 1st year, continued by Jan to Dec for the 2nd year?
I guess the idea is to normalize the years (to have 1st, 2nd), but not the months. (here's an example)
Number of Items Sold over 2 Years Period Since Release
I'd use the lubridate package for something like this. Note I am calling for dataframe df because you didn't give it a name.
So for example:
library(lubridate)
First format the date like so:
df$Date <- ymd(df$Date)
Then extract the month and the year:
df$Month <- month(df$Date, label=TRUE, abbr=TRUE)
df$Year <- year(df$Date)
From there you can plot your results with ggplot2:
library(ggplot2)
ggplot(df, aes(x=Month, y=Quantity, colour=Year)) +
geom_point()
Note your question could be asked better here as you haven't provided a reproducible example.
You could try:
data <- df %>%
group_by(ISBN) %>%
arrange(Date) %>%
mutate(Year = year(Date),
Month = month(Date, label = TRUE),
Rank = paste(sapply(cumsum(Year != lag(Year,default=0)), toOrdinal), "Year")) %>%
group_by(Rank, Month, add = TRUE) %>%
summarise(Sum = sum(Quantity))
ggplot(data = data, aes(x = Month, y = Sum,
group = factor(ISBN),
colour = factor(ISBN))) +
geom_line(stat = "identity") +
facet_grid(. ~ Rank) +
scale_colour_discrete(name = "ISBN") +
theme(panel.margin = unit(0, "lines"),
axis.text.x = element_text(angle = 90))
Aussming the following df:
df <- data.frame(
ISBN = sample(c(3457, 9885), 1000, replace = TRUE),
Date = sample(seq(as.Date('2004/01/01'),
as.Date('2011/12/31'), by = "month"),
1000, replace = TRUE),
Quantity = sample(1:12, 1000, replace = TRUE)
)
This would produce:

Shade ggplot2 background according to factor level [duplicate]

This question already has answers here:
Make the background of a graph different colours in different regions
(3 answers)
Closed 4 years ago.
I have a dataset with two variables (Tb and Ta) over time (Date). Looks like this:
` Date Tb Ta Light
1 2015-02-15 01:13:00 36.103 22.751 nightime
2 2015-02-15 01:55:00 36.103 22.626 nightime
3 2015-02-15 02:37:00 35.605 22.626 nightime
4 2015-02-15 03:19:00 35.605 22.751 nightime
5 2015-02-15 04:01:00 36.103 23.001 nightime
6 2015-02-15 04:43:00 35.605 22.876 nightime`
I am trying to make a plot with different shading for levels in the factor 'Light'. So all points with 'nightime' in 'Light' would be shaded in grey while the 'daytime' would be white. Something like this:
Is there a way to get geom_rect() to work with a factor level? I need all points coded as 'nightime' shaded with a grey background ...
I tried the following based on Using ggplot2 in R, how do I make the background of a graph different colours in different regions?
ggplot() + geom_rect(data=tbdf, (aes(xmin=Date,
xmax=Date, ymin=min(Tb), ymax=max(Tb), fill=Light))) +
geom_line(data = tbdf, aes(x = Date, y = Tb)) +
geom_line(data = tbdf, aes(x = Date, y = Ta), colour='grey') +
xlab('Date') +
ylab('Temperature (°C)')
and it ends up with a legend for Light but still the usual grey shading:
Any suggestions?
Due to a lack of sample data I created some.
library(ggplot2)
library(dplyr)
daytime <- rep(rep(c("day", "night"), each = 12),10)
df <- data.frame(date = 1:length(daytime), daytime, value = rnorm(length(daytime)))
> head(df)
date daytime value
1 1 day -0.7016900
2 2 day -0.5886091
3 3 day -0.1962264
4 4 day 1.3621115
5 5 day -1.5810459
6 6 day -0.6598885
Then I determined the start and end of each day and each night. For the sample data this would not be necessary but I guess the real data are not that simple.
period <- case_when(daytime != lead(daytime) & daytime == "day" ~ "endDay",
daytime != lead(daytime) & daytime == "night" ~ "endNight",
daytime != lag(daytime) & daytime == "day" ~ "beginDay",
daytime != lag(daytime) & daytime == "night" ~ "beginNight")
period[1] <- "beginDay"
period[length(period)] <- "endNight"
Combining both:
rect <- cbind(df,period)
names(rect)[1] <- "date"
and creating 2 dataframes, one for night and one for daytime with the corresponding x values of each period.
rect_night <- na.omit(rect[rect$daytime == "night", ])[ ,-2:-3]
rect_night <- data.frame(start = rect_night[rect_night$period == "beginNight", 1],
end = rect_night[rect_night$period == "endNight", 1])
rect_day <- na.omit(rect[rect$daytime == "day", ])
rect_day <- data.frame(start = rect_day[rect_day$period == "beginDay", 1],
end = rect_day[rect_day$period == "endDay", 1])
Putting alltogether in a plot.
ggplot(alpha = 0.3) +
geom_rect(data = rect_night,aes(xmin = start, xmax = end, ymin = -5, ymax = 5), fill = "grey") +
geom_rect(data = rect_day,aes(xmin = start, xmax = end, ymin = -5, ymax = 5), fill = "yellow") +
geom_line(data = df, aes(x = date, y = value))
It seems to have been a problem with the Date format. Changing it from 2015-02-15 01:13:00 format to a number (eg. 42050.05) worked great. Here's the code I used
ggplot() + geom_rect(data=tbdf, (aes(xmin=Date-0.5, xmax=Date+0.5,
ymin=min(Ta)-0.5, ymax=max(Tb)+0.5, fill=factor(Light)))) +
scale_fill_manual(values=c("grey", "white"), guide=FALSE) +
geom_line(data = tbdf, aes(x = Date, y = Tb), size=0.8) +
geom_line(data = tbdf, aes(x = Date, y = Ta), colour='grey50', size=0.8) +
ylab('Temperature (°C)')
Which gave me this
Which cleans up nicely.

Add several lines of variable text in fixed positions to a ggplot facet

I am tryig to add several lines of text to this facet. Sorry about the mess of code
From the object means1 I want to add the values of the variables "pCensCom" "pCensEx" and "pCensReg" for each facet, as described in the following figure
This is the object 'censTot1' used to build the chart
censo censTot tipoAni censAn año pCensAn
1: 2010-01-01 42 Hembra adulta 27 2010 64.285714
2: 2010-01-01 42 Joven 4 2010 9.523810
3: 2010-01-01 42 Macho adulto 1 2010 2.380952
4: 2010-01-01 42 Ternero 10 2010 23.809524
5: 2010-01-02 42 Hembra adulta 27 2010 64.285714
---
7300: 2014-12-30 57 Ternero 16 2014 28.070175
7301: 2014-12-31 57 Hembra adulta 32 2014 56.140351
7302: 2014-12-31 57 Joven 7 2014 12.280702
7303: 2014-12-31 57 Macho adulto 2 2014 3.508772
7304: 2014-12-31 57 Ternero 16 2014 28.070175
The following describes the code used to design the figure
# Plot color background
# %%%%%%%%%%%%%%%%%%%%%%
bg0<-data.table()
for(i in 1:5){
bg<-data.table(xstart=c(as.Date(paste0(años[i],"-01-01"), format="%Y-%m-%d"),as.Date(paste0(años[i],"-03-21"), format="%Y-%m-%d"), as.Date(paste0(años[i],"-06-21"),format = "%Y-%m-%d"),as.Date(paste0(años[i],"-09-21"),format = "%Y-%m-%d"),
as.Date(paste0(años[i],"-12-21"),format = "%Y-%m-%d")),xend=c(as.Date(paste0(años[i],"-03-21"), format="%Y-%m-%d"),
as.Date(paste0(años[i],"-06-21"),format = "%Y-%m-%d"), as.Date(paste0(años[i],"-09-21"),format = "%Y-%m-%d"),
as.Date(paste0(años[i],"-12-21"),format = "%Y-%m-%d"),as.Date(paste0(años[i],"-12-31"),format = "%Y-%m-%d")),
Estacion=c("Invierno","Primavera","Verano","Otoño","Invierno"))
l=list(bg0,bg); bg0<-rbindlist(l, fill=TRUE)
}
bg0<-bg0[,Estacion:=factor(ordered(Estacion,levels=c("Invierno","Primavera", "Verano", "Otoño")))]
cbPalette<-c("#FF3300","#006633","#FFFF00","#0000FF")
plotbg<-ggplot()+ geom_rect(data = bg0, aes(xmin = xstart, xmax = xend, ymin = 0, ymax = Inf, fill = Estacion), alpha = 0.10)+ scale_fill_manual(values=cbPalette)+ guides(fill=FALSE)+theme_bw()
means1<-data.table(tipoAni=c("Hembra adulta","Joven","Macho adulto","Ternero"),pCensCom=c(62.3,17.8,0.9,19.37),pCensEx=c(61.4,16.1,1.9,20.6),pCensReg=c(63.0,17.9,1.6,24.7))
# Plot
# %%%%
plotbg + geom_line(data=censTot1,aes(x=censo,y=pCensAn))+ facet_grid(tipoAni ~ .)+ xlab("Censos diarios") + ylab("Animales (%)") +theme_bw()+ theme(strip.text.x = element_text(size=8),strip.text.y = element_text(size=10, face="bold"),strip.background = element_rect(colour="red", fill="#CCCCFF"))
Please I need help, I tried several times using the functions annotation_custom, grobTree and textGrob and I have not been able to achieve
Here is a simplified answer. First I simulate some data dat, then a second data.table backgr that has the information for the background, and lastly textdt, which holds the information about the text elements.
The code looks like this:
library(data.table)
library(ggplot2)
library(scales)
dat <- data.table(x = rep(1:100, 2),
group = rep(LETTERS[1:2], each = 100),
val = rnorm(200))
dat[, price := 100 + cumsum(val), by = group]
# plot empty
ggplot(dat, aes(x = x, y = price)) +
geom_line() +
facet_grid(group~.)
# plot with added polygons
# for the background colors
backgr <- data.table(minval = c(10, 40, 60, 90),
maxval = c(20, 60, 80, 100),
backgroup = LETTERS[1:4])
# for the text elements
textdt <- data.table(xval = c(10, 50, 70),
yval = c(105, 100, 95),
textlabel = c("foo", "bar", "lorum"),
group = c("A", "A", "B"))
# plot
ggplot() +
geom_rect(data = backgr, aes(xmin = minval, xmax = maxval, ymin = -Inf,
ymax = Inf, fill = backgroup)) +
geom_line(data = dat, aes(x = x, y = price)) +
geom_text(data = textdt, aes(x = xval, y = yval, label = textlabel,
group = group)) +
facet_grid(group~.) +
scale_fill_manual(values = alpha(c("red", "green", "blue", "yellow"), 0.5))
Which results in a plot like this, which you can adjust to fit your data:

Resources