Calimo
Calimo

Reputation: 7969

Define ggplot2 aesthetics from a list programatically without aes_string

I have a list of aesthetics constructed programmatically and passed from other functions. They may contain any combination of aesthetics like alpha, colour, fill, etc., which is not know beforehand.

my_aes_list <- list(
    x = "cty",
    y = "hwy",
    col = "trans")

I can use aes_string to create aesthetics programmatically from this list:

library(ggplot2)
my_aes <- do.call(ggplot2::aes_string, my_aes_list)
ggplot(mpg) + geom_point(my_aes)

However aes_string() was deprecated in ggplot2 3.0.0 and I would like to replace this code before it gets removed in a future version.

The documented alternative and several stack overflow questions indicate to use the .data[[ pronoun. However I can't find out how to use it with arbitrary programmatic aesthetics.

Doing something like:

my_data_list <- list()
for (name in names(my_aes_list)) {
    my_data_list[[name]] <- .data[[my_aes_list[name]]]
}

obviously doesn't work outside of the aes call itself. I also tried the !!! injectors to no avail:

ggplot(mpg) + geom_point(aes(!!!my_aes_list))

seems to work but doesn't plot correctly.

What's the proper way to replace aes_string and call ggplot in this context?

Upvotes: 1

Views: 243

Answers (3)

tony-aw
tony-aw

Reputation: 11

The 'tinycodet' R package provides aes_pro(), which is equivalent to ggplot2::aes(), except it uses formula inputs instead of non-standard evaluation. So you can do the following:

library(ggplot2)
data("mpg", package = "ggplot2")
my_aes_list <- list(
  x = ~ cty,
  y = ~ hwy,
  col = ~ trans
)
my_aes <- do.call(tinycodet::aes_pro, my_aes_list) # create aes
ggplot(mpg) + geom_point(my_aes) # plot

Upvotes: 0

Calimo
Calimo

Reputation: 7969

One solution I found is to "defuse" the evaluation of the .data[[ pronoun with a call to expr():

my_data_list <- lapply(my_aes_list, function(x) ggplot2::expr(.data[[x]]))

Later, ggplot2::aes() transparently evaluates these expressions:

my_aes <- do.call(ggplot2::aes, my_data_list)
ggplot(mpg) + geom_point(my_aes)

Upvotes: 1

jared_mamrot
jared_mamrot

Reputation: 26225

Interesting problem; another potential solution is to 'enquo(ensym(list))' then use the !!! operator, i.e.

library(tidyverse)
library(rlang)

my_aes_list <- list(
  x = "cty",
  y = "hwy",
  col = "trans")

my_list_quos <- as_quosures(map(my_aes_list, sym), env = .GlobalEnv)
my_list_quos
#> <list_of<quosure>>
#> 
#> $x
#> <quosure>
#> expr: ^cty
#> env:  global
#> 
#> $y
#> <quosure>
#> expr: ^hwy
#> env:  global
#> 
#> $col
#> <quosure>
#> expr: ^trans
#> env:  global

ggplot(mpg) + geom_point(aes(!!!my_list_quos))

Created on 2023-06-26 with reprex v2.0.2

Upvotes: 1

Related Questions