R ggplot2奇怪的行为。它看起来通过引用传递

时间:2014-09-08 20:11:33

标签: r ggplot2

我尝试复制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"?  

我希望我可以拥有两个具有不同特征的不同对象ab。因此,为了以正确的方式执行此操作,我需要使用b再次为b = ggplot(df, aes(xy, y=z)) + geom_line()调用该绘图。但是,此时在算法中,无法知道绘图命令ggplot(df, aes(x=x, y=y)) + geom_line()

你知道这有什么问题吗? ggplot对象是以不同的方式处理的吗?

谢谢!

2 个答案:

答案 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"

然后绘制所有三个,我们得到

enter image description here

表示我们可以独立于“a”

更改“c”

答案 1 :(得分:3)

忽略ggplot的细节,有一个简单的技巧可以在R中对(几乎)任何对象进行深度复制:

obj_copy <- unserialize(serialize(obj, NULL))

将对象序列化为适合写入磁盘的二进制表示,然后从该表示重构对象。它等同于将对象保存到文件然后再次加载(即saveRDS后跟readRDS),只是它从未实际保存到文件中。它可能不是最有效的解决方案,但它应该适用于任何可以保存到文件的对象。

您可以使用此技巧定义deepcopy函数:

deepcopy <- function(p) {
    unserialize(serialize(p, NULL))
}

这似乎成功打破了相关ggplots之间的联系。

显然,这对于无法序列化的对象不起作用,例如来自bigmemory包的大矩阵。