2

I'm having trouble adding multiple annotations (using vectors) to a plot with facets.

For example:

library(tidyverse) # ggplot2_3.3.0

tibble(t = 1:100) %>% 
  crossing(id = LETTERS[1:2]) %>% 
  group_by(id) %>% 
  mutate(y = cumsum(rnorm(n()))) %>% 
  ggplot(aes(t, y)) + # perhaps add `group = id` if you don't facet by `id`
  facet_wrap(vars(id)) + # (1)
  annotate('rect', xmin = 20, xmax = 30, ymin = -Inf, ymax = Inf, fill = 'grey60') + # (2)
  annotate('rect', xmin = 30, xmax = 40, ymin = -Inf, ymax = Inf, fill = 'grey70') + # (2)
  annotate('rect', xmin = 40, xmax = 50, ymin = -Inf, ymax = Inf, fill = 'grey80') + # (2)
  annotate('rect', xmin = 50, xmax = 60, ymin = -Inf, ymax = Inf, fill = 'grey90') + # (2)
  # annotate('rect', ymin = -Inf, ymax = Inf,                # (3)
  #          xmin = seq(20, by=10, len=4),                   # (3)
  #          xmax = seq(30, by=10, len=4),                   # (3)
  #          fill = paste0('grey', seq(60, by=10, len=4))) + # (3)
  geom_line() +
  theme_light()

The above code produces the desired plot (in particular, I want the same annotation on all facets). However, the annotate command is repeated four times; furthermore the help page for annotate says "the properties of the geoms are ... passed in as vectors". So a natural thing to try is to comment out lines (2), and uncomment lines (3). Unfortunately this generates the error

Error: Aesthetics must be either length 1 or the same as the data (8): fill

Note that if, in addition, you comment out line (1) (and optionally add group = id to the aesthetics) then it does not generate an error.

1 Answer 1

2

For a discussion of this behaviour of ggplot2 see gihub. As the issue was closed and as far as I get it there is nothing you can do abozt that by using annotate. However, to achieve what you want you can simply use geom_rect like so:

library(tidyverse) # ggplot2_3.3.0

df_annotate <- data.frame(
  xmin = seq(20, 50, 10),
  xmax = seq(30, 60, 10),
  ymin = -Inf,
  ymax = Inf,
  fill = paste0("grey", seq(60, 90, 10))
)

tibble(t = 1:100) %>% 
  crossing(id = LETTERS[1:4]) %>% 
  group_by(id) %>% 
  mutate(y = cumsum(rnorm(n()))) %>% 
  ggplot() + 
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill), data = df_annotate) +
  geom_line(aes(t, y)) +
  scale_fill_identity() +
  facet_wrap(vars(id)) +
  theme_light()

Created on 2020-05-28 by the reprex package (v0.3.0)

Edit Using ggnewscale it's possible to have a second or ... fill scale:

library(tidyverse) # ggplot2_3.3.0
library(ggnewscale)

df_annotate <- data.frame(
  xmin = seq(20, 50, 10),
  xmax = seq(30, 60, 10),
  ymin = -Inf,
  ymax = Inf,
  fill = paste0("grey", seq(60, 90, 10))
)

df <- tibble(t = 1:100) %>% 
  crossing(id = LETTERS[1:4]) %>% 
  group_by(id) %>% 
  mutate(y = cumsum(rnorm(n())))

ggplot() + 
  geom_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill), data = df_annotate) +
  scale_fill_identity() +
  new_scale_fill() +
  geom_area(data = df, aes(t, y, fill = id)) +
  facet_wrap(vars(id)) +
  theme_light()

Created on 2020-05-29 by the reprex package (v0.3.0)

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I actually had an additional requirement (which I failed to mention above): My geom is actually geom_col which has it's own fill requirements (somewhat more colorful!). This was the reason I wanted to use annotate -- to keep the two separate. However you link to the GitHub issue is very helpful, and makes me think it's not really possible (or requires something like cran.r-project.org/package=ggnewscale) hence I'll accept this answer.
Hi @banbh. Thx. And yes. ggnewscale could do the trick. I read over this part of your comment but had the same idea. ((: As I already checked it out I added it as an edit to my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.