Home > Back-end >  Setting a Background Color for One Facet of Pie Charts in ggplot2
Setting a Background Color for One Facet of Pie Charts in ggplot2

Time:01-23

I'm trying to create a plot with three pie containing facets. One of these contains the overall statistics. therefore, to emphasize the "overall" one, I'd like to put a background color behind it.

Here is how the data looks

  cat     action   pct
  <chr>   <chr>  <dbl>
1 All     No        34
2 All     Yes       66
3 Host    No        24
4 Host    Yes       76
5 Refugee No        38
6 Refugee Yes       62

Here is the dput deconstruction

> dput(a)
structure(list(cat = c("All", "All", "Host", "Host", "Refugee", 
"Refugee"), action = c("No", "Yes", "No", "Yes", "No", "Yes"), 
    pct = c(34, 66, 24, 76, 38, 62)), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -6L), groups = structure(list(
    cat = c("All", "Host", "Refugee"), .rows = structure(list(
        1:2, 3:4, 5:6), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -3L), .drop = TRUE))

I've tried adding a geomrect() layer before. Usually this method works with my other line and bar graphs where I haven't applied coord_polar() in the plot.

Here is the simplified code:

a %>% 
  ggplot(aes("", pct, fill= action)) 
  geom_rect(data = data.frame(cat="All"), aes(xmin = -Inf,xmax = Inf, ymin = -Inf,ymax = Inf,),
            fill='red',alpha = 0.2, inherit.aes = FALSE) 
  geom_bar(stat = "identity", position = "fill") 
  coord_polar(theta = "y", start = 0) 
  facet_wrap(~cat) 
  theme_solid() 
  guides(fill="none")

with coord_polar()

without coord_polar()

CodePudding user response:

I don't think there's an easy way to do this directly within ggplot. The rectangular grobs and annotations don't seem to accept infinite limits with a polar transformation, and any finite limits will result in a circular highlight area being drawn. You cannot pass multiple element_rect in theme to style multiple panels either.

This leaves two broad options:

  1. Generate the plots separately and draw them together on a single page
  2. Take the graphical output of your plot and change the appropriate grob to a rectGrob with the appropriate fill color.

One neat way to achieve the first option without repeating yourself is to use dplyr::group_map and patchwork::wrap_plots:

library(tidyverse)

a %>% 
  group_by(cat) %>%
  group_map(.keep = TRUE,
            ~ ggplot(.x, aes("", pct, fill = action))  
    geom_bar(stat = "identity", position = "fill") 
    coord_polar(theta = "y", start = 0)  
    ggthemes::theme_solid()  
    guides(fill = "none")  
    theme(panel.background = element_rect(
            fill = if(all(.x$cat == 'All')) '#FF000032' else NA))) %>%
  patchwork::wrap_plots()

enter image description here

The other option, if for some reason you need to use facets, is some form of grob hacking like this:

p <- a %>% 
  ggplot(aes("", pct, fill = action))  
  geom_bar(stat = "identity", position = "fill")  
  coord_polar(theta = "y", start = 0)  
  facet_wrap(~cat)  
  ggthemes::theme_solid()  
  guides(fill = "none")

pg <- ggplotGrob(p)

new_background <- grid::rectGrob(gp = grid::gpar(fill = '#FF000032', col = NA))
panel1 <- pg$grobs[[which(pg$layout$name == 'panel-1-1')]]
panel1$children <- panel1$children
background <- grep('rect', sapply(panel1$children[[1]], names)$children)
panel1$children[[1]]$children[[background]] <- new_background
pg$grobs[[which(pg$layout$name == 'panel-1-1')]] <- panel1

grid::grid.newpage()
grid::grid.draw(pg)

enter image description here

  • Related