ggplot2 - 比例尺在哪里建造?
ggplot2 - where are the scales being built?
我想看看在哪里将因子值转换为数值。我试图通过简单地在各处添加 print
语句来实现这一点...
geom_tile2 <- function(mapping = NULL, data = NULL,
stat = "identity2", position = "identity",
...,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomTile2,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = na.rm,
...
)
)
}
GeomTile2 <- ggproto("GeomTile2", GeomRect,
extra_params = c("na.rm", "width", "height"),
setup_data = function(data, params) {
print(data)
data$width <- data$width %||% params$width %||% resolution(data$x, FALSE)
data$height <- data$height %||% params$height %||% resolution(data$y, FALSE)
transform(data,
xmin = x - width / 2, xmax = x + width / 2, width = NULL,
ymin = y - height / 2, ymax = y + height / 2, height = NULL
)
},
default_aes = aes(fill = "grey20", colour = NA, size = 0.1, linetype = 1,
alpha = NA),
required_aes = c("x", "y"),
draw_key = draw_key_polygon
)
和
stat_identity2 <- function(mapping = NULL, data = NULL,
geom = "point", position = "identity",
...,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = StatIdentity2,
geom = geom,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = FALSE,
...
)
)
}
StatIdentity2 <- ggproto("StatIdentity2", Stat,
setup_data = function(data, params) {
print(data)
data
},
compute_layer = function(data, scales, params) {
print(data)
print("stat end")
data
}
)
但是当我 运行 例如
ggplot(data.frame(x = rep(c("y", "n"), 6), y = rep(c("y", "n"), each = 6)),
aes(x = x, y = y)) +
geom_tile2()
x
和 y
是 stat
中的 setup_data
函数及以后的数字。查看包的 Github 回购协议,我似乎无法找到坐标转换实际发生的位置?
TL;DR
x / y 的因子到数值比例的转换由 ggplot2:::Layout$map_position()
函数完成,当前代码在这里:layout.r
详细解释
我通常会想到使用 ggplot2
包创建绘图的步骤分为两个阶段:
- 地块施工。这是当一个新的 ggplot 对象(通过
ggplot()
初始化)和所有 geom_*
/ stat_*
/ facet_*
/ scale_*
/ coord_*
图层添加到它被组合成一个 ggplot 对象。如果我们写类似 p <- ggplot(mpg, aes(class)) + geom_bar()
的东西,我们就停在这里。 GH代码在这里:plot-construction.r
- 绘图渲染。这是将组合的 ggplot 对象转换为可以渲染的对象(通过
ggplot_build()
)并进一步转换为 grobs 的 gtable(通过 ggplot_gtable()
)。这通常通过 ggplot 对象的 print / plot 方法触发(参见 here), but we can also use ggplotGrob()
, which returns the converted gtable object directly, minus the printing step. GH code for ggplot_build
/ ggplot_gtable
here: plot-build.r
根据我的经验,我们可能有兴趣调整的大部分步骤都在绘图渲染阶段,运行在 ggplot2:::ggplot_build.ggplot
/ ggplot2:::ggplot_gtable.ggplot_built
上进行调试是一个很好的方法弄清楚事情发生的第一步。
在这种情况下,在运行宁
之后
debugonce(ggplot2:::ggplot_build.ggplot)
ggplot(data.frame(x = rep(c("y", "n"), 6),
y = rep(c("y", "n"), each = 6)),
aes(x = x, y = y)) +
geom_tile() # no need to use the self-defined geom_tile2 here
我们开始单步执行函数:
> ggplot2:::ggplot_build.ggplot
function (plot)
{
plot <- plot_clone(plot)
if (length(plot$layers) == 0) {
plot <- plot + geom_blank()
}
layers <- plot$layers
layer_data <- lapply(layers, function(y) y$layer_data(plot$data))
scales <- plot$scales
by_layer <- function(f) {
out <- vector("list", length(data))
for (i in seq_along(data)) {
out[[i]] <- f(l = layers[[i]], d = data[[i]])
}
out
}
data <- layer_data
data <- by_layer(function(l, d) l$setup_layer(d, plot))
layout <- create_layout(plot$facet, plot$coordinates)
data <- layout$setup(data, plot$data, plot$plot_env)
data <- by_layer(function(l, d) l$compute_aesthetics(d, plot))
data <- lapply(data, scales_transform_df, scales = scales)
scale_x <- function() scales$get_scales("x")
scale_y <- function() scales$get_scales("y")
layout$train_position(data, scale_x(), scale_y())
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))
layout$reset_scales()
layout$train_position(data, scale_x(), scale_y())
layout$setup_panel_params()
data <- layout$map_position(data)
npscales <- scales$non_position_scales()
if (npscales$n() > 0) {
lapply(data, scales_train_df, scales = npscales)
data <- lapply(data, scales_map_df, scales = npscales)
}
data <- by_layer(function(l, d) l$compute_geom_2(d))
data <- by_layer(function(l, d) l$finish_statistics(d))
data <- layout$finish_data(data)
structure(list(data = data, layout = layout, plot = plot),
class = "ggplot_built")
}
在调试模式下,我们可以在每一步后检查 str(data[[i]])
,检查与 ggplot 对象的层 i
关联的数据(在本例中为 i
= 1,因为只有 1 个 geom 层)。
Browse[2]>
debug: data <- lapply(data, scales_transform_df, scales = scales)
Browse[2]>
debug: scale_x <- function() scales$get_scales("x")
Browse[2]> str(data[[1]]) # still factor after scale_transform_df step
'data.frame': 12 obs. of 4 variables:
$ x : Factor w/ 2 levels "n","y": 2 1 2 1 2 1 2 1 2 1 ...
$ y : Factor w/ 2 levels "n","y": 2 2 2 2 2 2 1 1 1 1 ...
$ PANEL: Factor w/ 1 level "1": 1 1 1 1 1 1 1 1 1 1 ...
$ group: int 4 2 4 2 4 2 3 1 3 1 ...
..- attr(*, "n")= int 4
# ... omitted
debug: data <- layout$map_position(data)
Browse[2]>
debug: data <- by_layer(function(l, d) l$compute_statistic(d, layout))
Browse[2]> str(data[[1]]) # numerical after map_position step
'data.frame': 12 obs. of 4 variables:
$ x : int 2 1 2 1 2 1 2 1 2 1 ...
$ y : int 2 2 2 2 2 2 1 1 1 1 ...
$ PANEL: Factor w/ 1 level "1": 1 1 1 1 1 1 1 1 1 1 ...
$ group: int 4 2 4 2 4 2 3 1 3 1 ...
..- attr(*, "n")= int 4
Stat*
的 setup_data
由 data <- by_layer(function(l, d) l$compute_statistic(d, layout))
触发(参见 ggplot2:::Layer$compute_statistic
here),这发生在 在这一步之后。这就是为什么当你在StatIdentity2$setup_data
中插入打印语句时,数据已经是数值形式了。
(而 Geom*
的 setup_data
是由 data <- by_layer(function(l, d) l$compute_geom_1(d))
触发的,甚至更晚。)
将 map_position
识别为事情发生的步骤后,我们可以再次 运行 调试模式并进入此函数以查看到底发生了什么。在这一点上,恐怕我真的不知道你的用例是什么,所以我不得不让你自己去做。
我想看看在哪里将因子值转换为数值。我试图通过简单地在各处添加 print
语句来实现这一点...
geom_tile2 <- function(mapping = NULL, data = NULL,
stat = "identity2", position = "identity",
...,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomTile2,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = na.rm,
...
)
)
}
GeomTile2 <- ggproto("GeomTile2", GeomRect,
extra_params = c("na.rm", "width", "height"),
setup_data = function(data, params) {
print(data)
data$width <- data$width %||% params$width %||% resolution(data$x, FALSE)
data$height <- data$height %||% params$height %||% resolution(data$y, FALSE)
transform(data,
xmin = x - width / 2, xmax = x + width / 2, width = NULL,
ymin = y - height / 2, ymax = y + height / 2, height = NULL
)
},
default_aes = aes(fill = "grey20", colour = NA, size = 0.1, linetype = 1,
alpha = NA),
required_aes = c("x", "y"),
draw_key = draw_key_polygon
)
和
stat_identity2 <- function(mapping = NULL, data = NULL,
geom = "point", position = "identity",
...,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = StatIdentity2,
geom = geom,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
na.rm = FALSE,
...
)
)
}
StatIdentity2 <- ggproto("StatIdentity2", Stat,
setup_data = function(data, params) {
print(data)
data
},
compute_layer = function(data, scales, params) {
print(data)
print("stat end")
data
}
)
但是当我 运行 例如
ggplot(data.frame(x = rep(c("y", "n"), 6), y = rep(c("y", "n"), each = 6)),
aes(x = x, y = y)) +
geom_tile2()
x
和 y
是 stat
中的 setup_data
函数及以后的数字。查看包的 Github 回购协议,我似乎无法找到坐标转换实际发生的位置?
TL;DR
x / y 的因子到数值比例的转换由 ggplot2:::Layout$map_position()
函数完成,当前代码在这里:layout.r
详细解释
我通常会想到使用 ggplot2
包创建绘图的步骤分为两个阶段:
- 地块施工。这是当一个新的 ggplot 对象(通过
ggplot()
初始化)和所有geom_*
/stat_*
/facet_*
/scale_*
/coord_*
图层添加到它被组合成一个 ggplot 对象。如果我们写类似p <- ggplot(mpg, aes(class)) + geom_bar()
的东西,我们就停在这里。 GH代码在这里:plot-construction.r - 绘图渲染。这是将组合的 ggplot 对象转换为可以渲染的对象(通过
ggplot_build()
)并进一步转换为 grobs 的 gtable(通过ggplot_gtable()
)。这通常通过 ggplot 对象的 print / plot 方法触发(参见 here), but we can also useggplotGrob()
, which returns the converted gtable object directly, minus the printing step. GH code forggplot_build
/ggplot_gtable
here: plot-build.r
根据我的经验,我们可能有兴趣调整的大部分步骤都在绘图渲染阶段,运行在 ggplot2:::ggplot_build.ggplot
/ ggplot2:::ggplot_gtable.ggplot_built
上进行调试是一个很好的方法弄清楚事情发生的第一步。
在这种情况下,在运行宁
之后debugonce(ggplot2:::ggplot_build.ggplot)
ggplot(data.frame(x = rep(c("y", "n"), 6),
y = rep(c("y", "n"), each = 6)),
aes(x = x, y = y)) +
geom_tile() # no need to use the self-defined geom_tile2 here
我们开始单步执行函数:
> ggplot2:::ggplot_build.ggplot
function (plot)
{
plot <- plot_clone(plot)
if (length(plot$layers) == 0) {
plot <- plot + geom_blank()
}
layers <- plot$layers
layer_data <- lapply(layers, function(y) y$layer_data(plot$data))
scales <- plot$scales
by_layer <- function(f) {
out <- vector("list", length(data))
for (i in seq_along(data)) {
out[[i]] <- f(l = layers[[i]], d = data[[i]])
}
out
}
data <- layer_data
data <- by_layer(function(l, d) l$setup_layer(d, plot))
layout <- create_layout(plot$facet, plot$coordinates)
data <- layout$setup(data, plot$data, plot$plot_env)
data <- by_layer(function(l, d) l$compute_aesthetics(d, plot))
data <- lapply(data, scales_transform_df, scales = scales)
scale_x <- function() scales$get_scales("x")
scale_y <- function() scales$get_scales("y")
layout$train_position(data, scale_x(), scale_y())
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))
layout$reset_scales()
layout$train_position(data, scale_x(), scale_y())
layout$setup_panel_params()
data <- layout$map_position(data)
npscales <- scales$non_position_scales()
if (npscales$n() > 0) {
lapply(data, scales_train_df, scales = npscales)
data <- lapply(data, scales_map_df, scales = npscales)
}
data <- by_layer(function(l, d) l$compute_geom_2(d))
data <- by_layer(function(l, d) l$finish_statistics(d))
data <- layout$finish_data(data)
structure(list(data = data, layout = layout, plot = plot),
class = "ggplot_built")
}
在调试模式下,我们可以在每一步后检查 str(data[[i]])
,检查与 ggplot 对象的层 i
关联的数据(在本例中为 i
= 1,因为只有 1 个 geom 层)。
Browse[2]>
debug: data <- lapply(data, scales_transform_df, scales = scales)
Browse[2]>
debug: scale_x <- function() scales$get_scales("x")
Browse[2]> str(data[[1]]) # still factor after scale_transform_df step
'data.frame': 12 obs. of 4 variables:
$ x : Factor w/ 2 levels "n","y": 2 1 2 1 2 1 2 1 2 1 ...
$ y : Factor w/ 2 levels "n","y": 2 2 2 2 2 2 1 1 1 1 ...
$ PANEL: Factor w/ 1 level "1": 1 1 1 1 1 1 1 1 1 1 ...
$ group: int 4 2 4 2 4 2 3 1 3 1 ...
..- attr(*, "n")= int 4
# ... omitted
debug: data <- layout$map_position(data)
Browse[2]>
debug: data <- by_layer(function(l, d) l$compute_statistic(d, layout))
Browse[2]> str(data[[1]]) # numerical after map_position step
'data.frame': 12 obs. of 4 variables:
$ x : int 2 1 2 1 2 1 2 1 2 1 ...
$ y : int 2 2 2 2 2 2 1 1 1 1 ...
$ PANEL: Factor w/ 1 level "1": 1 1 1 1 1 1 1 1 1 1 ...
$ group: int 4 2 4 2 4 2 3 1 3 1 ...
..- attr(*, "n")= int 4
Stat*
的 setup_data
由 data <- by_layer(function(l, d) l$compute_statistic(d, layout))
触发(参见 ggplot2:::Layer$compute_statistic
here),这发生在 在这一步之后。这就是为什么当你在StatIdentity2$setup_data
中插入打印语句时,数据已经是数值形式了。
(而 Geom*
的 setup_data
是由 data <- by_layer(function(l, d) l$compute_geom_1(d))
触发的,甚至更晚。)
将 map_position
识别为事情发生的步骤后,我们可以再次 运行 调试模式并进入此函数以查看到底发生了什么。在这一点上,恐怕我真的不知道你的用例是什么,所以我不得不让你自己去做。