Чтобы изменить несколько аспектов макета графика, созданного с помощью ggplot, я сначала скопировал исходный объект ggplot в новую переменную, чтобы сохранить оригинал нетронутым. Когда я обновил копию, я заметил, что некоторые вещи также были обновлены в исходном объекте, как если бы они были связаны. Но это произошло не для всех изменений, как будто это зависит от того, какой тип параметра изменяется.
У кого-нибудь есть объяснение этому поведению и решение?
Вот пример:
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 таким образом, перезаписав определенные параметры, но есть ли более чистый/официальный способ сделать это? Например. метки Я могу использовать тему, но как насчет специфических для геометрии вещей?
Редактировать:
Моя установка: 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
Created on 2020-12-14 by the reprex package (v0.3.0)