R,ggplot2:如何在 ggplot2 中可视化图形对象的数据、属性和其他组件的继承或流动?

R, ggplot2: How can I visualize the inheritance or flow of data, attributes, and other components of a graphical object in ggplot2?

我经常不确定 ggplot2 中图形对象的哪些数据元素、属性和其他组件由哪些其他元素继承,以及向下流动的默认值在哪里,例如 geoms ,起源。在特定情况下,通常可以通过仔细阅读 Hadley 的 ggplot2 书来回答这些问题。但我发现对 ggplot2 中的整个继承流程进行某种可视化是很有用的,我想知道是否有人见过、创建过或知道如何创建这样的东西。同样,在一个规范级别(如 aes 或主题)中出现并被另一级别(如 geom 或 scale)继承的默认值的紧凑列表对我来说非常有用,我怀疑许多人学习如何使用 ggplot2。

我会接受以下任何一个作为答案:

  1. 继承可视化(也许是网络?)或指针 相同。
  2. 构建继承可视化的代码,或指向的指针 一样。
  3. 一种替代的、非视觉的方法,使它变得简单,或者至少 更容易理解和记住这样的继承和答案 关于它的具体问题。
  4. 一个专门列出参数默认值的列表,显示它们出现的位置和 哪些子函数继承了它们,或者产生这样一个子函数的代码 列表。

这个问题似乎是关于 ggplot 包的多个级别,但我会尽力提供一些信息。在一个堆栈溢出答案中描述 ggplot 的整个继承系统几乎是不可能的,但指向正确的函数可能会帮助您入门。

在顶层,数据和美学映射都继承自主要的 ggplot 调用。在下面的代码中,geom_point() 继承映射和数据:

ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point()

除非您明确提供替代映射并将继承设置为 false:

ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point(aes(Petal.Width, Petal.Length), inherit.aes = FALSE)

接下来,在各个层级,某些默认值是从统计数据、几何图形或位置继承的。考虑以下情节:

df <- reshape2::melt(volcano)

ggplot(df, aes(Var1, Var2)) +
  geom_raster()

栅格将为深灰色,因为我们尚未指定填充贴图。您可以通过查看 geom / stat 的 ggproto 对象了解默认值:

> GeomRaster$default_aes
Aesthetic mapping: 
* `fill`  -> "grey20"
* `alpha` -> NA

> StatDensity$default_aes
Aesthetic mapping: 
* `y`    -> `stat(density)`
* `fill` -> NA

了解如何为图层指定参数的另一个关键要素是查看 layer() 代码。具体来说,这里的这一点(为清楚起见缩写):

function (geom = NULL, stat = NULL, data = NULL, mapping = NULL, 
  position = NULL, params = list(), inherit.aes = TRUE, check.aes = TRUE, 
  check.param = TRUE, show.legend = NA, key_glyph = NULL, 
  layer_class = Layer) 
{
...
  aes_params <- params[intersect(names(params), geom$aesthetics())]
  geom_params <- params[intersect(names(params), geom$parameters(TRUE))]
  stat_params <- params[intersect(names(params), stat$parameters(TRUE))]
...
  ggproto("LayerInstance", layer_class, geom = geom, geom_params = geom_params, 
    stat = stat, stat_params = stat_params, data = data, 
    mapping = mapping, aes_params = aes_params, position = position, 
    inherit.aes = inherit.aes, show.legend = show.legend)
}

其中您可以看到,无论您提供什么参数,它们都会根据 stat/geom/position 的有效参数进行检查,并分发到层的适当部分。从上次调用可以看出,创建了一个 Layer ggproto 对象。此 class 的父级未导出,但您仍然可以检查该对象内的函数。例如,如果你好奇审美是如何评价的,你可以输入:

ggplot2:::Layer$compute_aesthetics

你可以看到这里也包含了一些默认的比例尺。当然,如果不了解调用这些层函数的操作顺序,这些层的作用就没有多大意义。为此,我们可以查看绘图生成器(为清楚起见也进行了缩写):

> ggplot2:::ggplot_build.ggplot
function (plot) 
{
...
    data <- by_layer(function(l, d) l$setup_layer(d, plot))
...
    data <- by_layer(function(l, d) l$compute_aesthetics(d, plot))
    data <- lapply(data, scales_transform_df, scales = scales)
...
    data <- layout$map_position(data)
    data <- by_layer(function(l, d) l$compute_statistic(d, layout))
    data <- by_layer(function(l, d) l$map_statistic(d, plot))
    scales_add_missing(plot, c("x", "y"), plot$plot_env)
    data <- by_layer(function(l, d) l$compute_geom_1(d))
    data <- by_layer(function(l, d) l$compute_position(d, layout))
...
    data <- by_layer(function(l, d) l$compute_geom_2(d))
    data <- by_layer(function(l, d) l$finish_statistics(d))
...
    structure(list(data = data, layout = layout, plot = plot), 
        class = "ggplot_built")
}

从这里可以看出,首先设置图层,然后计算美学,然后应用比例变换,然后计算统计信息,然后计算几何的一部分,然后计算位置,最后重置几何学。

这意味着您输入的统计变换将受到比例变换的影响,但不会受到坐标变换(稍后在其他地方)的影响。

如果您仔细阅读代码,您会发现直到此时,几乎没有任何与主题相关的东西被评估(除了一些带有构面的主题评估)。正如你所看到的,构建函数returns一个对象classggplot_build,这仍然不是图形输出。主题元素的解释和 geoms 对网格图形的实际解释发生在以下函数中:

ggplot2:::ggplot_gtable.ggplot_built

执行此函数后,您将拥有一个可以由 grid::grid.draw() 解释的 gtable 对象,它将输出到您的图形设备。

不幸的是,我不太精通主题元素的继承,但正如 Jon Spring 在评论中指出的那样,文档是一个很好的起点。 希望我已经指出了在 ggplot 中寻找继承模式的函数。