R ggplot2 weird behavior. It looks like he is following the link

I am trying to copy a ggplot object and then change some properties of a new copied object, for example, a colored line to red.

Assume this code:

df = data.frame(cbind(x=1:10, y=1:10)) a = ggplot(df, aes(x=x, y=y)) + geom_line() b = a 

Then, if I change the color of the string of variable a

 a$layers[[1]]$geom_params$colour = "red" 

it also changes color b

 > b$layers[[1]]$geom_params$colour [1] "red" # why it is not "black"? 

I would like to have two different objects a and b with different characteristics. So, to do it right, I would need to call the plot again for b using b = ggplot(df, aes(xy, y=z)) + geom_line() . However, at this time, there is no way in the algorithm to find out the command plot ggplot(df, aes(x=x, y=y)) + geom_line()

Do you know what's wrong with that? Are ggplot objects handled differently?

Thanks!

+5
source share
2 answers

The problem is that ggplot uses the proto library to simulate OO style objects. The proto library relies on environments to collect variables for objects. The environments are passed by reference, so you see the behavior that you are (as well as the reason that no one would probably recommend changing the properties of the layer this way).

Anyway, adapting the example from the proto documentaiton document, we can try to make a deep copy of the latters of the ggplot object. This should "disable" them. Here is such an auxiliary function

 duplicate.ggplot<-function(x) { require(proto) r<-x r$layers <- lapply(r$layers, function(x) { as.proto(as.list(x), parent=x) }) r } 

so if we run

 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" 

then we build all three, we get

enter image description here

which shows that we can change "c" independently of "a"

+7
source

Ignoring the specifics of ggplot, there is a simple trick to make a deep copy of (almost) any object in R:

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

This serializes the object into a binary representation suitable for writing to disk, and then reconstructs the object from that representation. This is equivalent to saving the object in a file and then saveRDS it (i.e. saveRDS followed by readRDS ), only it never saves the file. This is probably not the most efficient solution, but it should work for almost any object that can be saved to a file.

You can define the deepcopy function using this trick:

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

This seems to successfully break the ties between related ggplots.

Obviously, this will not work for objects that cannot be serialized, such as large matrices from the bigmemory package.

+3
source

Source: https://habr.com/ru/post/1202103/


All Articles