How to programmatically implement flexibility to either apply a column or use a single color to fill argument in ggplot

I am creating a custom function that generates bar plots using ggplot2 and geom_col().

My objective is to enable the function to dynamically assign either a single color or a color based on a grouping variable to the fill aesthetic. Here's the code I've developed:


f1 <- function(data, x, y, z, single_color=FALSE, color="red") {
  data <- data %>% 
  if (single_color) {
    p <- ggplot(data, aes(x = factor({{ x }}), y = {{ y }})) +
      geom_col(width = 0.6, fill = color) +
  } else {
    p <- ggplot(data, aes(x = factor({{ x }}), y = {{ y }}, fill = factor({{ z }}))) +
      geom_col(width = 0.6) +
      theme_minimal() +
      scale_fill_brewer(palette = "Set1")

f1(mtcars, cyl, n, cyl, single_color=TRUE, color="blue")
f1(mtcars, cyl, n, cyl, single_color=FALSE)

enter image description here

I'm contemplating whether there's a more straightforward method, such as:

f1 <- function(data, x, y, z) {
  z <- ensym(z)
  ggplot(data, aes(x = factor({{x}}), y = {{y}}, fill= !!z)) +
    geom_col(width = 0.6) +
    scale_fill_brewer(palette = "Set1") 

To summarize my question: Is it possible for z to be both a column name and a string simultaneously?

Related link:


  • If I understand you correctly, you want the argument z to be either a symbol representing a column name, or a string representing a color. I guess this is possible, though it's a little convoluted:

    f1 <- function(data, x, y, z) {
      is_column <- deparse(substitute(z)) %in% names(data)
      ggplot(data, aes(x = factor({{x}}), y = {{y}})) +
        do.call("geom_col", c(list(width = 0.6),
                            if(is_column) list(mapping = aes(fill = factor({{z}}))),
                            if(!is_column) list(fill = z)))

    Testing we get

    f1(mtcars, cyl, mpg, cyl)


    f1(mtcars, cyl, mpg, "blue")