以变量命名的列美学,如何在美学中使用括号运算符?

huangapple go评论80阅读模式
英文:

Aesthetics by column named with variable, how to use embrace operator in aesthetics?

问题

我有一个数据框,我想告诉ggplot2根据我用字符串变量命名的列进行着色

cubbins <- tibble(x=1:10, y=c(1:5, 1:5), title=rep(c("500 hats", "Oobleck"), 5))
my_col <- "title"

cubbins %>% ggplot(aes_string(x="x", y="y", color=my_col)) + geom_point() ## 正常工作,已弃用
cubbins %>% ggplot(aes(x=x, y=y, color=!!my_col)) + geom_point() ## 错误
cubbins %>% ggplot(aes(x=x, y=y, color={{my_col}})) + geom_point() ## 仍然错误
cubbins %>% ggplot(aes(x=x, y=y, color=sym(my_col))) + geom_point() ## 无效的美学警告
cubbins %>% ggplot(aes(x=x, y=y, color=enquo(my_col))) + geom_point() ## 无效的美学警告

cubbins %>% ggplot(aes(x=x, y=y, color=.data[[my_col]])) + geom_point() ## 这是当前aes_string文档中推荐的方式
cubbins %>% ggplot(aes(x=x, y=y, color=!!sym(my_col))) + geom_point() ## 正常工作,请解释

最后一个版本可以正常工作,但我对其他版本为什么无法工作感到困惑。感谢您的帮助。

错误版本:
以变量命名的列美学,如何在美学中使用括号运算符?
正确版本:
以变量命名的列美学,如何在美学中使用括号运算符?

背景信息:aes_string 已被弃用,但在我的简短搜索中没有找到关于正确解决方法的任何解释。

一般参考:https://rlang.r-lib.org/reference/topic-metaprogramming.html

英文:

I have a data frame and I want to tell ggplot2 to color according to a column I name with a string variable

cubbins &lt;- tibble(x=1:10, y=c(1:5, 1:5), title=rep(c(&quot;500 hats&quot;, &quot;Oobleck&quot;), 5))
my_col &lt;- &quot;title&quot;

cubbins %&gt;% ggplot(aes_string(x=&quot;x&quot;, y=&quot;y&quot;, color=my_col)) + geom_point() ## works, deprecated
cubbins %&gt;% ggplot(aes(x=x, y=y, color=!!my_col)) + geom_point() ## wrong
cubbins %&gt;% ggplot(aes(x=x, y=y, color={{my_col}})) + geom_point() ## same wrong
cubbins %&gt;% ggplot(aes(x=x, y=y, color=sym(my_col))) + geom_point() ## invalid aesthetics warning
cubbins %&gt;% ggplot(aes(x=x, y=y, color=enquo(my_col))) + geom_point() ## invalid aesthetics warning

cubbins %&gt;% ggplot(aes(x=x, y=y, color=.data[[my_col]])) + geom_point() ## this is what&#39;s recommended in the current aes_string documentation
cubbins %&gt;% ggplot(aes(x=x, y=y, color=!!sym(my_col))) + geom_point() ## WORKS, please explain

The last version works, but I'm confused about why all the other versions aren't working. Your assistance is appreciated.

wrong version:
以变量命名的列美学,如何在美学中使用括号运算符?
correct version:
以变量命名的列美学,如何在美学中使用括号运算符?

For background, aes_string is deprecated, but I didn't find any explanation for the proper workaround anywhere in my brief googling.

General refernce: https://rlang.r-lib.org/reference/topic-metaprogramming.html

答案1

得分: 3

我们实际上可以单独使用 aes 函数来更好地理解正在发生的事情。

基本上,我们希望得到与以下输出相同的内容:

library(ggplot2)

aes(colour = title)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

在这里,美学映射 colour符号 title 相关联。但我们希望使用存储的预定义字符字符串来实现这一点:

my_col &lt;- &quot;title&quot;

以前,我们可以简单地使用 aes_string

aes_string(color = my_col)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`
#&gt; 警告信息:
#&gt; `aes_string()` 在 ggplot2 3.0.0 中已弃用。
#&gt; 请使用 tidy evaluation ideoms 与 `aes()`

这个方法可以工作,将 colour 映射到符号 title,但正如警告信息所告诉我们的那样,此函数已被弃用。

为了完整起见,让我们看看 aes(color = my_col),你明智地没有尝试:

aes(color = my_col)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `my_col`

当然,aes 函数只是捕获了 符号 my_col,这不会起作用,因为你的数据框中没有叫做 my_col 的列。

现在我们继续尝试使用非引用的方法。!!{{ 运算符都评估其操作数并将其内联到 AST 中,因此它们都评估为 字符串 &quot;title&quot;,而不是 符号 title。请注意引号:

aes(color = !!my_col)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; &quot;title&quot;

#&gt; aes(color = {{my_col}})
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; &quot;title&quot;

这意味着你的图上的所有点都将具有相同的颜色,因为它们都映射到一个单一的字符串,该字符串将被循环使用到数据的长度。

你可能认为 symenquo 应该可以工作,但问题是,没有非引用运算符,整个 未评估的表达式 被捕获。看看使用 symenquo 会发生什么:

aes(color = sym(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `sym(my_col)`

aes(color = enquo(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `enquo(my_col)`

现在我们正在尝试将颜色映射到一个 调用,这甚至没有意义,ggplot 将抛出一个错误。我们需要将我们的映射映射到一个符号,而不是一个调用。但是,我们可以使用 !! 运算符来评估和内联 sym(my_col) 以获得符号 title。如果我们使用 enquo,那么我们将再次得到一个字符串作为评估的输出,而 {{ 运算符只能用于名称,而不是调用,所以解决方法是:

aes(color = !!sym(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

实际上,我更喜欢这种方法,这与推荐的方法相比,推荐的方法会产生:

aes(color = .data[my_col])
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `.data[my_col]`

这也可以正常工作,但只因为 ggplot 识别到 .data 代词并以不同的方式处理它。

还有其他选项。任何能够得到正确符号的方法都可以工作:

aes(color = !!str2lang(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

aes(color = !!as.name(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

甚至可以只使用基本的 R 函数从头开始构建美学映射,如果你真的想要:

ggplot(cubbins, 
  structure(
    list(colour = structure(
      `attr&lt;-`(call(&quot;~&quot;, str2lang(my_col)), &quot;.Environment&quot;, .GlobalEnv), 
      class = c(&quot;quosure&quot;, &quot;formula&quot;)), 
    x = structure(
      `attr&lt;-`(call(&quot;~&quot;, str2lang(&quot;x&quot;)), &quot;.Environment&quot;, .GlobalEnv), 
      class = c(&quot;quosure&quot;, &quot;formula&quot;)),
    y = structure(
      `attr&lt;-`(call(&quot;~&quot;, str2lang(&quot;y&quot;)), &quot;.Environment&quot;, .GlobalEnv), 
      class = c(&quot;quosure&quot;, &quot;formula&quot;))
    ), 
    class = &quot;uneval&quot;)) + geom_point()

以变量命名的列美学,如何在美学中使用括号运算符?

英文:

We can actually use the aes function on its own to get a better handle on what's going on.

Essentially, we want something that gives us the same output as:

library(ggplot2)

aes(colour = title)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

Here, the aesthetics colour is linked to the symbol title. But we want to achieve this using a stored, pre-defined character string:

my_col &lt;- &quot;title&quot;

Previously, we could simply have used aes_string:

aes_string(color = my_col)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`
#&gt; Warning message:
#&gt; `aes_string()` was deprecated in ggplot2 3.0.0.
#&gt; i Please use tidy evaluation ideoms with `aes()`

This works, mapping colour to the symbol title, but as the warning tells us, this function is deprecated.

For completeness, let's look at aes(color = my_col), which you sensibly didn't even try

aes(color = my_col)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `my_col`

Of course, the aes function has simply captured the symbol my_col, which won't work because you have no column called my_col in your data frame.

Now we move on to the attempts using unquoting. Both the !! and {{ operators evaluate their operand and inline it in the AST, so they both evaluate to the string &quot;title&quot;, not the symbol title. Note the quotation marks:

aes(color = !!my_col)
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; &quot;title&quot;

#&gt; aes(color = {{my_col}})
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; &quot;title&quot;

This means that all the points on your plot will be given the same colour, since they are all mapped to a single string, which will just be recycled to the length of the data.

You might think that sym or enquo should work, but the problem is that without an unquoting operator, the whole unevaluated expression is captured. Look what happens with sym and enquo:

aes(color = sym(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `sym(my_col)`

aes(color = enquo(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `enquo(my_col)`

Now we are trying to map colour to a call, which doesn't even make sense, and ggplot will just throw an error. We need our mapping to be to a symbol, not a call. However, we can evaluate and inline sym(my_col) using the !! operator to get the symbol title. If we use enquo then we will again get a string as the output of the evaluation, and the {{ operator only works on names, not calls, so the solution is:

aes(color = !!sym(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

I actually prefer this to the recommended method, which results in:

aes(color = .data[my_col])
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `.data[my_col]`

This works perfectly well, but only because ggplot recognises the .data pronoun and treats it differently.

There are other options. Anything that gets us the correct symbol will work:

aes(color = !!str2lang(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

aes(color = !!as.name(my_col))
#&gt; Aesthetic mapping: 
#&gt; * `colour` -&gt; `title`

And it's even possible to build the aesthetic mapping from scratch using only base R functions if you really wanted to:

ggplot(cubbins, 
  structure(
    list(colour = structure(
      `attr&lt;-`(call(&quot;~&quot;, str2lang(my_col)), &quot;.Environment&quot;, .GlobalEnv), 
      class = c(&quot;quosure&quot;, &quot;formula&quot;)), 
    x = structure(
      `attr&lt;-`(call(&quot;~&quot;, str2lang(&quot;x&quot;)), &quot;.Environment&quot;, .GlobalEnv), 
      class = c(&quot;quosure&quot;, &quot;formula&quot;)),
    y = structure(
      `attr&lt;-`(call(&quot;~&quot;, str2lang(&quot;y&quot;)), &quot;.Environment&quot;, .GlobalEnv), 
      class = c(&quot;quosure&quot;, &quot;formula&quot;))
    ), 
    class = &quot;uneval&quot;)) + geom_point()

以变量命名的列美学,如何在美学中使用括号运算符?

huangapple
  • 本文由 发表于 2023年7月14日 05:54:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76683473.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定