0

I would like to create a function that takes a column name and creates a plot based on that. For example, I want to be able to plot the Petal.Length column of the iris dataset against other variables. The way to do it without indirection is

ggplot(data = iris) + geom_point(x = Petal.Width, y = Petal.Length)

This is the plot I would like to replicate through indirection, but none of the following attempts work. These two return similar undesired plots:

colname = "Petal.Width"
ggplot(data = iris) + geom_point(x = colname, y = Petal.Length)

ggplot(data = iris) + geom_point(x = {{colname}}, y = Petal.Length)

The following attempt does not work either, it returns an error:

ggplot(data = iris) + geom_point(aes(x = !!!rlang::syms(colname), y = Petal.Length))

#> Warning in geom_point(aes(x = !!!rlang::syms(colname_x), y = Petal.Length)):
#> Ignoring unknown aesthetics:
#> Error in `geom_point()`:
#> ! Problem while setting up geom.
#> ℹ Error occurred in the 1st layer.
#> Caused by error in `compute_geom_1()`:
#> ! `geom_point()` requires the following missing aesthetics: x

Any hint on how we could do this? The idea is to have a function that is able to plot that kind of chart just by giving a string corresponding to one x variable that appears in the dataset.

  • See linked post: `colname = "Petal.Width"; colname = ensym(colname); ggplot(data = iris) + geom_point(aes(x = !!colname, y = Petal.Length))` – zx8754 Jan 09 '23 at 13:11

3 Answers3

2

Using the .data pronoun and by wrapping inside aes() you could do:

library(ggplot2)

colname <- "Petal.Width"
ggplot(data = iris) + 
  geom_point(aes(x = .data[[colname]], y = Petal.Length))

stefan
  • 90,330
  • 6
  • 25
  • 51
2

Your plot #2 is invariant in x because it takes "Petal.Width" as a literal value (as in data.frame(x="Petal.Width")), obviously not what you intend.

There are a few ways to work with programmatic variables:

  1. We can use the .data pronoun in ggplot, as in

    var1 <- "mpg"
    var2 <- "disp"
    ggplot(mtcars, aes(x = .data[[var1]], y = .data[[var2]])) +
      geom_point()
    
  2. We can use rlang::quo and !! for interactive work:

    x <- rlang::quo(mpg)
    y <- rlang::quo(disp)
    ggplot(mtcars, aes(x = !!x, y = !!y)) +
      geom_point()
    
  3. If in a function, we can enquo (and !!) them:

    fun <- function(data, x, y) {
      x <- rlang::enquo(x)
      y <- rlang::enquo(y)
      ggplot(data, aes(!!x, !!y)) +
        geom_point()
    }
    fun(mtcars, mpg, disp)
    
r2evans
  • 141,215
  • 6
  • 77
  • 149
1

another (more clumsy) approach with base R:

colname = "Petal.Width"
ggplot(data = iris) + 
  geom_point(aes(x = eval(parse(text = colname)), y = Petal.Length)
)
I_O
  • 4,983
  • 2
  • 2
  • 15