这是对this问题的后续跟踪。我正在尝试使用自定义参数编写自己的几何。我的问题是如何使用省略号(...)传递额外的参数。
以下示例代码按预期工作:
draw_panel_func <- function(data, panel_params, coord, showpoints=FALSE) {
print(showpoints)
if(showpoints) {
coords <- coord$transform(data, panel_params)
grid::pointsGrob(coords$x, coords$y)
} else {
zeroGrob()
}
}
## definition of the new geom. setup_data inserts the parameter
## into data, therefore making it accessible for .draw_panel_func
GeomSimplePoint <- ggproto("GeomSimplePoint", Geom,
required_aes = c("x", "y"),
default_aes = aes(shape = 19, colour = "black"),
draw_key = draw_key_point,
extra_params = c("na.rm", "showpoints"),
draw_panel = draw_panel_func
)
geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
position = "identity", na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE, showpoints=TRUE, ...) {
layer(
geom = GeomSimplePoint, mapping = mapping, data = data, stat = stat,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(na.rm = na.rm, showpoints=showpoints, ...)
)
}
这可行,我可以打电话
ggplot(mpg, aes(displ, hwy)) + geom_simple_point(showpoints=FALSE)
省略了点的绘制。
但是,因为我想对不同的新几何使用通用函数,所以我更愿意在不显式命名showpoints参数的情况下定义draw_panel
函数,而是使用省略号。我尝试了以下操作(所有代码的其余部分保持不变),它不起作用:
draw_panel_func <- function(data, panel_params, coord, ...) {
showpoints <- list(...)$showpoints
if(showpoints) {
coords <- coord$transform(data, panel_params)
grid::pointsGrob(coords$x, coords$y)
} else {
zeroGrob()
}
}
返回的错误是:
if(showpoints){:参数长度为零时出错
执行以下操作时会发生一件有趣的事情:
draw_panel_func <- function(data, panel_params, coord, showpoints=FALSE, ...) {
#showpoints <- list(...)$showpoints
if(showpoints) {
coords <- coord$transform(data, panel_params)
grid::pointsGrob(coords$x, coords$y)
} else {
zeroGrob()
}
}
由于某些原因,显示点现在始终为FALSE。但是,...
列表为NULL。这是完全出乎意料的。
这一切都非常令人困惑,并且某些情况下不会像我预期的那样运行。在这种情况下可以使用省略号吗?如果是,那怎么办?这是怎么回事?
编辑:按照Gilean0709的建议,我尝试从showpoints
的定义中删除geom_simple_point
:
geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
position = "identity", na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE, ...) {
layer(
geom = GeomSimplePoint, mapping = mapping, data = data, stat = stat,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(na.rm = na.rm, ...)
)
}
这仍然会产生相同的错误(显示点为NULL)。
答案 0 :(得分:1)
这与将参数分配到统计信息,地理信息和位置的方式有关。如果我们看一下layer()
的代码:
function(arguments){
...some_body...
params <- rename_aes(params)
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))]
all <- c(geom$parameters(TRUE), stat$parameters(TRUE), geom$aesthetics())
extra_param <- setdiff(names(params), all)
if (check.param && length(extra_param) > 0) {
warning("Ignoring unknown parameters: ", paste(extra_param,
collapse = ", "), call. = FALSE, immediate. = TRUE)
}
...some_more_body...
}
我们可以看到,根据参数名称,您在params
中输入的参数(包括...
)已分布在图层的各个方面。剩下的任何东西(extra_param
)都将被丢弃并发出警告。由于省略号...
是一个特例,本身没有名称(但...
中的元素本身没有名称),因此,如果ggplot geoms / stats / aes不知道该元素,则将其丢弃在...
中。
现在有一个丑陋的解决方法,那就是在开始时制作一个椭圆并将其作为命名参数传递给它:
geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
position = "identity", na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE, ...) {
elli <- list(...)
layer(
geom = GeomSimplePoint, mapping = mapping, data = data, stat = stat,
position = position, show.legend = show.legend, inherit.aes = inherit.aes,
params = list(na.rm = na.rm, elli = elli, ...)
)
}
然后,我们可以让面板绘制功能接受该椭圆的副本作为参数:
draw_panel_func <- function(data, panel_params, coord, elli) {
if(elli$showpoints) {
coords <- coord$transform(data, panel_params)
grid::pointsGrob(coords$x, coords$y)
} else {
zeroGrob()
}
}
并相应地更新ggproto:
GeomSimplePoint <- ggproto("GeomSimplePoint", Geom,
required_aes = c("x", "y"),
default_aes = aes(shape = 19, colour = "black"),
draw_key = draw_key_point,
extra_params = c("na.rm", "elli"),
draw_panel = draw_panel_func
)
现在生成的图将按预期工作,但会发出警告,因为它已传递给showpoints
(因为从技术上讲不是这样),它忽略了extra_param
参数被忽略,因为它现在是elli
的一部分)。不过,您可能想在面板绘图功能中进行一些额外的检查,以确保showpoints
甚至在开始时也是提供的参数。
希望这对您有帮助!