使用自己的 geoms 扩展 ggplot:适应默认比例
Extending ggplot with own geoms: Adapt default scale
背景
阅读 and the corresponding vignette 后,我试图了解如何扩展 ggplot
。
一言以蔽之
我明白,这些部分是如何组合在一起的,但我遗漏了一个重要信息:ggplot
如何确定轴的默认范围?
代码
考虑以下玩具示例:
library(grid)
library(ggplot2)
GeomFit <- ggproto("GeomFit", GeomBar,
required_aes = c("x", "y"),
setup_data = .subset2(GeomBar, "setup_data"),
draw_panel = function(self, data, panel_scales, coord, width = NULL) {
bars <- ggproto_parent(GeomBar, self)$draw_panel(data,
panel_scales,
coord)
coords <- coord$transform(data, panel_scales)
tg <- textGrob("test", coords$x, coords$y * 2 - coords$ymin)
grobTree(bars, tg)
}
)
geom_fit <- function(mapping = NULL, data = NULL,
stat = "count", position = "stack",
...,
width = NULL,
binwidth = NULL,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomFit,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
width = width,
na.rm = na.rm,
...
)
)
}
set.seed(1234567)
data_gd <- data.frame(x = letters[1:5],
y = 1:5)
p <- ggplot(data = data_gd, aes(x = x, y = y, fill = x)) +
geom_fit(stat = "identity")
产生这个情节:
问题
如您所见,有些文字没有显示。我假设 ggplot
以某种方式计算轴的范围,因为它不知道我的 textGrob
需要额外的 space。我该如何解决? (期望的结果相当于 p + expand_limits(y = 10)
NB. 当然,我可以通过要求添加手动秤将问题推给最终用户。但理想情况下,我希望正确设置秤。
尤里卡
感谢@Z.Lin 在如何调试 ggplot
代码方面的出色帮助,发现了一个丑陋的 hack。这是我想出这个相当丑陋的技巧以供将来参考的方法:
我是怎么到那里的
在调试 debug(ggplot2:::ggplot_build.ggplot)
时,我了解到可以在 FacetNull$train_scales
的某处找到罪魁祸首(在我没有刻面的情节中,
FacetGrid
等其他方面以类似的方式工作)。这是我通过 debug(environment(FacetNull$train_scales)$f)
学到的,而这又是我在 .
中学到的
一旦我能够调试 ggproto
对象,我就可以看到在这个函数中训练了尺度。基本上,该功能着眼于与特定比例相关的美学(不知道这些信息最初是在哪里设置的,有人有什么想法吗?)并查看这些美学中的哪些存在于图层数据中。
我看到字段 ymax_final
(这是 - 根据 this table - 仅用于 stat_boxplot
)是考虑用于设置比例的字段之一。有了这条信息,通过将 setup_data
中的这个字段设置为适当的值,很容易找到一个丑陋的 hack。
代码
GeomFit <- ggproto("GeomFit", GeomBar,
required_aes = c("x", "y"),
setup_data = function(self, data, params) {
data <- ggproto_parent(GeomBar, self)$setup_data(data, params)
## here's the hack: add a field which is not needed in this geom,
## but which is used by Facet*$train_scales which
## eventually sets up the scales
data$ymax_final <- 2 * data$y
data
},
draw_panel = function(self, data, panel_scales, coord, width = NULL) {
bars <- ggproto_parent(GeomBar, self)$draw_panel(data,
panel_scales,
coord)
coords <- coord$transform(data, panel_scales)
tg <- textGrob("test", coords$x, coords$y * 2 - coords$ymin)
grobTree(bars, tg)
}
)
结果
未决问题
如果不手动定义(轴)刻度,在哪里设置?我猜那里设置了与缩放相关的字段。
背景
阅读 ggplot
。
一言以蔽之
我明白,这些部分是如何组合在一起的,但我遗漏了一个重要信息:ggplot
如何确定轴的默认范围?
代码
考虑以下玩具示例:
library(grid)
library(ggplot2)
GeomFit <- ggproto("GeomFit", GeomBar,
required_aes = c("x", "y"),
setup_data = .subset2(GeomBar, "setup_data"),
draw_panel = function(self, data, panel_scales, coord, width = NULL) {
bars <- ggproto_parent(GeomBar, self)$draw_panel(data,
panel_scales,
coord)
coords <- coord$transform(data, panel_scales)
tg <- textGrob("test", coords$x, coords$y * 2 - coords$ymin)
grobTree(bars, tg)
}
)
geom_fit <- function(mapping = NULL, data = NULL,
stat = "count", position = "stack",
...,
width = NULL,
binwidth = NULL,
na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomFit,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
width = width,
na.rm = na.rm,
...
)
)
}
set.seed(1234567)
data_gd <- data.frame(x = letters[1:5],
y = 1:5)
p <- ggplot(data = data_gd, aes(x = x, y = y, fill = x)) +
geom_fit(stat = "identity")
产生这个情节:
问题
如您所见,有些文字没有显示。我假设 ggplot
以某种方式计算轴的范围,因为它不知道我的 textGrob
需要额外的 space。我该如何解决? (期望的结果相当于 p + expand_limits(y = 10)
NB. 当然,我可以通过要求添加手动秤将问题推给最终用户。但理想情况下,我希望正确设置秤。
尤里卡
感谢@Z.Lin 在如何调试 ggplot
代码方面的出色帮助,发现了一个丑陋的 hack。这是我想出这个相当丑陋的技巧以供将来参考的方法:
我是怎么到那里的
在调试 debug(ggplot2:::ggplot_build.ggplot)
时,我了解到可以在 FacetNull$train_scales
的某处找到罪魁祸首(在我没有刻面的情节中,
FacetGrid
等其他方面以类似的方式工作)。这是我通过 debug(environment(FacetNull$train_scales)$f)
学到的,而这又是我在
一旦我能够调试 ggproto
对象,我就可以看到在这个函数中训练了尺度。基本上,该功能着眼于与特定比例相关的美学(不知道这些信息最初是在哪里设置的,有人有什么想法吗?)并查看这些美学中的哪些存在于图层数据中。
我看到字段 ymax_final
(这是 - 根据 this table - 仅用于 stat_boxplot
)是考虑用于设置比例的字段之一。有了这条信息,通过将 setup_data
中的这个字段设置为适当的值,很容易找到一个丑陋的 hack。
代码
GeomFit <- ggproto("GeomFit", GeomBar,
required_aes = c("x", "y"),
setup_data = function(self, data, params) {
data <- ggproto_parent(GeomBar, self)$setup_data(data, params)
## here's the hack: add a field which is not needed in this geom,
## but which is used by Facet*$train_scales which
## eventually sets up the scales
data$ymax_final <- 2 * data$y
data
},
draw_panel = function(self, data, panel_scales, coord, width = NULL) {
bars <- ggproto_parent(GeomBar, self)$draw_panel(data,
panel_scales,
coord)
coords <- coord$transform(data, panel_scales)
tg <- textGrob("test", coords$x, coords$y * 2 - coords$ymin)
grobTree(bars, tg)
}
)
结果
未决问题
如果不手动定义(轴)刻度,在哪里设置?我猜那里设置了与缩放相关的字段。