ggplot2: Create an independent copy from an ggplot

2019-05-08 03:59发布

问题:

I'm not sure how to put this in OO-Speech. But when you are creating a ggplot it will be dependent from the source data.frame. So how can you save a ggplot without that dependency?

dat <- data.frame(x=runif(10),y=runif(10))  
g <- ggplot(dat, aes(x,y)) + geom_point()  
g  

dat <- NULL  
g

The second $g$ won't produce a plot hence dat is $NULL$. How can I save $g$ so that dat can be changed?

I know it is not good practice but I got some very long code on which I don't want to fiddle about.

回答1:

Personally, I think that @Joshua's answer is too complicated (if I'm understanding what you want to do).

I don't think it makes any sense to change the data frame stored in the plot object, since ggplot2 has a special infix operator that is specifically designed to apply a new data frame to a given plot object: %+%.

dat <- data.frame(x=runif(10),y=runif(10))  
g <- ggplot(dat, aes(x,y)) + geom_point()  
g

#Change the data frame
dat$y <- rexp(10)
#Replot g using the altered data frame
g %+% dat

This works, of course, with not just altered versions of the original data frame, but an entirely new data frame, provided it has all the required variables in it (and they are named the same).



回答2:

I think there are several options, I show in order of my preference.

## setup
require(ggplot2)
set.seed(10) # make reproducible
dat <- data.frame(x=1:10,y=runif(10))   

My favorite option is to create a simple function wrapper to your code. Then whenever you need to change the data, just pass new data to your function, and it will give it to ggplot and create the new graph. This is flexible and fairly robust to problems. It is also extensible, in that if later you decide you would also like to be able to change the title, you can just add a title argument to your function too.

## my favorite option
myplot <- function(data) {
  ggplot(data, aes(x, y)) + geom_point()
}

## use it
myplot(data = dat)

## change it
dat <- data.frame(x = 11:20, y = runif(10))
myplot(data = dat)

Another approach is to save your call to ggplot as an expression, which is unevaluated. Then you just evaluate it whenever you want. It is almost like typing the code each time (it is different in some ways but that is the best analogy I can think of).

## not wild about this one
myplotcall <- expression(ggplot(dat, aes(x,y)) + geom_point())

## look at it (literally just the input)
myplotcall
expression(ggplot(dat, aes(x, y)) + geom_point())

## use it
eval(myplotcall)

## change it
dat <- data.frame(x = 21:30, y = runif(10))
eval(myplotcall)

You can change the data in the ggplot object itself. I think that this approach would be the most prone to problems as you are mucking with internals of an object that was not really intended to be changed by the user (i.e., just because we can does not mean we should). This is more appropriately done with the %+% operator (see joran's answer)

## not wild about this either
g <- ggplot(dat, aes(x,y)) + geom_point()
g ## use it

## change it
dat <- data.frame(x = 31:40, y = runif(10))
g$data <- dat
g



标签: r oop ggplot2