Export and re-import ggplot object - r

I have two different (very long) R scripts, each ultimately producing two ggplots (p and q).
I want to save these two plots as "gg-files", so that I can re-upload them in a third R script, where I will use ggarrange (or else) to merge them for an academic publication.
How can I export/import ggplots as "gg-objects"?
My apologies for my code - I'm a newbie
Thank you in advance!
I have looked into several methods of saving (e.g. ggsave, svg() def.off(), imager package, rsvg package) but none provided what I am looking for.
# script A
rm(list = ls()) # clean environment
dat <- data.frame(x = 1:10, y = 1:10)
p <- ggplot(dat, aes(x = x, y = y)) + geom_point()
svg(filename = "p.svg") # saves as image
p
dev.off()
# script B
rm(list = ls()) # clean environment
dat <- data.frame(x = 1:10, y = 1:10)
q <- ggplot(dat, aes(x = x, y = y)) + geom_point()
# script C
rm(list = ls()) # clean environment
## import images - how?
## combine
ggarrange(
p, q,
nrow = 2
)

You can save them like this:
xx <- ggplot(mtcars)+geom_histogram(aes(x=cyl))
save(xx, file = "G:/gpl.rdata")
Then load them :
load("G:/gpl.rdata")
This will bring the whole object in and you can see the data used to build the plot and other features of the plot

Related

Modify GGplot2 Object

I was curious however, if it is possible to add any specific legend or put which species corresponds in the observed-expected plot, to know which circle it is respectively. I am using a fake dataset at the moment called finches. The package is called "cooccur" which creates a ggplot object. I was curious on how to actually edit this to put labels of species on here.
Alternatively is to extract the labels and co-occurrences and use base graphics, but this is not as ideal.
CODE SNIPPET BELOW
library(devtools)
#install_github("griffithdan/cooccur")
library(cooccur)
options(stringsAsFactors = FALSE)
data(finches)
cooccur.finches <- cooccur(mat=finches,
type="spp_site",
thresh=TRUE,
spp_names=TRUE)
summary(cooccur.finches)
plot(cooccur.finches)
p <- obs.v.exp(cooccur.finches)
# the ggplot2 object can be edited directly and then replotted
p
# alternatively, use base graphics, This is what I am currently doing but it is not correct
cooc.exp <- cooccur.finches$results$exp_cooccur
cooc.obs <- cooccur.finches$results$obs_cooccur
sp1 <- cooccur.finches$results$sp1_name
sp2 <- cooccur.finches$results$sp2_name
plot(cooc.obs ~ cooc.exp)
text(x = cooc.exp[1], y = cooc.obs[1], labels = sp1[1]) # plots only one name
I installed cooccur_1.3, and running your code gives this plot:
library(cooccur)
options(stringsAsFactors = FALSE)
data(finches)
cooccur.finches <- cooccur(mat=finches,
type="spp_site",
thresh=TRUE,
spp_names=TRUE)
plot(cooccur.finches)
Anyway, if you want to get a scatter plot, you can go to the dataframe and do a ggplot, below I only label the points where species 1 is Geospiza magnirostris, otherwise 80 points to label is quite insane:
library(ggrepel)
library(ggplot2)
df = cooccur.finches$results
df$type = "random"
df$type[df$p_lt<0.05] = "negative"
df$type[df$p_gt<0.05] = "positive"
ggplot(df,aes(x=exp_cooccur,y=obs_cooccur)) +
geom_point(aes(color=type)) + geom_abline(linetype="dashed") +
geom_label_repel(data=subset(df,sp1_name=="Geospiza magnirostris"),
aes(label=paste(sp1_name,sp2_name,sep="\n")),
size=2,nudge_x=-1,nudge_y=-1) +
scale_color_manual(values=c("#FFCC66","light blue","dark gray")) +
theme_bw()

Overlaying trials in separate files onto one ggplot graph

I am trying to plot one graph with multiple trials (from separate text files). In the below case, I am plotting the "place" variable with the "firing rate" variable, and it works when I use ggplot on its own:
a <- read.table("trial1.txt", header = T)
library(ggplot2)
ggplot(a, aes(x = place, y = firing_rate)) + geom_point() + geom_path()
But when I try to create a for loop to go through each trial file in the folder and plot it on the same graph, I am having issues. This is what I have so far:
files <- list.files(pattern=".txt")
for (i in files){
p <- lapply(i, read.table)
print(ggplot(p, aes(x = place, y = firing_rate)) + geom_point() + geom_path())
}
It gives me a "Error: data must be a data frame, or other object coercible by fortify(), not a list" message. I am a novice in R so I am not sure what to make of that.
Thank you in advance for the help!
In general avoiding loops is the best adivce in R. Since you are using ggplot you may be interested in using the map_df function from tidyverse:
First create a read function and include the filename as a trial lable:
readDataFile = function(x){
a <- read.table(x, header = T)
a$trial = x
return(a)
}
Next up map_df:
dataComplete = map_df(files, readDataFile)
This runs our little function on each file and combines them all to a single data frame (of course assuming they are compatible in format).
Finally, you can plot almost as before but can distinguish based on the trial variable:
ggplot(dataComplete, aes(x = place, y = firing_rate, color=trial, group=trial)) + geom_point() + geom_path()

Storing do.call("grid.arrange") output without printing

I would like to create a variable p that contains a plot with four ggplot2 subplots. I am able to achieve this with the below code:
library(ggplot2)
library(gridExtra)
data = diamonds[1:50,]
x = data$x
myPlots = lapply(c(1,5,6,7), function(i){
y = as.data.frame(data[,i])
y = y[,1]
df = data.frame(x=x,y=y)
p <- qplot(x, y, data=df)
p
})
p = do.call("grid.arrange", c(myPlots, ncol=2))
I like that I can use the variable p later by calling:
library(grid)
grid.draw(p)
However, I do not like that when I initially create p with the do.call("grid.arrange") syntax, it plots it automatically (at least in RStudio).
My question is: Is it possible to create p to be stored for later use, without plotting it upon its creation?

Is it possible to save a ggplot in RDS format with a global variable in the ggplot() call?

RDS files are wonderful for sharing R objects between R files. And I often share ggplot objects between R files when I have a particularly complicated layout. Usually this works great.
My grumble is that if your ggplot() function call contains a global variable, that variable is lost when you save the plot as an .rds file. So when you load the plot in a new R file, it's no bueno. Information is lost.
Does anyone know a clever solution for this problem? The work-arounds I have come up with are clunky. And I really don't want to regress to the default save() and load() functions.
How about a few examples. I'll start with a chunk that works. Then I'll show how things fall apart with a global variable.
NOTE: This code will put a couple junk files in your current working directory. Ye be warned.
# Preliminaries -------------------------------------------
library(tibble)
library(magrittr)
library(ggplot2)
# Fake data
x <- 1:5 %>% as.factor()
y <- rnorm(5)
df <- data_frame(x, y)
# First an example that works -----------------------------
# Notice how the color palette is
# defined within scale_fill_manual()
this_plot_works <- ggplot(df, aes(x, y, fill = x)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = c("red", "blue", "orange", "green", "purple"))
# Save plot to file
saveRDS(this_plot_works, file = "this_plot_works.rds")
# To simulate the behavior of moving to a new R file
# let's remove the ggplot object from the environment.
rm(this_plot_works)
# Now, pretending we're in a new R file, load the plot
this_plot_works_reloaded <- readRDS("this_plot_works.rds")
this_plot_works_reloaded
Now I'll specify the color palette as a global variable, and I'll call it within the ggplot function (I guess, technically, it's called in the 'scale_fill_manual()' function, but you know what I mean). This strategy will not work.
# Second example that won't work --------------------------
# Specify color palette as a global variable
col_pal <- c("red", "blue", "orange", "green", "purple")
# Plot
# Note that the color palette is tied to the global variable
this_plot_wont_work <- ggplot(df, aes(x, y, fill = x)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = col_pal)
# Save the plot to file
saveRDS(this_plot_wont_work, file = "this_plot_wont_work.rds")
# Again, let's remove the key global variables
# and pretend we're switching to a new R file
rm(this_plot_wont_work, col_pal)
# Load the plot
this_plot_wont_work_reloaded <- readRDS("this_plot_wont_work.rds")
this_plot_wont_work_reloaded
The question is pretty old but anyway...
You could save the plot and global variables as separate objects:
# SAVE PLOT...
saveRDS(this_plot_wont_work, file = 'this_plot_wont_work.rds')
# ...AND GLOBAL VARIABLES
globVar = list(col_pal = col_pal)
saveRDS(globVar, file = 'this_plot_wont_work.bis.rds')
Then reload them in the right order (i.e. global variables first)
# LOAD GLOBAL VARIABLES RDS NAMED LIST
globRDS = 'this_plot_wont_work.bis.rds'
gglob = readRDS(globRDS)
# TURN ELEMENTS INTO ACCESSIBLE VARIABLES SO GGPLOT2 HAVE ACCESS TO THEM
# (I.E. LIST(VAR1 = VALUE1) >>> VAR1 = VALUE1)
for (i in seq(length(gglob))){
assign(x = names(gglob[i]) , value = gglob[[i]])
}
# AND FINALLY LOAD THE GGPLOT OBJECT
plotRDS = 'this_plot_wont_work.rds'
gg = readRDS(plotRDS)
gg
I think one option would be to create the plot and all objects that your plot needs within a new environment. You can then export and import this environment as .Rds as a single object. Once imported into a new session, you can either use that environment or you can also move the objects of that environment into your global environment.
NB: this answer will create files in your working directory
## Session 1 - when defining your plot, do this within a new environment
e <- new.env()
## thanks https://stackoverflow.com/a/10761618/7941188
with(e, {
set.seed(42)
df <- data.frame(x = as.character(1:5), y = rnorm(5))
col_pal <- c("red", "blue", "orange", "green", "purple")
p <- ggplot(df, aes(x, y, fill = x)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = col_pal)
})
saveRDS(e, "plot_and_obj.Rds")
## New session
library(ggplot2)
e <- readRDS("plot_and_obj.Rds")
## call plot either within the environment
with(e, p)
## Or move all objects from child environment to global env
## thanks https://stackoverflow.com/a/13797968/7941188
list2env(as.list(e), globalenv())
p

Using a for loop to save multiple ggplot as jpeg

I'd like to save multiple ggplots as jpegs through a for loop. But when I've tried to adapt code I've written for a basic plot command, I get no output (nothing is saved to my working directory).
For Example, this works great:
library(cowplot)
library(ggplot)
X<-c(1,2,3,4,5,6,7,8,9)
Y1<-c(2,3,4,4,3,2,4,5,6)
Y2<-c(3,4,5,3,2,1,1,2,3)
Y3<-c(4,5,6,7,8,9,8,7,6)
DF<-data.frame(X,Y1,Y2,Y3)
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
plot(DF[,1],DF[,i+1])
dev.off()
}
I end up getting three jpeg files saved to my working directory.
I'm not sure how to properly index the ggplot call here for i, but even this should return 3 instances of the same plot:
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
ggplot(data=DF,aes(x=X,y=Y1))+geom_line()
dev.off()
}
In the end, I was hoping to combine multiple plots onto one jpeg, and then save multiple jpegs like this:
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
A<-ggplot(data=DF,aes(x=X,y=Y1))+geom_line()
B<-ggplot(data=DF,aes(x=X,y=Y2))+geom_line()
C<-ggplot(data=DF,aes(x=X,y=Y3))+geom_line()
plot_grid(A,B,C)
dev.off()
}
So this plot should also return 3 instances of the same plot, all with different indexed file names. But again, I get nothing.
So my question is why is there a difference between generic plotting and ggploting in this for loop. And how can one save mutliple jpegs from ggplots like above?
How about
library(gridExtra) # gridExtra::arrangeGrob
for(i in 1:3) {
jpeg(paste0(i, ".jpg"))
A <- ggplot(data = DF, aes(x = X, y = Y1)) + geom_line()
B <- ggplot(data = DF, aes(x = X, y = Y2)) + geom_line()
C <- ggplot(data = DF, aes(x = X, y = Y3)) + geom_line()
grid.arrange(arrangeGrob(A, B, C, ncol = 3))
dev.off()
}
Note: this solution does not produce the side annotations of cowplot ("A", "B", "C").
using your code:
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
A<-ggplot(data=DF,aes(x=X,y=Y1))+geom_line()
B<-ggplot(data=DF,aes(x=X,y=Y2))+geom_line()
C<-ggplot(data=DF,aes(x=X,y=Y3))+geom_line()
k<-plot_grid(A,B,C)
ggsave(k, filname = "path/finalplot.jpeg")
}
look at ?ggsave to look at other arguments to specify like height and width

Resources