• R语言已解决
  • 【已解决】plot 函数的 xlab 和 ylab 的参数设置是否不一样

Cloud2016 如果是随便处理的话,那 xlab 应该有一半几率适合方法1,一半几率方法2。此前我画了好几次,好像挺稳定的。要不画100次试试?我现在手头没电脑……

    Cloud2016 可以看 plot.formula 方法的源代码:

    > graphics:::plot.formula
    function (formula, data = parent.frame(), ..., subset, ylab = varnames[response], 
      ask = dev.interactive()) 
    {
      ...

    我没有细看,但 ylab 这个参数确实是作了特殊处理,应该是在某个地方被执行了 eval() 导致 y[i] 被打回原形。

      yihui dapengde plot.formula 方法里确实对 ylab 的处理不一样,源代码不少,看起来有点晕,大家平时看源代码有什么辅助没有?

        Cloud2016 只看明白了一点:确实是对 ylab 经过了特殊处理。xlab 和 ylab 确实待遇不一样。其他的我就看不懂了。

        PS. ggplot 对方法 1 是支持的。

        gg <- ggplot(anscombe) + geom_point(aes(x1, y1))
        
        gg + 
          xlab(substitute(x[i], list(i = 1))) + 
          ylab(substitute(y[i], list(i = 1)))
        
        gg + 
          xlab(as.expression(substitute(x[i], list(i = 1)))) +
          ylab(as.expression(substitute(y[i], list(i = 1))))

          我之前没好好注意这个问题,就是 plot 是一个泛型函数,对于不同的数据对象,它有不同的方法。我之前说 xlab 和 ylab 没什么不同是对 plot.default 说的,而在 plot.formula 中确实对 ylab 做了特别处理

           methods(plot)
           [1] plot.acf*           plot.data.frame*    plot.decomposed.ts*
           [4] plot.default        plot.dendrogram*    plot.density*      
           [7] plot.ecdf           plot.factor*        plot.formula*      
          [10] plot.function       plot.hclust*        plot.histogram*    
          [13] plot.HoltWinters*   plot.isoreg*        plot.lm*           
          [16] plot.medpolish*     plot.mlm*           plot.ppr*          
          [19] plot.prcomp*        plot.princomp*      plot.profile.nls*  
          [22] plot.raster*        plot.spec*          plot.stepfun       
          [25] plot.stl*           plot.table*         plot.ts            
          [28] plot.tskernel*      plot.TukeyHSD*     
          see '?methods' for accessing help and source code

          Cloud2016 Base R 的源代码说实话不读也罢,它并不适合学习。在 plot.formula 中,我怀疑是这句 do.callylab 从 call 运行为实际值了:https://github.com/wch/r-source/blob/540cb48/src/library/graphics/R/plot.R#L207 因为 do.call() 默认不保护表达式。对比:

          > do.call(c, list(a = substitute(cars[i, 1], list(i = 1))))  # 默认不保护
          a 
          4 
          > do.call(c, list(a = substitute(cars[i, 1], list(i = 1))), quote = TRUE)  # 保护表达式
          $a
          cars[1, 1]

          quote() / enquote() 这些概念比较难理解,我至今也没完全搞明白,也没太大兴趣去深究。

            yihui dapengde 太好了,终于挖出根源了,我觉得这应该算一个 BUG 了,英语水平好的大神们有时间的话,不妨提交一个报告

            yihui
            关于 quote() / enquote(),只知道 enquote() 是表达式再额外加个quote, 例子如下:

            > quote(AA(c(10.5, 15.2, 12.3))) # AA 未定义, 保护表达式
            AA(c(10.5, 15.2, 12.3))
            > enquote(call("AA", c(10.5, 15.2, 12.3))) # 进一步保护表达式?基本上没用过这块。
            quote(AA(c(10.5, 15.2, 12.3)))

            关于 quote()call()的区别,call()不保护 arguments,比如:

            > quote(round(BB)) ## BB未定义,保护所有表达式
            round(BB)
            > call("round", BB) ## 保护 "round", 不保护 BB
            Error: object 'BB' not found
            5 个月 后
            7 个月 后