【问题标题】:How can I pass a variable through a quoted expression into a function that returns a function using that value?如何通过带引号的表达式将变量传递给使用该值返回函数的函数?
【发布时间】:2018-09-18 07:09:29
【问题描述】:

这是一个例子:

library(ggplot2)
library(scales) # for percent() function

custom_percent <- function(n){
    function(x){
         return(paste(percent(x), sprintf('(%d)', round(x* (n)))))
    }
 }

mydata = data.frame(x = rep(c('a','b','c'), each=100))

ggplot(mydata) + geom_text(aes_(x=~x, y=~..prop.., 
                           label=bquote(.(custom_percent)(length(x))(..prop..)),
                           stat='count')

该函数在这样的环境之外可以正常工作,但为了与ggplot 一起使用,它必须以一种或另一种方式引用。

不幸的是,我无法弄清楚如何正确返回包含以这种方式传递的变量的生成函数。我试过这个:

custom_percent <- function(n){
    n = enquo(n)
    function(x){
         return(paste(percent(x), sprintf('(%d)', round(x* (!!n)))))
    }
 }

但是当我这样做时出现错误:Error in !n : invalid argument type

有谁知道如何在custom_percent()返回的函数中正确使用n的期望值?

在有人问之前,我知道我可以事先在摘要数据框中生成统计数据使用utils::getAnywhere() 作为解决方法,但这不是问题的重点。

【问题讨论】:

  • 你的输出需要什么?
  • 例如。 custom_percent(3) 应该输出什么?
  • 您使用的是什么版本的ggplot2?我正在使用开发版并获得Error in FUN(X[[i]], ...) : Unknown input:function
  • 请注意,您只能在整洁的 eval 函数的参数中使用 !!paste()sprintf()round()都是正常功能。

标签: r ggplot2 tidyverse tidyeval non-standard-evaluation


【解决方案1】:

您可以使用基数 r substitute 来捕获整个表达式,然后将表达式写为 functionBody

custom_percent <- function(n){
 n=eval(n)
 m=substitute(return(paste(percent(x), sprintf('(%d)', round(x*n)))))
 `functionBody<-`(function(x)1,parent.frame(),m)
}

s=3
custom_percent(s)
function (x) 
return(paste(percent(x), sprintf("(%d)", round(x * 3))))

如您所见,n 已替换为 3。您可以尝试任何其他号码。它会起作用的

【讨论】:

    【解决方案2】:

    问题不在于您的功能 - 最初编写时看起来不错。您在 geom_text 调用中缺少括号,我认为这是主要问题。

    custom_percent <- function(n){
      function(x){
        return(paste(percent(x), sprintf('(%d)', round(x* (n)))))
      }
    }
    
    # I made the data slightly more variable
    mydata = data.frame(x = rep(c('a','b','c'), rbinom(3, 100, .8)))
    
    ggplot(mydata, aes(x = x)) + 
      # geom_bar(stat = 'count') + 
      geom_text(aes_(label=bquote(.(custom_percent)(length(x))(..count.. / sum(..count..)))),
        stat='count')
    

    我认为这可以让你得到你想要的(并且把 ..prop.. 扔进去也可以,这个数据只是平坦的 1 - 这对我来说没有意义。如果那是你想要/期望的,一定要切换它回来了。您可以查看https://sebastiansauer.github.io/percentage_plot_ggplot2_V2/ - 它显示了您可以在哪里使用..prop....count..,但它并没有真正解释原因)。

    您可以做的另一件事(利用..prop.. 写的):

    ggplot(mydata, aes(x = x, y = ..prop..), stat = 'count') + 
      # geom_bar(aes(y = ..prop..), stat = 'count') +
      geom_text(aes_(label=bquote(.(custom_percent)(length(x))((..count..) / sum(..count..)))),
        stat='count') + 
      scale_y_continuous(labels=scales::percent)
    

    【讨论】:

      猜你喜欢
      • 2016-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-30
      • 1970-01-01
      • 2021-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多