r - 复制的 ggplot-object 与原始对象部分链接
问题描述
为了改变用 ggplot 制作的绘图的一些布局方面,我首先将原始 ggplot-object 复制到一个新变量中,以保持原始不变。当我更新副本时,我注意到原始对象中的某些内容也已更新,就好像它们是链接的一样。但并非所有更改都发生这种情况,好像它取决于更改的参数类型。
有没有人对此行为有解释和解决方案?
这是一个例子:
library(tidyverse)
# Create ggplot-object
irisplot <- ggplot(iris, aes(x=Species, y=Sepal.Width, color=Species)) +
geom_boxplot(outlier.alpha=0) +
geom_jitter(width=0.5)
# Copy into new variable
newvariable <- irisplot
tracemem(irisplot)==tracemem(newvariable) # prints FALSE with rlang::duplicate(irisplot) and TRUE without
untracemem(irisplot)
untracemem(newvariable)
##### Linked: layers
# Check original outlier.alpha
irisplot$layers[[1]]$geom_params$outlier.alpha # prints 0 for me
newvariable$layers[[1]]$geom_params$outlier.alpha # prints 0 for me
# Update outlier.alpha in copy
newvariable$layers[[1]]$geom_params$outlier.alpha <- 1
tracemem(irisplot)==tracemem(newvariable)
# Check updated outlier.alpha
newvariable$layers[[1]]$geom_params$outlier.alpha # prints 1 for me
irisplot$layers[[1]]$geom_params$outlier.alpha # prints 1 for me
untracemem(irisplot)
untracemem(newvariable)
##### Not linked: labels
# Check original x-label
irisplot$labels$x # prints "Species" for me
newvariable$labels$x # prints "Species" for me
# Updated x-label
newvariable$labels$x <- "New label"
# Check updated x-label
newvariable$labels$x # prints "New label" for me
irisplot$labels$x # prints "Species" for me
我包括tracemem
检查它是否是由于最初共享内存地址,但替换复制行newvariable <- rlang::duplicate(irisplot)
并不会改变链接行为。
一个稍微相关的问题:通过覆盖特定参数,以这种方式修改现有的 ggplot-object 似乎可以解决问题,但是是否有更清洁/官方的方式来处理它?例如。标签我可以使用主题,但是对于特定于几何的东西呢?
编辑:
我的设置:Windows 10,R 版本 3.6.1,ggplot2 3.3.2,rlang 0.4.7
得到相同结果的同事:windows 10,R 版本 4.0.3,ggplot2 3.3.2,rlang 0.4.7
解决方案
ggplot2
使用环境作为其ggproto
对象的基础。在 R 中,环境是通过引用传递的,因此在复制 ggplot 时不会得到深层副本。有几种方法可以获得深层副本,但也许最简单的方法是unserialize(serialize(ggplot))
:
library(ggplot2)
irisplot <- ggplot(iris, aes(x=Species, y=Sepal.Width, color=Species)) +
geom_boxplot(outlier.alpha=0) +
geom_jitter(width=0.5)
# Make a deep copy
newvariable <- unserialize(serialize(irisplot, NULL))
# objects are currently the same
irisplot$layers[[1]]$geom_params$outlier.alpha
#> [1] 0
newvariable$layers[[1]]$geom_params$outlier.alpha
#> [1] 0
# Update outlier.alpha in copy
newvariable$layers[[1]]$geom_params$outlier.alpha <- 1
# Check updated outlier.alpha
newvariable$layers[[1]]$geom_params$outlier.alpha
#> [1] 1
irisplot$layers[[1]]$geom_params$outlier.alpha
#> [1] 0
由reprex 包(v0.3.0)于 2020-12-14 创建
推荐阅读
- java - Java 对象构造部分
- python - 如何将字符串合并到另一个字符串
- azure - 通过 Azure 数据工厂将数据从 Azure Functions 存储到 Azure SQL Server 的最佳实践
- c# - C#扩展Log4net的ILog接口现有方法
- c - C中的argc和argv
- reactjs - 如何在 React Router v4 中获取所有参数
- c++ - c++17 map::extract 方法在 macOS 上可用吗?
- r - gbm 包和分位数回归
- java - 将 maven Shade 与 Proguard 混合
- javascript - 当我的屏幕第二次加载时,反应本机组件接收道具不加载