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。
我会接受以下任何一个作为答案:
- 继承可视化(也许是网络?)或指针
相同。
- 构建继承可视化的代码,或指向的指针
一样。
- 一种替代的、非视觉的方法,使它变得简单,或者至少
更容易理解和记住这样的继承和答案
关于它的具体问题。
- 一个专门列出参数默认值的列表,显示它们出现的位置和
哪些子函数继承了它们,或者产生这样一个子函数的代码
列表。
这个问题似乎是关于 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 中寻找继承模式的函数。
我经常不确定 ggplot2
中图形对象的哪些数据元素、属性和其他组件由哪些其他元素继承,以及向下流动的默认值在哪里,例如 geoms ,起源。在特定情况下,通常可以通过仔细阅读 Hadley 的 ggplot2
书来回答这些问题。但我发现对 ggplot2
中的整个继承流程进行某种可视化是很有用的,我想知道是否有人见过、创建过或知道如何创建这样的东西。同样,在一个规范级别(如 aes 或主题)中出现并被另一级别(如 geom 或 scale)继承的默认值的紧凑列表对我来说非常有用,我怀疑许多人学习如何使用 ggplot2。
我会接受以下任何一个作为答案:
- 继承可视化(也许是网络?)或指针 相同。
- 构建继承可视化的代码,或指向的指针 一样。
- 一种替代的、非视觉的方法,使它变得简单,或者至少 更容易理解和记住这样的继承和答案 关于它的具体问题。
- 一个专门列出参数默认值的列表,显示它们出现的位置和 哪些子函数继承了它们,或者产生这样一个子函数的代码 列表。
这个问题似乎是关于 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 中寻找继承模式的函数。