r - 将额外参数传递给 ggplot2 geoms : using ellipsis (. ..)

标签 r ggplot2

这是 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)

省略点的绘制。

但是,因为我想对不同的新几何对象使用通用函数,所以我更愿意定义 draw_panel 函数而不显式命名 showpoints 参数,而是使用省略号。我尝试了以下操作(所有其余代码保持不变),它不起作用:

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()
  }
}

返回的错误是:

Error in if (showpoints) { : argument is of length zero

当我执行以下操作时,会发生一件有趣的事情:

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()
  }
}

出于某种原因,showpoints 现在始终为 FALSE。但是,... 列表为 NULL。这完全出乎我的意料。

这一切都非常令人困惑,并且肯定它的行为并不像我预期的那样。在这种情况下可以使用省略号吗?如果是,那么如何?这里发生了什么?

编辑:按照Gilean0709的建议,我尝试从geom_simple_point的定义中删除showpoints:

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, ...)
  )   
}

这仍然给出相同的错误(showpoints 为 NULL)。

最佳答案

这与参数分配到统计数据、几何图形和位置的方式有关。如果我们看一下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 甚至是一开始提供的参数。

希望这有帮助!

关于r - 将额外参数传递给 ggplot2 geoms : using ellipsis (. ..),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57088809/

相关文章:

r - 我们可以在linux下安装 `.zip` R包吗?

重新排列行和列+使用R中的平均分数

r - 如何使用 R 动态回归和预测多个项目?

r - 'closure' 类型的 ggplot2 条形图对象不可子集化

r - 每个方面从最高到最低对 geom_lines 进行排序

r - 在 plyr 或 dplyr 中调试 - 查看哪个组

r - 绘制带有悬挂叶子的水平树状图? (右)

r - 仅在 Shinyapps.io 上为特定的 Shiny 应用程序设置不同的语言环境

r - 用于列表中大量数据的面网格

r - 如何 reshape 数据以在 R 中创建多变量箱线图的各个方面