Search code examples
rggplot2facet-grid

tidy_eval inside labeller() function for facet_grid() in R


I previously posted this question as well as this one which might give additional context to this question.

data for context:


library(tidyverse)
library(rlang)

set.seed(1)
dfr2 <- tibble(x1 = factor(sample(letters[1:3], 50, replace = T), levels=letters[1:3]),
             x2 = factor(sample(letters[1:2], 50, replace = T), levels=letters[1:2]),
             x3 = factor(sample(letters[1:3], 50, replace = T), levels=letters[1:3]),
             grpA = factor(sample(c("grp1","grp2"),50, prob=c(0.3, 0.7) ,replace=T), levels = c("grp1", "grp2")),
             grpB = factor(sample(c("grp1","grp2"),50, prob=c(0.6, 0.4) ,replace=T), levels = c("grp1", "grp2"))
             )

head(dfr2)



function for data prep in which I calculate variables used for plotting, as well as the group totals for the grouping variable: grp_tot



plot_data_prepr <- function(dat, groupvar, mainvar){
  
  groupvar <- sym(groupvar)
  mainvar <- sym(mainvar)
  
  plot_data <- dat %>% 
    group_by(!!groupvar) %>% 
    count(!!mainvar, .drop = F) %>% drop_na() %>% 
    mutate(pct = n/sum(n),
         pct2 = ifelse(n == 0, 0.005, n/sum(n)),
         grp_tot = sum(n),
         pct_lab = paste0(format(pct*100, digits = 1),'%'),
         pct_pos = pct2 + .02)
  
  return(plot_data)
}


normal use of the data prep function:



plot_data_prepr(dat = dfr2, groupvar = "grpA", mainvar = "x1")



in the labeller() function below, I have to explicitly type 'grpA' to get the code to work. Although this produces the desired result of facet labels with the appropriate labels, it is not what I want as it will prevent me from dynamically changing the grouping variable if I were to loop through grouping variables:



for(mvar in names(dfr2)[1:3]) {
  
  smvar <- sym(mvar)
  
  gvar <- names(dfr2[4])
  sgvar <- sym(gvar)
  
  dd <- plot_data_prepr(dat = dfr2, groupvar = gvar, mainvar = mvar)

  lookup <- unique(dd$grp_tot)

  plusN <- function(string) {
    
    label <- paste0(string, ' (N = ',lookup,')')
    label
  }
  
    plot <- ggplot(dd, 
                   aes(x = !!smvar,y = pct2, fill = !!smvar)) +
      geom_bar(stat = 'identity') +
      ylim(0,1) +
      geom_text(aes(label=pct_lab, y = pct_pos + .02)) +
      facet_grid(as.formula(paste0(".~", gvar)), labeller = labeller(grpA = plusN))
      
    print(plot)
      
  }



Instead, I would like to be able to use the quoted symbol gvar so that I could dynamically change the grouping variable and labels atop the plot. I tried changing the plusN() function by using enquo() on the 'string' argument, and then changing 'grpA' to gvar in the labeller() function, but now the facet labels do not appear at all:


for(mvar in names(dfr2)[1:3]) {
  
  smvar <- sym(mvar)
  
  gvar <- names(dfr2[4])
  sgvar <- sym(gvar)
  
  dd <- plot_data_prepr(dat = dfr2, groupvar = gvar, mainvar = mvar)

  lookup <- unique(dd$grp_tot)

  plusN <- function(string) {
    
    enquo(string)
    
    label <- paste0(!!string, ' (N = ',lookup,')')
    label
  }
  
    plot <- ggplot(dd, 
                   aes(x = !!smvar,y = pct2, fill = !!smvar)) +
      geom_bar(stat = 'identity') +
      ylim(0,1) +
      geom_text(aes(label=pct_lab, y = pct_pos + .02)) +
      facet_grid(as.formula(paste0(".~", gvar)), labeller = labeller(gvar = plusN))
      
    print(plot)
      
  }

Perhaps someone might be able to help me resolve my issue.

Thanks.


Solution

  • As far as I get it, one approach to solve your issue would be to use a labeller function as facet_grid passes a df to the labeller function, where the column names of the df are the names of the facetting var(s). Try this:

    Try this:

    for(mvar in names(dfr2)[1:1]) {
      
      smvar <- sym(mvar)
      
      gvar <- names(dfr2[4])
      sgvar <- sym(gvar)
      
      dd <- plot_data_prepr(dat = dfr2, groupvar = gvar, mainvar = mvar)
      
      lookup <- unique(dd$grp_tot)
    
      my_label <- function(x) {
        var <- names(x)[1]
        list(paste0(var, ": ", x[[var]], " (N = ", lookup, ")"))
      }
      
      plot <- ggplot(dd, 
                     aes(x = !!smvar,y = pct2, fill = !!smvar)) +
        geom_bar(stat = 'identity') +
        ylim(0,1) +
        geom_text(aes(label=pct_lab, y = pct_pos + .02)) +
        facet_grid(as.formula(paste0(".~", gvar)), labeller = my_label)
      
      print(plot)
      
    }