在RStudio中,在data.table()内使用plot()时,会使用错误组的值。

7

我想生成一个分裂图。图的上半部分应该使用组a的值,下半部分应该使用组b的值。我使用data.table()来完成这个任务。以下是我用来生成示例并设置图形输出的代码:

library(data.table)
set.seed(23)
Example <- data.table('group' = rep(c('a', 'b'), each = 5), 'value' = runif(10))
layout(1:2)
par('mai' = rep(.5, 4))

在通常的R控制台中运行以下代码时,正确的值将用于绘图。当在Rstudio中运行相同的代码时,第二组的值将用于两个图表:
Example[, plot(value, ylim = c(0, 1)), by = group] # Example 1
Example[, .SD[plot(value, ylim = c(0, 1))], by = group] # Example 2

在示例2的数据表子集.SD[]中添加逗号时,Rstudio也会生成正确的输出:
Example[, .SD[, plot(value, ylim = c(0, 1))], by = group] # Example 3

当使用barplot()而不是plot()时,Rstudio也会使用正确的值:
Example[, barplot(value, ylim = c(0, 1)), by = group] # Example 4

我是否忽略了什么问题还是这是一个bug?

系统:Windows 7,Rstudio桌面版v0.98.1091,R 3.1.2,data.table 1.9.4


在我的设置中,所有的图形都能够正确地生成:Rstudio 0.98.1028,R 3.0.2。 - Steven
1个回答

8
很好的发现(已经+1)!在我的情况下,示例3也没有产生正确的图形(OS X 10.10.1,R 3.1.2,Rstudio 0.98.1091)。R控制台/ GUI和Rstudio之间唯一的区别是绘图设备。 RStudio似乎使用本地图形设备RstudioGD,而R控制台/GUI使用Quartz。通过调试graphics ::: plot.default,我能够将问题缩小到函数plot.xy()。这个函数调用不同的图形设备(如上所示)。通过调用函数quartz()来初始化例如Quartz,然后运行您的代码就可以正常工作了!FWIW,也可以使用dplyr()复制此问题:
require(dplyr)
df = as.data.frame(Example)
my_fun = function(x) {plot(x, ylim=c(0,1)); 1L }
df %>% group_by(group) %>% summarise(my_fun(value))

会导致相同的错误图形。

这很可能是由于data.table中处理子组的方式(我认为dplyr应该像data.table一样处理),您可以通过以下方式查看:

Example[, print(sapply(.SD, address)), by=group]
#         value 
# "0x105bbf5b8" 
#         value 
# "0x105bbf5b8" 
# Empty data.table (0 rows) of 1 col: group

data.table.SD分配最大组,并在每个子组中内部重用此内存,以避免重复的内存分配/释放 - 以实现效率。不确定(这里瞎猜),但似乎RstudioGD不会释放与子组相关联的指针,并且随着子组中的数据更新,绘图也会更新。您可以通过执行以下操作来验证此操作:

# on RstudioGD
debug(graphics:::plot.default)
set.seed(23)
Example <- data.table('group' = rep(c('a', 'b'), each = 5), 'value' = runif(10))
layout(1:2)
par('mai' = rep(.5, 4))
Example[, plot(value, ylim = c(0, 1)), by = group] # Example 1
undebug(graphics:::plot.default)

保持按下回车键,您会发现第一个图绘制正确...当第二个图添加时,第一个图也会更改。这可能是Rv3.1+中最近更改的结果,该版本浅复制函数参数而不是深复制(在这里随意猜测)。
您可以通过显式复制value来暂时修复此问题:
Example[, plot(copy(value), ylim = c(0, 1)), by = group] # Example 1

将会生成正确的图表。


1
非常感谢您详细的回答和使用copy()函数的提示。目前看来,这似乎是最简单的解决方法。 - Jonas
如果这对@Arun有帮助的话,当我从控制台运行示例1或2时,我会得到正确的绘图,就像Jonas所说的那样,但是如果我然后打印绘图或复制为元文件,然后粘贴(例如进入Word),我会得到错误的绘图。复制为位图不会出现这种情况。最后,尝试一下没有ylim=c(0,1)的示例。当我打印或复制时,每个绘图都会得到适当的y范围,但是在第一个绘图中,重复的最后数据部分偏离了刻度。 - DaveTurek
Windows 7,R 3.1.2,data.table 1.9.4 - DaveTurek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接