Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shade ggplot2 background according to factor level [duplicate]

Tags:

r

ggplot2

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?

like image 427
Daniele L Avatar asked Sep 13 '25 10:09

Daniele L


1 Answers

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))

enter image description here

like image 81
Alex Avatar answered Sep 15 '25 01:09

Alex