42

I'm using the "tips" data set in ggplot2. If I do

sp = ggplot(tips,aes(x=total_bill, y = tip/total_bill)) + 
        geom_point(shape=1) + 
        facet_grid(sex ~ day)

The plot comes out fine. But I now want to change the panel background for just the plots under "Fri". Is there a way to do this?

Even better, can I conditionally change colors by passing parameters? For example if more than 3 points are below 0.1, then change panel background (for just that panel) to a certain color while all others remain the default light grey?

joran
  • 169,992
  • 32
  • 429
  • 468
broccoli
  • 4,738
  • 10
  • 42
  • 54

2 Answers2

85

The general rule for doing anything in ggplot2 is to,

  1. Create a data frame that encodes the information you want to plot
  2. Pass that data frame to a geom

This is made a bit more complicated in this case because of the particular aspect of the plot you want to alter. The Powers That Be designed ggplot2 in a way that separates data elements of the plot (i.e. geom's) from non-data elements (i.e. theme's), and it so happens that the plot background falls under the "non-data" category.

There is always the option of modifying the underlying grid object manually but this is tedious and the details may change with different versions of ggplot2. Instead, we'll employ the "hack" that Hadley refers to in this question.

#Create a data frame with the faceting variables
# and some dummy data (that will be overwritten)
tp <- unique(tips[,c('sex','day')])
tp$total_bill <- tp$tip <- 1

#Just Fri
ggplot(tips,aes(x=total_bill, y = tip/total_bill)) + 
        geom_rect(data = subset(tp,day == 'Fri'),aes(fill = day),xmin = -Inf,xmax = Inf,
            ymin = -Inf,ymax = Inf,alpha = 0.3) +
        geom_point(shape=1) + 
        facet_grid(sex ~ day) 

enter image description here

#Each panel
ggplot(tips,aes(x=total_bill, y = tip/total_bill)) + 
        geom_rect(data = tp,aes(fill = day),xmin = -Inf,xmax = Inf,
            ymin = -Inf,ymax = Inf,alpha = 0.3) +
        geom_point(shape=1) + 
        facet_grid(sex ~ day) 

enter image description here

Community
  • 1
  • 1
joran
  • 169,992
  • 32
  • 429
  • 468
  • Thanks much for the help. Definitely useful. – broccoli Mar 24 '12 at 00:33
  • 3
    Note that setting panel.background and the above geom_rect behave differently when behind geom_raster because an optimization can take place when there is "nothing" behind the raster. When saved as a pdf, the geom_rect version is a significantly larger file and virtually unopenable with most pdf viewers! – momeara Jun 27 '13 at 01:53
  • Is it possible to do this with a continuous feature and scale? – UnivStudent Sep 02 '15 at 17:52
  • @UnivStudent Can you be more specific? – joran Sep 02 '15 at 19:03
  • @joran Instead of having a factor variable like days of the week, can you colour this according to a numeric feature? – UnivStudent Sep 02 '15 at 19:07
  • @UnivStudent Yes, but what would that mean? Do you mean you want non-constant color in each panel? If so, in what direction does the color vary and how do you connect that to the x and y variables in the panel? I could go on... – joran Sep 02 '15 at 19:09
  • @Joran I figured out how to do it with this example but using the fill as numeric. Is it always necessary to have the dummy variables for all variables present in the original data frame? – UnivStudent Sep 05 '15 at 16:59
  • 1
    Great solution, but does not work well if you have `fill` aesthetic in other layers, like `geom_bar`. – yuk Apr 10 '21 at 22:32
  • 1
    Is there any way to pick specific colors for the days? I have tried adding a column with color names "red", "blue", "green" etc. ggplot seems to use them but not in the order I specified. – ktm Feb 01 '23 at 19:46
3

I cannot comment yet.. so here is an additional answer to joran his answer.

If you are having trouble with the transparency setting, like setting alpha = 0.2 but not noticing any difference, it might be because of the data that you give to ggplot.

"Thanks for clarifying your question. This was puzzling to me, so I went to google, and ended up learning something new (after working around some vagaries in their examples). Apparently what you are doing is drawing many rectangles on top of each other, effectively nullifying the semi-transparency you want. So, the only ways to overcome this are to hard-code the rectangle coordinates in a separate df"

This answer comes from geom_rect and alpha - does this work with hard coded values?

Community
  • 1
  • 1
zwep
  • 1,207
  • 12
  • 26