1

I have a data frame in this kind of format:

df <- data.frame(
  time = rep(seq(from = as.POSIXct("2016-08-10 11:00:00"), 
         to = as.POSIXct("2016-08-10 12:00:00"), by="sec"), 2),
  value = c(diffinv(rnorm(3601)), diff(rnorm(3601))),
  facets = c(rep("A",3601), rep("B", 3601)),
  shading = rep(c(rep("x", 1500), rep("y", 750), rep("z", 1351)), 2),
  stringsAsFactors = FALSE
)

I can plot the value time series on separate graphs sharing the x-axis using ggplot2's facet_grid function. I also want to include another dimension in my plot - the variable shading to shade the background.

I know I can do this by specifying the ranges of the x-axis the shaded regions will cover:

xRange1 <- range(df$time[df$shading=="x"])
xRange2 <- range(df$time[df$shading=="y"])
xRange3 <- range(df$time[df$shading=="z"])

yRange <- range(df$value)

When I first set this up I include alpha in each of my geom_rect

ggplot(df, aes(x = time, y = value)) +
  geom_line() +
  facet_grid(facets ~ ., scales = "free_y") +
  geom_rect(aes(xmin = xRange1[1], xmax = xRange1[2]), 
                ymin = yRange[1], ymax = yRange[2],
                alpha = 0.3, fill = "#EEF2BF") +
  geom_rect(aes(xmin = xRange2[1], xmax = xRange2[2]),
                ymin = yRange[1], ymax = yRange[2],
                alpha = 0.3, fill = "#A3BAB6",) +
  geom_rect(aes(xmin = xRange3[1], xmax = xRange3[2]),
                ymin = yRange[1], ymax = yRange[2],
                alpha = 0.3, fill = "#BFA67E")

enter image description here

Obviously the alpha didn't work.

One way to get around this is to put geom_line() at the end:

ggplot(df, aes(x = time, y = value)) +
  facet_grid(facets ~ ., scales = "free_y") +
  geom_rect(aes(xmin = xRange1[1], xmax = xRange1[2]), 
            ymin = yRange[1], ymax = yRange[2],
            alpha = 0.3, fill = "#EEF2BF") +
  geom_rect(aes(xmin = xRange2[1], xmax = xRange2[2]),
            ymin = yRange[1], ymax = yRange[2],
            alpha = 0.3, fill = "#A3BAB6",) +
  geom_rect(aes(xmin = xRange3[1], xmax = xRange3[2]),
            ymin = yRange[1], ymax = yRange[2],
            alpha = 0.3, fill = "#BFA67E") +
  geom_line() 

enter image description here

But that hides the grid and doesn't solve the underlying problem.

I have looked at several posts and none of them address this directly. I have looked at using other functions in my plot including scale_fill_manual (last example on page) and scale_alpha

Edit: I suspect the best solution also involves setting up the geom_rect in a less manual way. My actual data frame has more than 3 character values I want to shade with.

Community
  • 1
  • 1
Warner
  • 1,353
  • 9
  • 23
  • 1
    Have you checked [this post](http://stackoverflow.com/questions/17521438/geom-rect-and-alpha-does-this-work-with-hard-coded-values) out? – bouncyball Aug 10 '16 at 16:55
  • @bouncyball Yes I have. The issue with that approach is that when I use `annotate` I lose the `scales = "free_y"` from my `facet_grid` function. – Warner Aug 10 '16 at 16:58
  • set `inherit.aes = FALSE` in `geom_rect` – Richard Telford Aug 10 '16 at 17:02
  • 1
    Another option is make a summary dataset that contains the values for x values for the three different shading groups. You can then use this dataset and the `fill` argument to add your rectangles all at one time. – aosmith Aug 10 '16 at 17:05
  • @RichardTelford This did not work. – Warner Aug 10 '16 at 17:42
  • @aosmith I think this is a good idea but I'm not sure how to execute it. I created `> df2 X1 X2 Y1 Y2 1 2016-08-10 11:00:00 2016-08-10 11:24:59 -22.44567 144.67652 2 2016-08-10 11:25:00 2016-08-10 11:37:29 -22.44567 144.67652 3 2016-08-10 11:37:30 2016-08-10 12:00:00 -22.44567 144.67652` but I am not having success adding `geom_rect(data = df2, aes(xmin=X1, xmax=X2, ymin = Y1, ymax= Y2), inherit.aes = FALSE)` – Warner Aug 10 '16 at 17:44
  • Hard to explain in comments, but my version was three rows long and had columns for `shading`, `xmin`, `xmax`. Shading was x, y, or z (which I used as `fill`) and the other two columns were the min and max for the x variable (I was using `-Inf/Inf` for the y variable but you could add `ymin` and `ymax` to dataset with the same value for each shading group/row). – aosmith Aug 10 '16 at 17:57
  • 1
    Here is my code for making the dataset using *dplyr* functions: `dfrect = df %>% group_by(shading) %>% summarise(xmin = min(time), xmax = max(time))`. And the code for rectangles/fill: `geom_rect(data = dfrect, aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf, fill = shading), alpha = 0.3, inherit.aes = FALSE) + scale_fill_manual(values = c("#EEF2BF"), "#A3BAB6", "#BFA67E"))` – aosmith Aug 10 '16 at 17:59
  • This works @aosmith. I don't know why this thread was marked as a duplicate because the problem here is different and (in my opinion) non-trivial. This is a great answer but it's unfortunate nobody will post other ways to approach this problem. – Warner Aug 10 '16 at 20:10

0 Answers0