I would like to print multiple graphs in one pdf file. I know there has been a lot on this, but I would like to print different window/graph sizes for each page, i.e. first page a 8.5x11, second page 11x8.5 and so on. I tried this:
pdf(file="Combined_Graphs.pdf",onefile=TRUE,bg="white",width=8.5,height=11)
hist(rnorm(100))
pdf(file="Combined_Graphs.pdf",onefile=TRUE,width=11, height=8.5, bg="white")
hist(rnorm(100,10,2),col="blue")
dev.off()
I must be using onefile=TRUE wrong as it only generates the last graphic before closing. Is there a better way to size the graphic device without having to call the pdf function twice?
What I would do is produce seperate PDF's and them combine them later. I use the PDF toolkit for this. Wrapping this in an R function using a system call through system even makes it scriptable from R. The call to pdftk will look something like:
pdftk *pdf cat output combined.pdf
or in R:
system("pdftk *pdf cat output combined.pdf")
combine_pdfs = function(path, output_pdf) {
system(sprintf("pdftk %s/*pdf cat output %s"), path, output_pdf)
}
I think what you are trying to do cannot be done in R, i.e., you need to use external tools such as the PDF toolkit as suggested by Paul Hiemstra to combine separate PDF files with varying page dimensions (an alternative tool is PDFjam).
If you set onefile = TRUE in your call to pdf(), each plot that is written to that PDF device will be printed on a separate page, yet with the same page dimensions. In your example, you open a first PDF device, write one plot to it, then you open a second PDF device, write a different plot to it, and then close the second PDF device but leave the first PDF device open. Since you use the same file argument for both pdf() calls, you might not notice that the first PDF device is still open. If you closed it, only the first plot would end up in "Combined_Graphs.pdf".
Here is a modified version of your example that illustrates how PDF devices are opened, filled with content, and closed:
pdf(file = "foo.pdf", onefile = TRUE, width = 8.5, height = 11)
hist(rnorm(100))
hist(rnorm(100, 10, 2), col = "red")
pdf(file = "bar.pdf", width =11, height = 8.5)
hist(rnorm(100, 10, 2), col = "blue")
dev.off()
dev.off()
Related
I have 3 R plots saved as pdf files (upper_left.pdf, upper_right.pdf, lower.pdf) as vector graphic and want to make a one-page pdf file and arrange them on it as follows:
What I have tried already
I have tried reading the pdf's using magick::image_read_pdf and appending them using magick::image_append. More specifically,
library(magick)
panel.ul <- image_read_pdf("upper_left.pdf")
panel.ur <- image_read_pdf("upper_right.pdf")
panel.l <- image_read_pdf("lower.pdf")
whole <- c(panel.ul, panel.ur) %>%
image_append() %>%
c(panel.l) %>%
image_append(stack = TRUE)
The first issue is magick::image_read_pdf imports the plot as png (if I'm right, not vector graphic though).
magick::image_append also 'works' and gives me what I want in viewer pane (in RStudio, next to Help).
I then try to save them using export::graph2pdf(whole), but it gives me a blank page.
So, if I am to use magick, there are two issues that need to be solved:
importing plots as vector graphic objects (do not know the technical term in R)
Exporting the stacked plot to a vector pdf file.
How can I solve it? thanks in advance.
You're basically done. You only need to add
plot(whole) # plot the external object generated in ImageMagick to R's plotting device
savePlot(type = "pdf") # saves the current plotting device to a pdf file.
You will find your plot in your workoing directory called "Rplot.pdf".
savePlot has many options to customize your pdf output. Make sure to check ?savePlot.
To recreate your scheme from above youll need to temporarily save the upper panel as a separate pdf before you paste it to on top of the lower panel:
whole2 <- image_append(c(panel.ul, panel.ur))
plot(whole2)
savePlot("whole2.pdf", type = "pdf")
If the upper and lower panel do not look proportionate you can use the heght and width parameters of savePlot to adjust the size of the first pdf.
panel.upr <- image_read_pdf("whole2.pdf")
final <- image_append(c(image_append(panel.upr),panel.l), stack = TRUE)
plot(final)
savePlot("final.pdf", type = "pdf")
I know that
pdf("myOut.pdf")
will print to a PDF in R. What if I want to
Make a loop that prints subsequent graphs on new pages of a PDF file (appending to the end)?
Make a loop that prints subsequent graphs to new PDF files (one graph per file)?
Did you look at help(pdf) ?
Usage:
pdf(file = ifelse(onefile, "Rplots.pdf", "Rplot%03d.pdf"),
width, height, onefile, family, title, fonts, version,
paper, encoding, bg, fg, pointsize, pagecentre, colormodel,
useDingbats, useKerning)
Arguments:
file: a character string giving the name of the file. For use with
'onefile=FALSE' give a C integer format such as
'"Rplot%03d.pdf"' (the default in that case). (See
'postscript' for further details.)
For 1), you keep onefile at the default value of TRUE. Several plots go into the same file.
For 2), you set onefile to FALSE and choose a filename with the C integer format and R will create a set of files.
Not sure I understand.
Appending to same file (one plot per page):
pdf("myOut.pdf")
for (i in 1:10){
plot(...)
}
dev.off()
New file for each loop:
for (i in 1:10){
pdf(paste("myOut",i,".pdf",sep=""))
plot(...)
dev.off()
}
pdf(file = "Location_where_you_want_the_file/name_of_file.pdf", title="if you want any")
plot() # Or other graphics you want to have printed in your pdf
dev.off()
You can plot as many things as you want in the pdf, the plots will be added to the pdf in different pages.
dev.off() closes the connection to the file and the pdf will be created and you will se something like
> dev.off()
null device 1
I know that
pdf("myOut.pdf")
will print to a PDF in R. What if I want to
Make a loop that prints subsequent graphs on new pages of a PDF file (appending to the end)?
Make a loop that prints subsequent graphs to new PDF files (one graph per file)?
Did you look at help(pdf) ?
Usage:
pdf(file = ifelse(onefile, "Rplots.pdf", "Rplot%03d.pdf"),
width, height, onefile, family, title, fonts, version,
paper, encoding, bg, fg, pointsize, pagecentre, colormodel,
useDingbats, useKerning)
Arguments:
file: a character string giving the name of the file. For use with
'onefile=FALSE' give a C integer format such as
'"Rplot%03d.pdf"' (the default in that case). (See
'postscript' for further details.)
For 1), you keep onefile at the default value of TRUE. Several plots go into the same file.
For 2), you set onefile to FALSE and choose a filename with the C integer format and R will create a set of files.
Not sure I understand.
Appending to same file (one plot per page):
pdf("myOut.pdf")
for (i in 1:10){
plot(...)
}
dev.off()
New file for each loop:
for (i in 1:10){
pdf(paste("myOut",i,".pdf",sep=""))
plot(...)
dev.off()
}
pdf(file = "Location_where_you_want_the_file/name_of_file.pdf", title="if you want any")
plot() # Or other graphics you want to have printed in your pdf
dev.off()
You can plot as many things as you want in the pdf, the plots will be added to the pdf in different pages.
dev.off() closes the connection to the file and the pdf will be created and you will se something like
> dev.off()
null device 1
I am trying to capture all plots a user makes in a script and save it in a folder. I have tried png("C:/path/to/plotfolder/Rplot%03d.png") and it works great for most plots. Unfortunately the department got alot of functions that use the windows() function. Those plots are not captured, and I've been unable to find a function that can capture plots send to those devices.
png("path/to/somewhere/plot.png")
windows()
plot(1:20)
dev.off()
This creates an empty file called plot.png.
I would really like to avoid forcing users to avoid those functions or rewrite them, so is there any way to capture plots send to a windows() device with a single call as in png()? If this is not the case, I guess i will have to just remove the windows() calls from the scripts or something.
Extra information
I need this since i'm trying to create a rscript function that runs a script and saves all output including warnings,errors, prints and plots to a specific folder that can then later be opened by another application. I would like not to interfere with the users code forcing them to make alternate functions when working with this script.
edit
Tried looking into knitr, as it seems to be able to find and save plots in windows() devices, but so far i have been unable to find anything. UPDATE: Not compatible with what i want
edit
I have found something that could work sometimes, but not a solution. Using savePlot in a while loop could save all open windows, but if several plots have been send to the device it will only save the last
I have found somewhat of a solution, though i would like a better solution. Since it's an supposed to run as an rscript i just replaced windows() with a wrapper for png(). As
windows <- function (width = 480, height = 480, pointsize = 12, record, rescale, xpinch,
ypinch, bg = "white", canvas, gamma, xpos, ypos, buffered, title, restoreConsole = TRUE,
clickToConfirm, fillOddEven, family = "sans", antialias = c("default", "none", "cleartype", "grey", "subpixel"),
filename = plotoutput) {
png(filename,width,height,pointsize,bg,restoreConsole,family,antialias)
}
Thanks for the help James.
I have written a function that creates a barplot. I would like to save this plot as a pdf as well as display it on my screen (x11) when applying this function. The code looks like this.
create.barplots <- function(vec)
{
x11() # opens the window
### Here is a code that creates a barplot and works perfectly
### but irrelevant for my question
dev.copy(pdf("barplots.table.2.pdf")) # is supposed to copy the plot in pdf
# under the name "barplots.table.2.pdf"
dev.off() # is supposed to close the pdf device
}
This creates the following error: 'device' should be a function
When I modify the code to:
create.barplots <- function(vec)
{
x11()
### Here is a code that creates a barplot and works perfectly
### but irrelevant for my question
dev.copy(pdf) # This is the only difference to the code above
dev.off()
}
R displays the plot and creates a file called Rplots.pdf. This is a problem because of several reasons.
I also tried to open the devices the other way around. First open the pdf device, than copy the content of the pdf device into the x11 device, than set the pdf device as active and than close the pdf device. The code here looks like this:
create.barplots <- function(vec)
{
pdf("barplots.table.2.pdf") # open the pdf device
### Here is a code that creates a barplot and works perfectly
### but irrelevant for my question
dev.copy(x11) # copy the content of the pdf device into the x11 device
dev.set(which = 2) # set the pdf device as actice
dev.off() # close the pdf device
}
The problem here is that the wondow that is supposed to display the plot is empty!
To sum up, I have two questions:
1) How to save a plot as pdf and display it in x11 simultaneously? And
2) How to save the plot not in the working directory somewhere else?
EDIT
The solutions above work great. But I still do not understand why
pdf("barplots.table.2")
barplot(something)
dev.copy(x11)
displays an empty grey window instead of copying the content of the pdf device in the window device! I also tried
pdf("barplots.table.2")
barplot(something)
dev.copy(window)
In which I failed as well...
How about:
create.barplots <- function(...) {
x11()
plot.barplots(...) # create the barplot
dev.copy2pdf(file = "path/to/barplots.table.2.pdf")
}
You can easily add arguments for pdf in the dev.copy call, like this:
create.barplots <- function(vec,dir,file)
{
windows()
plot(vec)
dev.copy(pdf,file=paste(dir,file,sep="/")
dev.off()
}
dev.copy() has a ... argument to pass arguments to the pdf function, see also ?dev.copy. Alternatively you can use dev.copy2pdf , as Max told you. I'd also advise you to use windows() instead of x11(), otherwise you might have trouble with the font families. The defaults for x11 and pdf don't always match.
To save a file in another directory, just add the full directory (eg with paste, like in the function above)
As I mentioned in a previous post, you may consider my knitr package; if you use it in an interactive R session, you will be able to see the plots in a window and save them to pdf without any hacks (it is the default behavior). I still need a lot of efforts on the documentation and demos, but it should be able to work with an Rnw document. The main reason that you can both see the plots and save them in knitr is, knitr is very different with Sweave in design -- the graphical device is opened after the code is evaluated, so your plots will not be hidden in an off-screen device. Again, I need to warn you that it is highly experimental at the moment.
Following works nicely for me when called from inside functions. Call it after the plot code:
pdf2 <- function (file = "plot.pdf", w = 10, h = 7.07, openPDF = FALSE)
{
dev.copy2pdf(file = file, width = w, height = h, out.type = "pdf")
if(openPDF) browseURL(file)
}
NB. openPDF may only work in Windows with full (not relative) file path.
Based on the answer by Max Gasner, I wrote this helper function which allows to quickly switch from displaying and not. The argument x is a plot object or the function that does the drawing.
savepdf<-function(x, file, display=TRUE) {
if (display){
x;
dev.copy2pdf(file=file)
}
else {
pdf(file=file)
x;
dev.off()
}
}
Example:
savepdf(plot(c(1,2,3)), file="123.pdf", display=F)