Plot a variable whose name is a function call

For various reasons I have a data frame that contains a variable with the name "log(foo)". I am trying to plot objects like this from within a function. I use aes_string() in my functions to refer to the name of the variable I want to plot, but this is failing when the string is a function call like "log(foo)". When the data for the plot is evaluated, ggplot is looking for a variable with name "foo" not "log(foo)".

library("ggplot2")
df <- data.frame(y = runif(1:10), "log(foo)" = 1:10, check.names = FALSE)
varname <- "log(foo)"
ggplot(df, aes_string(x = varname, y = "y")) + geom_point()

The above gives the error:

Error in FUN(X[[i]], ...) : object 'foo' not found

Is there any idiom that will allow the use of non standard variable names like this?

This is simply because that data.frame doesn't have such column as log(foo). You need to specify check.names = FALSE or use tibble.

df <- data.frame(y = runif(1:10), "log(foo)" = 1:10)
colnames(df)
#> [1] "y"        "log.foo."

Created on 2018-09-05 by the reprex package (v0.2.0).

Gah, sorry; in creating my example I forgot check.names = FALSE but I do have this set in the actual code where this error occurred. Turning on check.names = FALSE doesn't resolve the issue:

> df <- data.frame(y = runif(1:10), "log(foo)" = 1:10, check.names = FALSE)
> names(df)
[1] "y"        "log(foo)"
> ggplot(df, aes_string(x = varname, y = "y")) + geom_point()
Error in FUN(X[[i]], ...) : object 'foo' not found

Ah, sorry that my code did not answer your question... It seems you can wrap the name with ` `.

library(ggplot2)

df <- data.frame(y = runif(1:10), "log(foo)" = 1:10, check.names = FALSE)
varname = "`log(foo)`"
ggplot(df, aes_string(x = varname, y = "y")) + geom_point()

Created on 2018-09-05 by the reprex package (v0.2.0).

2 Likes

If you're using the last release or newer, ggplot now has tidy eval, so you can use rlang::sym and unquote in regular aes:

library(ggplot2)
set.seed(47)

df <- data.frame(y = runif(1:10), "log(foo)" = 1:10, check.names = FALSE)
varname <- "log(foo)"

ggplot(df, aes(x = !!sym(varname), y = y)) + geom_point()

With the old-style system, you can do something similar with aes_:

ggplot(df, aes_(x = as.name(varname), y = ~y)) + geom_point()

With aes_string, as @yutannihilation said, you'd need to insert quotes to inhibit evaluation, e.g.

ggplot(df, aes_string(x = sprintf("`%s`", varname), y = "y")) + geom_point()

From the docs (?aes_), though:

Life cycle

All these functions are soft-deprecated. Please use tidy evaluation idioms instead (see the quasiquotation section in aes() documentation).

6 Likes

Thanks @alistaire ; I wondered if rlang was the way to go here. I hadn't seen the as.name() variant for aes_() before, having tried the quote() variant, that is documented, without success.

I think I'll use aes_() with as.name() for the time being as I haven't really studied rlang enough to be confident using it in a package.