将额外的参数传递给ggplot2 geoms:使用省略号(...) [英] Passing extra arguments to ggplot2 geoms: using ellipsis (...)

查看:54
本文介绍了将额外的参数传递给ggplot2 geoms:使用省略号(...)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是对问题.我正在尝试使用自定义参数编写自己的几何.我的问题是如何使用省略号(...)传递额外的参数.

This is a follow-up on this question. I am trying to write my own geoms with custom parameters. My question is how to use ellipsis (...) to pass extra arguments.

以下示例代码按预期工作:

The following example code works as expected:

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 函数.我尝试了以下操作(所有代码的其余部分保持不变),这是行不通的:

However, because I want to use a generic function for different new geoms, I would prefer to define the draw_panel function without explicitly naming the showpoints parameter, but using ellipsis. I tried the following (all the remainder of the code remains identical), it doesn't work:

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){:参数长度为零时出错

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

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

An interesting thing happens when I do the following:

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.这是完全出乎意料的.

For some reason, showpoints is now always FALSE. However, the ... list is NULL. This is completely unexpected.

这一切都非常令人困惑,并且一定不能像我期望的那样表现.在这种情况下可以使用省略号吗?如果是,那怎么办?这是怎么回事?

This is all very confusing and for certain it does not behave like I would expected. Is it possible to use ellipsis in this context? If yes, then how? What is happening here?

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

Following the suggestion of Gilean0709 I tried to remove showpoints from the definition of 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).

This still gives the same error (showpoints is NULL).

推荐答案

这与将参数分布到统计信息,地理数据和位置的方式有关.如果我们看一下 layer()的代码:

This has to do with the ways the parameters are being distributed to stats, geoms and positions. If we look at the code of 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/统计信息/aes不了解 ... 中的元素.

We can see that the parameters you put in params (including ...) are being distributed across the different aspects of a layer based on the names of the params. Anything leftover (extra_param) gets discarded and warned about. Since the ellipses ... is a special case that has no name in and of itself (but the elements in ... do), this gets discarded if ggplot geoms/stats/aes doesn't know about the elements in ....

现在有一个丑陋的解决方法,那就是在开始时制作一个椭圆并将其作为命名参数传递给它:

Now there is an ugly way around this, and that is to make a copy of the ellipses in the very beginning and pass that around as a named argument:

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

然后,我们可以让面板绘制功能接受此椭圆的副本作为参数:

Then, we can have the panel drawing function accept this copy of the ellipses as an argument:

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:

And update the ggproto accordingly:

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
) 

现在生成的图将按预期工作,但会发出警告,因为它已传递给 extra_param (甚至尽管从技术上讲它并不被忽略,因为它现在是 elli 的一部分).不过,您可能想在面板绘图功能中进行一些额外的检查,以确保 showpoints 甚至在开始时也是提供的参数.

And now that produces a plot that will work as intended, but it will throw the warning that it is ignoring the showpoints parameter because it get's passed to extra_param (even though technically it isn't ignored, since it is now part of elli). You probably want to code some extra checks in the panel drawing function though, to make sure that showpoints was even a provided argument in the beginning.

希望这对您有帮助!

这篇关于将额外的参数传递给ggplot2 geoms:使用省略号(...)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆