抛出一个话题,R是不是有个大坑,在自动化脚本中(或者在循环中),某些脚本执行会不出结果,特别是作图脚本。ps:分步执行可以出图

其实看我公众号的各位读者们,你们不应该有这个问题,如果有,那么证明我的文章没有好好看!

有两篇很重要的文章《扪心自问,meme几何?》和《树变图,图变树?》,特别是第二篇,和这个问题息息相关。

首先假设我们有一个图:

require(ggplot2)
p = qplot(1:10)

为什么在终端打p可以出图?

因为在R里,所有都是对象,而在终端里你输入一个对象回车,R会去找相应的方法去打印出来,如果是S3对象,会去寻找print方法,而如果是S4会去找show方法。

所以你在终端里打p,其实等同于你打print(p),它其实调用了ggplot2:::print.ggplot

你打plot(p)也可以,如果你看过代码的话,画图这个动作是定义在plot.ggplot方法里的,而print.ggplot <- plot.ggplot

为什么在循环里就不行?

很多人认为这是ggplot2的问题,而且这也是一个FAQ了,我也遇到好多人问我,其实这不是ggplot2的问题,如果你认为是ggplot2的问题,你看到的只是皮毛。

我上面已经说了,是面向对象的问题,所以这是R里普遍的现象,而ggplot2之所以有这个问题,因为返回的不是图,而是对象。

假设你有一个变量x <- 5,你打x,它会显示5,而如果在循环里呢?

不信你试试以下两段循环:

for (i in 1:3) x
for (i in 1:3) print(x)

第一段啥都不显示,第二段显示了。在循环里你的x,啥都没干,扔了。

那么为什么呢?因为在循环里,R不会自做聪明地去打印任何东西,或者做其它任何的操作,除非你让它干。

为什么没有循环的脚本,在终端里跑可以,跑脚本却不行?

这是交互与否的问题,你如果是交互环境,R是面向用户,它自做聪明地要方便用户。而如果你不是在交互,那么你是开发者,你理应知道自己想干什么,所以说有这个问题的人,你们还只是用户的水平,不要以为写两句脚本就是码农。

你跑下面的代码,返回的是FALSE

Rscript -e 'interactive()'

而你在R终端里跑interactive,返回的是TRUE

一点提醒

~/.Rprofile会影响你的R终端和R脚本,所以你额外的东西,放在了~/.Rprofile里,相当于在你的R脚本里预先跑了~/.Rprofile,而你的脚本拿到别人的机器上跑,别人可能没有~/.Rprofile,或者有却与你的不同,于是你的脚本挂了,因为运行环境不一致。所以在定义~/.Rprofile的时候,要小心。你最好能够加一个判断语句,知道自己是在终端还是脚本,如果是脚本不加载,终端才加载。于是你用终端的时候方便,你写脚本的时候不影响,起码保证你在自己机器上跑的脚本和在别人机器上跑的是一样的。如果你懂这些,再说自己是用python还是R吧。许多人声称在用某种语言做开发,其实只是用户,在用别人开发好的包,在穿别人做好的内裤(取java类库的谐音),所以我一直强调,也别扯什么语言了,谁的内裤多,谁就是超人,就喊谁当爹!