【问题标题】:last line of an R function prevent the plottingR 函数的最后一行阻止绘图
【发布时间】:2020-05-21 05:29:50
【问题描述】:

我真的很想知道为什么当我在函数 foo1 中保留最后一行 (sigma) 时,我的 plot 调用停止工作,但是当我删除 foo2 中的最后一行时,plot 调用工作好吗?!

注意: 我的理解是 plot 应该显示在函数中的任何位置,例如:

foo3 <- function(x = 1:3){; plot(x); return(x); }; foo3()

我需要保留最后一行,但我还需要绘图,这可以修复吗?

library(lme4)
library(emmeans)

h <- read.csv('https://raw.githubusercontent.com/hkil/m/master/h.csv')
h$year <- as.factor(h$year)
m <- lmer(scale~ year*group + (1|stid), data = h)

foo1 <- function(fit, plot = T){

  vc <- VarCorr(fit)
  f  <- as.formula(bquote(pairwise ~ .(terms(fit)[[3]])))
  ems <- emmeans(fit, f, infer = c(T, T))

  if(plot) plot(ems)

  ## Why having this line prevents plotting?
  sigma <- sqrt(sum(as.numeric(c(attr(vc[[1]], "stddev"), attr(vc, "sc")))^2)) 
}

###### EXAMPLE: Will NOT plot !!! 
foo1(m, plot = T)

但只需删除foo1 的最后一行,情节就可以正常工作了!

foo2 <- function(fit, plot = T){

  f <- as.formula(bquote(pairwise ~ .(terms(fit)[[3]])))   
  ems <- emmeans(fit, f, infer = c(T, T))

  if(plot) plot(ems)
}

###### EXAMPLE: NOW plots fine !!!
foo2(m, plot = T)          

【问题讨论】:

    标签: r function class attributes s4


    【解决方案1】:

    意外行为的根本原因是emmeans 使用ggplot2 作为绘图方法。您可以查看函数emmeans:::.plot.srg 的代码。这就是为什么您可以将绘图存储在对象 (p) 和 print 它中:

    foo1 <- function(fit, plot=TRUE) {
      vc <- VarCorr(fit)
      f <- as.formula(bquote(pairwise ~ .(terms(fit)[[3]])))
      ems <- emmeans(fit, f, infer=c(TRUE, TRUE))
      sigma <- sqrt(sum(as.numeric(c(attr(vc[[1]], "stddev"), attr(vc, "sc")))^2))
      p <- plot(ems)
      if(plot) print(p)
      return(sigma)
    }
    
    foo1(m, plot=TRUE)  ## plots
    # [1] 126.6106
    

    直观地说,我们期望您的 foo3 &lt;- function(x = 1:3){; plot(x); return(x); }; foo3() 示例中的行为:

    foo2 <- function(x, plot=TRUE) {
      y <- seq_len(x)^2
      if(plot) plot(seq_len(x), y)
      return(y)
    }
    foo2(20)  ## plots
    # [1]   1   4   9  16  25  36  49  64  81 100 121 144 169
    # [14] 196 225 256 289 324 361 400
    

    但是当一个人使用ggplot 时,这会有所不同。当我们不存储"ggplot" 对象时,下面一行将“覆盖”绘图。

    library(ggplot2)
    foo3a <- function(x, plot=TRUE) {
      y <- seq_len(x)^2
      if(plot) ggplot(mapping=aes(seq_len(x), y)) + geom_point()
      return(y)  ## try to comment/un-comment this line
    }
    foo3a(20)  ## won't plot, just output of y (depending on `return`)
    

    因此,如果它不是函数的最后一行,我们实际上必须 print "ggplot" 对象(我通过将绘图存储在函数 p 中的函数 foo3b 中来显示这一点)。

    foo3b <- function(x, plot=TRUE) {
      y <- seq_len(x)^2
      p <- ggplot(mapping=aes(seq_len(x), y)) + geom_point()
      if(plot) print(p)
      return(y)  ## try to comment/un-comment this line (works in both cases)
    }
    foo3b(20)  ## plots
    # [1]   1   4   9  16  25  36  49  64  81 100 121 144 169
    # [14] 196 225 256 289 324 361 400
    

    请注意,return 的使用也很有用。

    【讨论】:

      【解决方案2】:

      嗯,这是有道理的,因为在 foo2 中,plot 是函数中的最后一个命令,它会返回该命令,而在 foo1 中并非如此。

      如果你想plot然后做一些额外的计算,一个简单的方法是在函数中print它。

      foo1 <- function(fit, plot = T){
      
         vc <- VarCorr(fit)
         f <- as.formula(bquote(pairwise ~ .(terms(fit)[[3]])))
      
         ems <- emmeans(fit, f, infer = c(T, T))
         if(plot) print(plot(ems))
         sigma <- sqrt(sum(as.numeric(c(attr(vc[[1]], "stddev"), attr(vc, "sc")))^2)) 
      }
      

      那么如果你运行foo1

      x <- foo1(m, plot = T)
      x
      #[1] 126.61
      

      它从函数返回sigma 值,因为我们使用print 它也使用plots

      【讨论】:

      • 但我确信情节不需要是最后展示的部分!!!
      • 是的,如果你检查我的函数foo1它不是函数的最后一行。
      • 那是什么:foo3 &lt;- function(x = 1:3){; plot(x); return(x); }; foo3()
      • 我认为这与 s4 在我的具体案例中使用的包的绘图功能有关!
      • 好吧..这很有趣。我不确定那里发生了什么。我的印象是,如果您的绘图不是函数中的最后一行,则需要显式打印它才能显示。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多