Saving two ggplots in grid.arrange to eps file format - r

I am working in RStudio and have two ggplots, call them plot1 and plot2. I would like to arrange them one above the other and save into eps format. I have read the following posts on the topic:
Export a graph to .eps file with R
Saving grid.arrange() plot to file
Side-by-side plots with ggplot2
I have tried multiple methods which I list below, all of which have failed. Most revolve around using gridarrange.
1) My initial method was to run:
setEPS()
postscript("Figure1.eps",width=11.5,height=16)
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
dev.off()
Similar to link 1 but with grid.arrange. There are no errors in R and an EPS file appears in my directory, however the filesize is small and I cannot open it in a file viewer, it appears to be corrupted for some reason.
2) My second attempt used ggsave:
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave("Figure1.eps", p)
This saves only the second plot. Then try suggestions from comments from link 2:
The code
p <- arrangeGrob(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
grid.draw(p) # interactive device
ggsave("Figure1.eps", p)
gives output: Error in ggsave("saving.eps", p) : plot should be a ggplot2 plot
The code
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
p<-arrangeGrob(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave("Figure1.eps", p)
gives output: Error in ggsave("saving.eps", p) : plot should be a ggplot2 plot
The code
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]
p<-arrangeGrob(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
ggsave("Figure1.eps", p)
gives output:
Saving 8.28 x 9.07 in image
TableGrob (2 x 1) "arrange": 2 grobs
z cells name grob
1 1 (1-1,1-1) arrange gtable[layout]
2 2 (2-2,1-1) arrange gtable[layout]
In this final case, a file appears in the directory but it is small and cannot be opened.
3) My final attempt is just to use the command
png("Figure1.eps",height=11.5,width=16,units="cm",res=600)
grid.arrange(plot1,plot2,nrow=2,heights=c(9.5/20,10.5/20))
dev.off()
This produces a 'eps' file and is of a large size, and can be opened, however I am unsure if to trust it. Why would the png command be able to create an eps file? I have a feeling it's just a png file but masked as an eps somehow if that is possible. Is there a way to check the files format?
EDIT: Code to create plots for which the above code can be ran.
data1<-data.frame(a=c(1,2,3,4,0.5,1,1.5,2,0.5,1,3,4),b=c(1,2,3,4,1,2,3,4,1,2,3,4),
c=c('graph1','graph1','graph1','graph1','graph2','graph2','graph2','graph2','graph3','graph3','graph3','graph3'))
data2<-data.frame(a=c(10,20,25,40,13,14,25,37,2,20,34,35),b=c(1,2,3,4,1,2,3,4,1,2,3,4),
c=c('graph1','graph1','graph1','graph1','graph2','graph2','graph2','graph2','graph3','graph3','graph3','graph3'))
plot1<-ggplot(data1, aes(x=b,y=a)) +
geom_line() +
geom_point(size=2.5) +
facet_wrap(~c, scales="fix") +
scale_x_continuous(limits=c(1,4),labels=c("Zero","Low","Med","High")) +
ylab("ylab1") +
coord_cartesian(ylim=c(0,4)) +
theme(legend.position="none",axis.title.x=element_blank(), panel.margin.x=unit(1.1, "lines"))
plot2<-ggplot(data2, aes(x=b,y=a)) +
geom_line() +
geom_point(size=2.5) +
facet_wrap(~c, scales="fix") +
scale_x_continuous(limits=c(1,4),labels=c("Zero","Low","Med","High")) +
coord_cartesian(ylim=c(0,40)) +
xlab("level of correlation") +
ylab("ylab2") +
theme(legend.position="none",axis.title.x=element_blank(), panel.margin.x=unit(1.1, "lines"))
EDIT: I have also now realised that
setEPS()
postscript("TestFig3.eps")
plot1
dev.off()
which should just simply create an eps file (no grid.arrange involved) also does not work. A file is created and no error message in R, but it is corrupted in some way.
Ideally I would like an
eps()
grid.arrange()
dev.off()
but ?eps provides no packages.
I realise there is already quite a lot of chat about this, however I have not been able to source a solution from it all.

Related

How to plot a high resolution image in ggplot without saving the file?

I am working on a restricted data online which I do not have access to. I can still get the outputs of my codes, but I cannot access any saved files of the outputs. Options like ggsave and other ones permit to have high-resolution quality figures, but then I cannot use these as I do not have access to the folders. Is there another way to produce these figures without having to save them? I can have access to the figures that plot in the R interface.
Let's suppose we use this code:
plot= ggplot(mtcars, aes(displ, hwy)) +
geom_point() +
geom_smooth()
If we type plot, R will display the graph. Is there a way to modify its resolution, length and width? and then to type plot and get these modifications?
For running remote scripts (e.g. via ssh) that output a svg representation of a plot, you might consider using repr.
Here's an example code (hack) that can work in non interactive mode on linux servers:
sink(file = "/dev/null") # suppresses all the output
library(ggplot2)
library(repr)
png(filename = "/dev/null") # start an arbitrary device. (it does not really matter)
dev.control("enable") #set this to allow recording from the device
g <- ggplot(mtcars, aes(disp, hp)) +
geom_point() +
geom_smooth()
print(g)
p <- recordPlot() #record it
dev.off() #close the device
sink() #restore the output
cat(repr_svg(p), width = 7, height = 7)) #print out the svg
Save the script to e.g. example_script.R, then run in a terminal
cat example_script.R | ssh myuser#myhost Rscript '-' > example.svg
This will save the results in the file example.svg

r - Missing object when ggsave output as .svg

I'm attempting to step through a dataset and create a histogram and summary table for each factor and save the output as a .svg . The histogram is created using ggplot2 and the summary table using summary().
I have successfully used the code below to save the output to a single .pdf with each page containing the relevant histogram/table. However, when I attempt to save each histogram/table combo into a set of .svg images using ggsave only the ggplot histogram is showing up in the .svg. The table is just white space.
I've tried using dev.copy Cairo and svg but all end up with the same result: Histogram renders, but table does not. If I save the image as a .png the table shows up.
I'm using the iris data as a reproducible dataset. I'm not using R-Studio which I saw was causing some "empty plot" grief for others.
#packages used
library(ggplot2)
library(gridExtra)
library(gtable)
library(Cairo)
#Create iris histogram plot
iris.hp<-ggplot(data=iris, aes(x=Sepal.Length)) +
geom_histogram(binwidth =.25,origin=-0.125,
right = TRUE,col="white", fill="steelblue4",alpha=1) +
labs(title = "Iris Sepal Length")+
labs(x="Sepal Length", y="Count")
iris.list<-by(data = iris, INDICES = iris$Species, simplify = TRUE,FUN = function(x)
{iris.hp %+% x + ggtitle(unique(x$Species))})
#Generate list of data to create summary statistics table
sum.str<-aggregate(Sepal.Length~Species,iris,summary)
spec<-sum.str[,1]
spec.stats<-sum.str[,2]
sum.data<-data.frame(spec,spec.stats)
sum.table<-tableGrob(sum.data)
colnames(sum.data) <-c("species","sep.len.min","sep.len.1stQ","sep.len.med",
"sep.len.mean","sep. len.3rdQ","sep.len.max")
table.list<-by(data = sum.data, INDICES = sum.data$"species", simplify = TRUE,
FUN = function(x) {tableGrob(x)})
#Combined histogram and summary table across multiple plots
multi.plots<-marrangeGrob(grobs=(c(rbind(iris.list,table.list))),
nrow=2, ncol=1, top = quote(paste(iris$labels$Species,'\nPage', g, 'of',pages)))
#bypass the class check per #baptiste
ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]
#
for(i in 1:3){
multi.plots<-marrangeGrob(grobs=(c(rbind(iris.list[i],table.list[i]))),
nrow=2, ncol=1,heights=c(1.65,.35),
top = quote(paste(iris$labels$Species,'\nPage', g, 'of',pages)))
prefix<-unique(iris$Species)
prefix<-prefix[i]
filename<-paste(prefix,".svg",sep="")
ggsave(filename,multi.plots)
#dev.off()
}
Edit removed theme tt3 that #rawr referenced. It was accidentally left in example code. It was not causing the problem, just in case anyone was curious.
Edit: Removing previous answer regarding it working under 32bit install and not x64 install because that was not the problem. Still unsure what was causing the issue, but it is working now. Leaving the info about grid.export as it may be a useful alternative for someone else.
Below is the loop for saving the .svg's using grid.export(), although I was having some text formatting issues with this (different dataset).
for(i in 1:3){
multi.plots<-marrangeGrob(grobs=(c(rbind(iris.list[i],table.list[i]))),
nrow=2, ncol=1,heights=c(1.65,.35), top =quote(paste(iris$labels$Species,'\nPage', g,
'of',pages)))
prefix<-unique(iris$Species)
prefix<-prefix[i]
filename<-paste(prefix,".svg",sep="")
grid.draw(multi.plots)
grid.export(filename)
grid.newpage()
}
EDIT: As for using arrangeGrob per #baptiste's comment. Below is the updated code. I was incorrectly using the single brackets [] for the returned by list, so I switched to the correct double brackets [[]] and used grid.draw to on the ggsave call.
for(i in 1:3){
prefix<-unique(iris$Species)
prefix<-prefix[i]
multi.plots<-grid.arrange(arrangeGrob(iris.list[[i]],table.list[[i]],
nrow=2,ncol=1,top = quote(paste(iris$labels$Species))))
filename<-paste(prefix,".svg",sep="")
ggsave(filename,grid.draw(multi.plots))
}

Plot multiple ggplot2 on same page

I have a working loop which generates and can save individual plots from each file saved in a directory.
I want to plot all of the returned plots in a single file as a 2x2 grid over multiple pages but cannot do this.
I have tried to save the plot objects in a list
pltList <- list()
pltList[]
for (f in 1:length(files)){
plot_object <- ggplot2(...) #make ggplot2 plot
print(plot_object)
pltList[[f]] <- plot_object #save ggplot2 plot in list
}
jpeg(filename.jpg)
par(mfrow=c(2,2)) #to generate 2x2 plot per page
print(pltList[[1]])
print(pltList[[2]])
...
print(pltList[[f]])
dev.off()
The problem is that the resulting saved .jpg file only contains the last plot and not a 2x2 grid of all plots over many pages which is what I want.
EDIT
My first problem is how to save each plot from the loop in the list - how can I view the saved objects from the list to make sure they have been saved correctly?
When I do print(pltList[1]), the resulting output is:
function (x, y, ...)
UseMethod("plot")
<bytecode: 0x0000000010f43b78>
<environment: namespace:graphics>
rather than the actual plot. It seems that the plots are not being saved in the list as expected. How can I correct for this?
Hopefully, once this is fixed, your plotting suggestions will work.
I did recently the same. I used grid.arrange().
library(ggplot2)
library(gridExtra)
library(grid)
p1<-ggplot()+geom_line(aes(x=1:10,y=1:10))
p2<-ggplot()+geom_line(aes(x=1:10,y=1:10))
p3<-ggplot()+geom_line(aes(x=1:10,y=1:10))
p4<-ggplot()+geom_line(aes(x=1:10,y=1:10))
grid.arrange(p1,p2,p3,p4, ncol=1, top=textGrob("Multiple Plots", gp=gpar(fontsize=12, font = 2)))
Assuming you need a PDF output where every page has multiple plots plotted as one, e.g.: if there are 12 plots then 4 plots per page.
Try this example:
library(ggplot2)
library(cowplot)
# list of 12 dummy plots, only title is changing.
pltList <- lapply(1:12, function(i){
ggplot(mtcars,aes(mpg,cyl)) +
geom_point() +
ggtitle(paste("Title",i))})
# outputs 3 jpeg files with 4 plots each.
for(i in seq(1,12,4))
ggsave(paste0("Temp",i,".jpeg"),
plot_grid(pltList[[i]],
pltList[[i+1]],
pltList[[i+2]],
pltList[[i+3]],nrow = 2))
# or we can output into 1 PDF with 3 pages using print
pdf("TempPDF.pdf")
for(i in seq(1,12,4))
print(plot_grid(pltList[[i]],
pltList[[i+1]],
pltList[[i+2]],
pltList[[i+3]],nrow = 2))
dev.off()
EDIT:
Another way using gridExtra, as suggested by #user20650:
library(gridExtra)
#output as PDF
pdf("multipage.pdf")
#use gridExtra to put plots together
marrangeGrob(pltList, nrow=2, ncol=2)
dev.off()

Plotting to a file from a function in R

Background
Hey everyone!
I'm new to using R, and became interested in using it after having a team member give a tutorial of how useful it can be in an academic setting.
I am trying to write a script to automatically read my data from multiple files and then plot the resultant graphs to multiple files, so that they can be easily added to a manuscript (PowerPoint, latex, etc.)
Problem
I have found that the following code will allow me to produce a graph
p = qplot(factor(step), y, data=x, colour=c))
p = p + theme_bw()
# etc...
wrapping this around a png call will allow me to output the plot to a PNG:
png("test.png")
p = qplot(factor(step), y, data=x, colour=c))
p = p + theme_bw()
# etc...
p
dev.off()
I wanted to put the graph creation into a function so that I can create graphs and consequent seperate PNGs. So I put everything into a function:
func <- function()
{
png("test.png")
p = qplot(factor(step), y, data=x, colour=c))
p = p + theme_bw()
# etc...
p
dev.off()
}
If I call func() A PNG is created, but it is empty. Is there any specific reason why I can do this without the function but can't when I'm calling it from a function?
When using ggplot2 or lattice non-interactively (i.e. not from the command-line), you need to explicitly print() plots that you've constructed. So just do print(p) in the final line of your code, and all should be fine.
This is unintuitive enough that it's one of the most frequent of all FAQs.

Getting LaTeX into R Plots

I would like to add LaTeX typesetting to elements of plots in R (e.g: the title, axis labels, annotations, etc.) using either the combination of base/lattice or with ggplot2.
Questions:
Is there a way to get LaTeX into plots using these packages, and if so, how is it done?
If not, are there additional packages needed to accomplish this.
For example, in Python matplotlib compiles LaTeX via the text.usetex packages as discussed here: http://www.scipy.org/Cookbook/Matplotlib/UsingTex
Is there a similar process by which such plots can be generated in R?
The CRAN package latex2exp contains a TeX function that translate LaTeX formulas to R's plotmath expressions. You can use it anywhere you could enter mathematical annotations, such as axis labels, legend labels, and general text.
For example:
x <- seq(0, 4, length.out=100)
alpha <- 1:5
plot(x, xlim=c(0, 4), ylim=c(0, 10),
xlab='x', ylab=TeX(r'($\alpha x^\alpha$, where $\alpha \in \{1 \ldots 5\}$)'),
type='n', main=TeX(r'(Using $\LaTeX$ for plotting in base graphics!)', bold=TRUE))
for (a in alpha) {
lines(x, a*x^a, col=a)
}
legend('topleft',
legend=TeX(sprintf(r'($\alpha = %d$)', alpha)),
lwd=1,
col=alpha)
produces this plot.
Here's an example using ggplot2:
q <- qplot(cty, hwy, data = mpg, colour = displ)
q + xlab(expression(beta +frac(miles, gallon)))
As stolen from here, the following command correctly uses LaTeX to draw the title:
plot(1, main=expression(beta[1]))
See ?plotmath for more details.
You can generate tikz code from R:
http://r-forge.r-project.org/projects/tikzdevice/
Here's something from my own Lab Reports.
tickzDevice exports tikz images for LaTeX
Note, that in certain cases "\\" becomes "\" and "$" becomes "$\" as in the following R code: "$z\\frac{a}{b}$" -> "$\z\frac{a}{b}$\"
Also xtable exports tables to latex code
The code:
library(reshape2)
library(plyr)
library(ggplot2)
library(systemfit)
library(xtable)
require(graphics)
require(tikzDevice)
setwd("~/DataFolder/")
Lab5p9 <- read.csv (file="~/DataFolder/Lab5part9.csv", comment.char="#")
AR <- subset(Lab5p9,Region == "Forward.Active")
# make sure the data names aren't already in latex format, it interferes with the ggplot ~ # tikzDecice combo
colnames(AR) <- c("$V_{BB}[V]$", "$V_{RB}[V]$" , "$V_{RC}[V]$" , "$I_B[\\mu A]$" , "IC" , "$V_{BE}[V]$" , "$V_{CE}[V]$" , "beta" , "$I_E[mA]$")
# make sure the working directory is where you want your tikz file to go
setwd("~/TexImageFolder/")
# export plot as a .tex file in the tikz format
tikz('betaplot.tex', width = 6,height = 3.5,pointsize = 12) #define plot name size and font size
#define plot margin widths
par(mar=c(3,5,3,5)) # The syntax is mar=c(bottom, left, top, right).
ggplot(AR, aes(x=IC, y=beta)) + # define data set
geom_point(colour="#000000",size=1.5) + # use points
geom_smooth(method=loess,span=2) + # use smooth
theme_bw() + # no grey background
xlab("$I_C[mA]$") + # x axis label in latex format
ylab ("$\\beta$") + # y axis label in latex format
theme(axis.title.y=element_text(angle=0)) + # rotate y axis label
theme(axis.title.x=element_text(vjust=-0.5)) + # adjust x axis label down
theme(axis.title.y=element_text(hjust=-0.5)) + # adjust y axis lable left
theme(panel.grid.major=element_line(colour="grey80", size=0.5)) +# major grid color
theme(panel.grid.minor=element_line(colour="grey95", size=0.4)) +# minor grid color
scale_x_continuous(minor_breaks=seq(0,9.5,by=0.5)) +# adjust x minor grid spacing
scale_y_continuous(minor_breaks=seq(170,185,by=0.5)) + # adjust y minor grid spacing
theme(panel.border=element_rect(colour="black",size=.75))# border color and size
dev.off() # export file and exit tikzDevice function
Here's a cool function that lets you use the plotmath functionality, but with the expressions stored as objects of the character mode. This lets you manipulate them programmatically using paste or regular expression functions. I don't use ggplot, but it should work there as well:
express <- function(char.expressions){
return(parse(text=paste(char.expressions,collapse=";")))
}
par(mar=c(6,6,1,1))
plot(0,0,xlim=sym(),ylim=sym(),xaxt="n",yaxt="n",mgp=c(4,0.2,0),
xlab="axis(1,(-9:9)/10,tick.labels,las=2,cex.axis=0.8)",
ylab="axis(2,(-9:9)/10,express(tick.labels),las=1,cex.axis=0.8)")
tick.labels <- paste("x >=",(-9:9)/10)
# this is what you get if you just use tick.labels the regular way:
axis(1,(-9:9)/10,tick.labels,las=2,cex.axis=0.8)
# but if you express() them... voila!
axis(2,(-9:9)/10,express(tick.labels),las=1,cex.axis=0.8)
I did this a few years ago by outputting to a .fig format instead of directly to a .pdf; you write the titles including the latex code and use fig2ps or fig2pdf to create the final graphic file. The setup I had to do this broke with R 2.5; if I had to do it again I'd look into tikz instead, but am including this here anyway as another potential option.
My notes on how I did it using Sweave are here: http://www.stat.umn.edu/~arendahl/computing
I just have a workaround. One may first generate an eps file, then convert it back to pgf using the tool eps2pgf. See http://www.texample.net/tikz/examples/eps2pgf/
h <- rnorm(mean = 5, sd = 1, n = 1000)
hist(h, main = expression(paste("Sampled values, ", mu, "=5, ", sigma,
"=1")))
Taken from a very help article here https://stats.idre.ucla.edu/r/codefragments/greek_letters/
You can use the following, for example:
title(sub=TeX(sprintf(paste("Some latex symbols are ", r'(\lambda)', "and", r'(\alpha)'))))
Just remember to enclose LaTeX expressions in paste() using r'()'
You can also add named objects in the paste() function. E.g.,
lambda_variable <- 3
title(sub=TeX(sprintf(paste(r'(\lambda=)', lambda_variable))))
Not sure if there are better ways to do this, but the above worked for me :)

Resources