有什么理由不使用 ggplot() + aes() + geom_() 语法吗?

Are there any reasons not to use ggplot() + aes() + geom_() syntax?

我是一个相当有经验的 ggplot2 用户,并将它教给大学生。但是,我只是遇到了一个使用以下语法的示例:

ggplot(mtcars) + aes(cyl) + geom_histogram()

这比在 ggplot()geom_ 中指定 aes 更符合添加层的逻辑......但它似乎没有在任何地方记录ggplot2 帮助。因此,我想知道是否有任何原因限制/不应使用此语法? (显然,我发现如果要在 geom 之间有所不同,则需要在 geom 中指定它...)

TL;DR

我看不出有任何不使用此模式的充分理由,但文档中推荐了其他模式,但没有详细说明。

+ aes() 是做什么的?

ggplot 有两种美学类型:

  • 默认值(通常在 ggplot() 内提供),以及
  • geom_*() 特定美学

如果inherit.aes = TRUE设置在geoms内部,那么这两种美学在最终的情节中结合在一起。如果未设置默认美学,则必须设置 geom_* 特定美学。

使用 ggplot(df) + aes(x, y) 改变 默认 美学。

这记录在 ?"+.gg":

An aes() object replaces the default aesthetics.

有什么理由不使用它吗?

我看不出有什么强烈的理由不这样做。但是,在 ?ggplot 的文档中指出:

There are three common ways to invoke ggplot():

  • ggplot(df, aes(x, y, other aesthetics))
  • ggplot(df)
  • ggplot()

The first method is recommended if all layers use the same data and the same set of aesthetics.

据我所知,+ aes() 的典型用例是所有层都使用相同的美学。所以文档推荐通常的模式 ggplot(df, aes(x, y, other aesthetics)),但我找不到详细说明原因。

进一步:即使绘图看起来相同,但 ggplot(df, aes()ggplot(df) + aes() 返回的对象并不相同,因此可能存在一些边缘情况,其中一种模式会导致错误或不同的模式情节。

您可以看到此代码的许多小差异:

library(ggplot2)
a <- ggplot(mtcars, aes(hp, mpg)) + geom_point()
b <- ggplot(mtcars) + aes(hp, mpg) + geom_point()

waldo::compare(a, b, x_arg = "a", y_arg = "b")

这是一个接近 opinion-based 的问题,但我认为它是 on-topic,因为它有助于阐明 ggplot 调用的语法和结构。

从某种意义上说,您自己已经回答了这个问题:

it does not seem to be documented anywhere in the ggplot2 help

这个,以及在线教程、博客和 SO 答案中几乎没有示例,足以成为不以这种方式使用 aes 的充分理由(或者至少不教人们以这种方式使用它) .这可能会导致新用户感到困惑和沮丧。

This fits a lot better into the logic of adding up layers

有点正确,但可能有点误导。它实际上做的是指定 default 美学映射,后续层将从 ggplot 对象本身继承。它应该被视为基础图的核心 部分 ,连同默认数据对象,因此“属于”初始 ggplot 调用,而不是正在被调用的东西添加或分层到图上。如果您创建一个没有数据和映射的默认 ggplot 对象,插槽仍然存在,但包含豁免而不是 NULL :

p <- ggplot()

p$mapping
#> Aesthetic mapping: 
#> <empty>

p$data
#> list()
#> attr(,"class")
#> [1] "waiver"

请注意,与比例和 co-ordinate 对象不同,您可能会争辩说它们也是如此,数据和美学映射没有默认值。

这是否意味着您应该永远不要使用这种语法?不,但对于精通 ggplot 的人来说,它应该被认为是一个高级技巧。我发现最常见的用例是更改在扩展包中创建的 ggplot 的映射,例如 ggsurvplotggraph,其中绘图函数使用 ggplot 周围的包装器。它还可以用于快速创建具有相同主题和色阶的多个绘图:

p <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) + 
  geom_point(aes(color = Species)) +
  theme_light()

library(patchwork)

p + (p + aes(Petal.Width, Petal.Length))

所以最重要的是,如果你愿意,你可以使用它,但最好避免教给初学者