Cauder
Cauder

Reputation: 2587

How do I add shaded backgrounds to ggplot?

I'm following along with the example on page 82 from ggplot2 by Hadley Wickham.

presidential <- presidential[-(1:3), ]

yrng <- range(economics$unemploy)
xrng <- range(economics$date)
unemp + geom_vline(aes(xintercept = start), data = presidential
unemp + geom_rect(aes(NULL, NULL, xmin = start, xmax = end,
fill = party), ymin = yrng[1], ymax = yrng[2],
data = presidential) + scale_fill_manual(values =
alpha(c("blue", "red"), 0.2))

enter image description here

That's the code that is used in the book to generate a plot with shaded backgrounds.

I'd like to do the same thing, except with the data from the Tour de France

Here's my code.

library(tidyverse)
library(lubridate)

# organize the data
tdf_winners <- read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-04-07/tdf_winners.csv')

wins.by.winner_name <-
  tdf_winners %>% 
  count(winner_name) %>% 
  arrange(-n) %>% 
  mutate(total_wins = n) %>% 
  select(-n)

tdf_winners <-
  tdf_winners %>% 
  filter(start_date > ymd("1913-01-01")) %>%
  left_join(wins.by.winner_name, by = "winner_name") %>% 
    mutate(winner_name_lbl = ifelse(total_wins == 1, "One Time Winner",
                                  winner_name))

# create the graphic

yrng <- range(tdf_winners$time_overall[!is.na(tdf_winners$time_overall)])
xrng <- range(tdf_winners$edition)

  tdf_winners %>% 
  ggplot(aes(edition, time_overall)) +
  geom_col() +
    geom_rect(aes(NULL, NULL, 
                      xmin = edition, xmax = edition, fill = winner_name_lbl),
              ymin = yrng[1], ymax = yrng[2],
              data = tdf_winners) +
  scale_fill_manual(values = alpha(c("blue", "red",
                                     "green", "purple",
                                     "pink", "orange",
                                     "yellow", "violet",
                                     "black", "maroon",
                                     "lightblue", "lightgreen",
                                     "lightpink", "navy",
                                     "lightyellow", "royalblue",
                                     "grey", "lightgrey",
                                     "darkgrey", "darkgreen", "white"
                                     )))

Unfortunately, it doesn't create the shaded background. I'd like to have a shade that depends on the winner name.

How do I create this?

Upvotes: 1

Views: 913

Answers (1)

eipi10
eipi10

Reputation: 93761

I think geom_tile is easier to work with here. It's similar to geom_rect, but the rectangles are parametrized by their center, height, and width, rather than the locations of the four vertices.

my_colors = c("blue", "red",
              "green", "purple",
              "pink", "orange",
              "yellow", "violet",
              "black", "maroon",
              "lightblue", "lightgreen",
              "lightpink", "navy",
              "lightyellow", "royalblue",
              "grey", "lightgrey",
              "darkgrey", "darkgreen", "white")

tdf_winners %>% 
  ggplot(aes(edition, time_overall)) +
    geom_tile(aes(x=edition, y=125, width=1, height=250, fill = winner_name_lbl), alpha=0.4) +
    geom_col(fill="grey50") +
    scale_fill_manual(values = my_colors) +
    scale_y_continuous(limits=c(0, 250), expand=c(0,0)) +
    theme_classic()

enter image description here

Here's another option that I think is easier on the eyes:

winners = tdf_winners %>%  
  arrange(edition) %>% 
  mutate(winner.change = cumsum(c(0, diff(as.numeric(factor(winner_name))))!=0)) %>% 
  group_by(winner.change) %>% 
  summarise(edition.ctr = mean(edition),
            width = n(),
            winner_name = unique(winner_name)) %>% 
  ungroup() %>% 
  mutate(winner.change = factor(winner.change %% 2))

tdf_winners %>% 
  ggplot(aes(edition, time_overall)) +
    geom_tile(data=winners, colour="white", show.legend=FALSE,
              aes(x=edition.ctr, y=125, width=width, height=250, fill=winner.change), alpha=0.4) +
    geom_line(colour="grey50") +
    geom_point(colour="grey20") +
    scale_fill_manual(values = hcl(c(15,195), 100, 80)) +
    scale_y_continuous(limits=c(0, 250), expand=c(0,0)) +
    scale_x_continuous(breaks=winners$edition.ctr, labels=winners$winner_name, 
                       expand=expansion(c(0.01,.01)),
                       sec.axis=sec_axis(~ ., 
                                         breaks=tdf_winners$edition,
                                         labels=year(tdf_winners$start_date))) +
    theme_classic() +
    theme(axis.text.x=element_text(angle=-90, vjust=0.5, hjust=0),
          axis.text.x.top=element_text(angle=-90, hjust=0.5, vjust=0.5, size=8)) +
    labs(x="", y="Time") 

enter image description here

Zooming in to get a better look at a portion of the plot:

enter image description here

A couple of other notes:

geom_rect wasn't doing anything in your example, because xmin = edition, xmax = edition results in a rectangle of zero width.

The alpha() function isn't necessary unless you want to set a transparency value for the fill colors.

Upvotes: 3

Related Questions