我尝试复制ggplot对象,然后将新复制对象的某些属性更改为例如颜色线为红色。
假设此代码:
df = data.frame(cbind(x=1:10, y=1:10))
a = ggplot(df, aes(x=x, y=y)) + geom_line()
b = a
然后,如果我改变变量行a
a$layers[[1]]$geom_params$colour = "red"
它也会改变b
> b$layers[[1]]$geom_params$colour
[1] "red" # why it is not "black"?
我希望我可以拥有两个具有不同特征的不同对象a
和b
。因此,为了以正确的方式执行此操作,我需要使用b
再次为b = ggplot(df, aes(xy, y=z)) + geom_line()
调用该绘图。但是,此时在算法中,无法知道绘图命令ggplot(df, aes(x=x, y=y)) + geom_line()
你知道这有什么问题吗? ggplot对象是以不同的方式处理的吗?
谢谢!
答案 0 :(得分:7)
这里的问题是ggplot
使用proto
库来模仿OO风格的对象。 proto
库依赖于环境来收集对象的变量。环境通过引用传递,这就是您看到自己行为的原因(也是没有人建议以这种方式更改图层属性的原因)。
无论如何,调整proto
文档中的示例,我们可以尝试对ggplot
对象的laters进行深度复制。这应该“断开”它们。这是一个辅助函数
duplicate.ggplot<-function(x) {
require(proto)
r<-x
r$layers <- lapply(r$layers, function(x) {
as.proto(as.list(x), parent=x)
})
r
}
所以,如果我们运行
df = data.frame(cbind(x=1:10, y=1:10))
a = ggplot(df, aes(x=x, y=y)) + geom_line()
b = a
c = duplicate.ggplot(a)
a$layers[[1]]$geom_params$colour = "red"
然后绘制所有三个,我们得到
表示我们可以独立于“a”
更改“c”答案 1 :(得分:3)
忽略ggplot的细节,有一个简单的技巧可以在R中对(几乎)任何对象进行深度复制:
obj_copy <- unserialize(serialize(obj, NULL))
将对象序列化为适合写入磁盘的二进制表示,然后从该表示重构对象。它等同于将对象保存到文件然后再次加载(即saveRDS
后跟readRDS
),只是它从未实际保存到文件中。它可能不是最有效的解决方案,但它应该适用于任何可以保存到文件的对象。
您可以使用此技巧定义deepcopy
函数:
deepcopy <- function(p) {
unserialize(serialize(p, NULL))
}
这似乎成功打破了相关ggplots之间的联系。
显然,这对于无法序列化的对象不起作用,例如来自bigmemory包的大矩阵。