10

I am trying to get a shaded rectangle on the first three panels in my facet_wrap plot. However, when I use geom_rect for the job, it produces the rectangle on each of the panels. Is there a way to selectively get the rectangle only on the first three panels?

Here is some code

dfTemp = data.frame(value = rnorm(100*4), variable = sort(rep(1:4, 100)),
                    date = rep(seq.Date(
                      from = as.Date('2011-01-01', format = '%Y-%m-%d'),
                      length.out = 100,
                      by = 'day'), 4))

ggplot(dfTemp) +
  geom_rect(aes(xmin = as.Date('2011-02-01', format = '%Y-%m-%d'),
                xmax = as.Date('2011-03-01', format = '%Y-%m-%d'),
                ymin = -Inf,
                ymax = Inf), alpha = 0.2, fill = 'grey') +
  geom_line(aes(x = date, y = value, group = variable, color = factor(variable))) +
  facet_wrap(~variable , scale = 'free', ncol = 1) 

Update 1:

I updated my code to

dfTemp = data.frame(value = rnorm(100*4), variable = sort(rep(1:4, 100)),
                    date = rep(seq.Date(
                      from = as.Date('2011-01-01', format = '%Y-%m-%d'),
                      length.out = 100,
                      by = 'day'), 4))

ggplot(dfTemp) +
  geom_rect(data = dfTemp[dfTemp$variable %in% c(2, 3),],
            aes(xmin = as.Date('2011-02-01', format = '%Y-%m-%d'),
                xmax = as.Date('2011-03-01', format = '%Y-%m-%d'),
                ymin = -Inf,
                ymax = Inf), alpha = 0.2, fill = 'grey') +
  geom_line(aes(x = date, y = value, group = variable, color = factor(variable))) +
  facet_wrap(~variable , scale = 'free', ncol = 1) 

Note that I am now subsetting the data that I am passing to geom_rect. But this gives me this warning:

Warning message: In [<-.factor(*tmp*, rng, value = c(1L, 1L, 1L, 1L, 1L, 1L, : invalid factor level, NA generated

What does this mean?

tchakravarty
  • 10,736
  • 12
  • 72
  • 116
  • I added an update to my answer that should clarify why you don't even need to subset the data as the only data you want from the data frame are values for `variable`, and nothing else. – BrodieG Mar 06 '14 at 19:58

2 Answers2

9

Here is a solution that creates a new data frame with variable and then takes advantage of recycling in aes to generate the rectangle coordinates for each value in variable.

ggplot(dfTemp) +
  geom_rect(
    data=data.frame(variable=factor(1:3)), 
    aes(xmin=as.Date('2011-02-01'), xmax=as.Date('2011-03-01'), ymin=-Inf, ymax=Inf), 
    alpha = 0.5, fill = 'grey') +
  geom_line(aes(x = date, y = value, group = variable, color = factor(variable))) +
  facet_wrap(~variable , scale = 'free', ncol = 2)

enter image description here

BrodieG
  • 51,669
  • 9
  • 93
  • 146
7

There's a very simple way to do this:

library(ggplot2)
library(plyr)      # for .(...)
ggplot(dfTemp) +
  geom_rect(subset= .(variable<4),aes(xmin = as.Date('2011-02-01', format = '%Y-%m-%d'),
                xmax = as.Date('2011-03-01', format = '%Y-%m-%d'),
                ymin = -Inf,
                ymax = Inf), alpha = 0.2, fill = 'grey') +
  geom_line(aes(x = date, y = value, group = variable, color = factor(variable))) +
  facet_wrap(~variable , scale = 'free', ncol = 1) 

The only difference with your original code is the addition of subset=.(variable<4) to the call to geom_rect(...).

jlhoward
  • 58,004
  • 7
  • 97
  • 140
  • The evil genius of Hadley. Thanks. :) – tchakravarty Mar 06 '14 at 19:25
  • 1
    @fgnu, while this is great, note how the transparency doesn't work. This is because you are drawing the rectangles as many times as you have data points so they add up to the point were you can't see through them. If you do it this way you have to subset and ensure you get only one rectangle per variable value less than 4. – BrodieG Mar 06 '14 at 19:43
  • @BrodieG Thanks for that. I actually prefer my own solution which subsets explicitly. Was just very taken to see plyr syntax working so seamlessly in ggplot2. – tchakravarty Mar 06 '14 at 19:45
  • @fgnu, I think your approach has the same problem with transparency. You want not only the values that are not 4 in variable, you also want just one row from each of the groups otherwise you end up with the same rectangle overplotted by however may rows you have in each group (and no transparency as a result). – BrodieG Mar 06 '14 at 19:50
  • JL, @BrodieG has a valid point. While your solution is neater, from a visualization point of view, the transparency is important. – tchakravarty Mar 07 '14 at 04:32