7

I haven't found any history questions about this... I want to highlight the weekend performance for a ggplot graph, so that user could tell directly one the graph which part(may be a gray shade?) is weekend performance right away.

Here's a simple version of testing data:

test <- data.frame(DATE=seq(from = as.POSIXct("2014-07-16 01:00"), to = as.POSIXct("2014-07-30 00:00"), by = "hour"),count=floor(runif(336,1,100)))

Simple version of my graph is:

ggplot() + geom_line(aes(x=DATE,y=count),data=test) + labs(title="test")

So that result could be like something below...

enter image description here

glennsl
  • 28,186
  • 12
  • 57
  • 75
linp
  • 1,427
  • 2
  • 12
  • 13
  • 1
    See [geom_rect](http://docs.ggplot2.org/current/geom_rect.html)?. Should do what you're after. Also [this question](http://stackoverflow.com/questions/16504349/can-a-portion-of-the-background-in-ggplot-be-changed-to-a-different-color) may help. – Adam Kimberley Aug 13 '14 at 15:49
  • @AdamKimberley Nice thanks! I can actually specify the date instead of the cell position. Think I need to come up a smarter way in longer time range but so far this works like a charm! :) – linp Aug 13 '14 at 16:24

5 Answers5

11

Using geom_area() is more concise, and will work for any date range.

    library(ggplot2)

    test <- data.frame(DATE=seq(from = as.POSIXct("2014-07-16 01:00"), 
                                to = as.POSIXct("2014-07-30 00:00"), 
                                by = "hour"),
                       count=floor(runif(336,1,100)))

    test$weekend <- weekdays(test$DATE) %in% c("Saturday", "Sunday")

    ggplot(data=test, aes(x=DATE, y=count)) +
      geom_area(aes(y=weekend*max(count)), fill="yellow") +
      geom_line() +
      labs(title="test")

enter image description here

mynameisthis
  • 133
  • 1
  • 8
  • I couldn't get this to work for a faceted plot, but I found a useful clue here: https://stackoverflow.com/questions/51092214/faceting-based-on-geom-point-when-ggplot-empty-and-multiple-shaded-geom-rect-e – John Jan 23 '19 at 22:44
5

Here's code that does both weekends in your data. You could generalize to any number of weekends by adding more geom_rect() calls (or calling a loop that does).

# your data
test <- data.frame(DATE=seq(from = as.POSIXct("2014-07-16 01:00"), to = as.POSIXct("2014-07-30 00:00"), by = "hour"),count=floor(runif(336,1,100)))
your_plot <- ggplot(test) + geom_line(aes(x=DATE,y=count)) + labs(title="test") 

# get all the start and end points
library(lubridate) # for hour function
sats <- which(hour(test$DATE)==0 & weekdays(test$DATE)=='Saturday')
suns <- which(hour(test$DATE)==23 & weekdays(test$DATE)=='Sunday')

# do your plot plus weekend highlights
your_plot +
  geom_rect(aes(xmin=DATE[sats[1]], xmax=DATE[suns[1]],
                  ymin=min(count), ymax=max(count)),
            fill='yellow', alpha=.005) +

  geom_rect(aes(xmin=DATE[sats[2]], xmax=DATE[suns[2]],
                ymin=min(count), ymax=max(count)),
            fill='yellow', alpha=.005)

Here's the output

arvi1000
  • 9,393
  • 2
  • 42
  • 52
  • Nice! I just followed Adam's suggestion specify the date, but this is exactly what I was looking for regarding to longer time range. Thanks! :) – linp Aug 13 '14 at 16:26
  • How about mentioning that the hours and weekdays functions are in the lubridate package? – mborowczak Feb 17 '15 at 17:23
  • Good point. Added. (Though it's just hour. weekdays is in base) – arvi1000 Feb 17 '15 at 17:30
  • You can also use `data.table::hour` – arvi1000 Feb 17 '15 at 17:38
  • If you're using a loop to add more geom_rect(), dont forget to use aes_string() instead of plain aes(). Otherwise only the last rectangle will be shown. – Daan Feb 19 '19 at 21:22
2

Here is an approach using Tydiverse tools, and more precisely geom_tile. The advantage is that you have not to precise the x boundaries.

library(dplyr)
library(lubridate)
library(ggplot2)

test %>%
  # My preference :-)
  rename_all(tolower) %>%
  # Computing the weekends by converting in weekday starting on monday to ease the cut
  mutate(weekend = wday(date, week_start = getOption("lubridate.week.start", 1)) > 5) %>%
  ggplot() +
  geom_line(aes(x = date, y = count)) +
  # And here is the trick!
  scale_fill_manual(values = c("alpha", "yellow")) +
  geom_tile(aes(
    x = date,
    y = min(count),
    height = Inf,
    fill = weekend
  ), alpha = .4)

Result

Note: I've written a more detailed post on this topic.

Romain
  • 19,910
  • 6
  • 56
  • 65
1

As per my comment, hopefully this is what you are looking for:

test <- data.frame(DATE=seq(from = as.POSIXct("2014-07-16 01:00"), to = as.POSIXct("2014-07-30 00:00"), by = "hour"),count=floor(runif(336,1,100)))

ggplot() + geom_rect(aes(xmin = as.POSIXct("2014-07-26 00:00"), xmax = as.POSIXct("2014-07-28 00:00"), ymin = 0, ymax = 100), fill = "yellow")+
 geom_line(aes(x=DATE,y=count),data=test) + labs(title="test")

Giving pretty much exactly the image in the question. You can alter fill to change the colour and easily add further rectangles at different points if required.

Resulting image

Adam Kimberley
  • 879
  • 5
  • 12
1

I found a nice solution with geom_bar() where you make a vector which is infinite on weekends, the remaining values are NA and will not be plotted. I used lubridate as I am more familiar with it. I also had to name the aesthetics in the first call to ggplot() so the axes inherit their proper names and y is not labelled as "weekend":

library(lubridate)
library(ggplot2)

test <- data.frame(DATE=seq(from = as.POSIXct("2014-07-16 01:00"), to = as.POSIXct("2014-07-30 00:00"), by = "hour"),count=floor(runif(336,1,100)))
your_plot <- ggplot(test) + geom_line(aes(x=DATE,y=count)) + labs(title="test") 
your_plot

test$wd <- wday(test$DATE, label = TRUE)
test$weekend[test$wd=="Sat" | test$wd=="Sun"] <- 1/0

highlight_plot <- ggplot(test, aes(x= DATE, y = weekend)) + 
  geom_bar(stat="Identity", aes(y=weekend), col="yellow", alpha=.4, width = 1) + 
geom_line(aes(x=DATE,y=count)) + labs(title="test") 

highlight_plot

This solution is pretty flexible and it's easy to adapt the method to highlight different vectors of dates.

glennsl
  • 28,186
  • 12
  • 57
  • 75
Alex vER
  • 11
  • 2