Plot a variable whose name is a function call

ggplot2

#1

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?


#2

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).


#3

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

#4

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).


#5

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

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.