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.
Related
I plot a simple linear regression using R.
I would like to save that image as PNG or JPEG, is it possible to do it automatically? (via code)
There are two different questions: First, I am already looking at the plot on my monitor and I would like to save it as is. Second, I have not yet generated the plot, but I would like to directly save it to disk when I execute my plotting code.
There are two closely-related questions, and an answer for each.
1. An image will be generated in future in my script, how do I save it to disk?
To save a plot, you need to do the following:
Open a device, using png(), bmp(), pdf() or similar
Plot your model
Close the device using dev.off()
Some example code for saving the plot to a png file:
fit <- lm(some ~ model)
png(filename="your/file/location/name.png")
plot(fit)
dev.off()
This is described in the (combined) help page for the graphical formats ?png, ?bmp, ?jpeg and ?tiff as well as in the separate help page for ?pdf.
Note however that the image might look different on disk to the same plot directly plotted to your screen, for example if you have resized the on-screen window.
Note that if your plot is made by either lattice or ggplot2 you have to explicitly print the plot. See this answer that explains this in more detail and also links to the R FAQ: ggplot's qplot does not execute on sourcing
2. I'm currently looking at a plot on my screen and I want to copy it 'as-is' to disk.
dev.print(pdf, 'filename.pdf')
This should copy the image perfectly, respecting any resizing you have done to the interactive window. You can, as in the first part of this answer, replace pdf with other filetypes such as png.
If you want to keep seeing the plot in R, another option is to use dev.copy:
X11 ()
plot (x,y)
dev.copy(jpeg,filename="plot.jpg");
dev.off ();
If you reach a clutter of too many plot windows in R, use graphics.off() to close all of the plot windows.
If you use ggplot2 the preferred way of saving is to use ggsave. First you have to plot, after creating the plot you call ggsave:
ggplot(...)
ggsave("plot.png")
The format of the image is determined by the extension you choose for the filename. Additional parameters can be passed to ggsave, notably width, height, and dpi.
Like this
png('filename.png')
# make plot
dev.off()
or this
# sometimes plots do better in vector graphics
svg('filename.svg')
# make plot
dev.off()
or this
pdf('filename.pdf')
# make plot
dev.off()
And probably others too. They're all listed together in the help pages.
For the first question, I find dev.print to be the best when working interactively. First, you set up your plot visually and when you are happy with what you see, you can ask R to save the current plot to disk
dev.print(pdf, file="filename.pdf");
You can replace pdf with other formats such as png.
This will copy the image exactly as you see it on screen. The problem with dev.copy is that the image is often different and doesn't remember the window size and aspect ratio - it forces the plot to be square by default.
For the second question, (as others have already answered), you must direct the output to disk before you execute your plotting commands
pdf('filename.pdf')
plot( yourdata )
points (some_more_data)
dev.off() # to complete the writing process and return output to your monitor
If you use R Studio http://rstudio.org/ there is a special menu to save you plot as any format you like and at any resolution you choose
If you open a device using png(), bmp(), pdf() etc. as suggested by Andrie (the best answer), the windows with plots will not pop up open, just *.png, *bmp or *.pdf files will be created. This is convenient in massive calculations, since R can handle only limited number of graphic windows.
However, if you want to see the plots and also have them saved, call savePlot(filename, type) after the plots are drawn and the window containing them is active.
plotpath<- file.path(path, "PLOT_name",paste("plot_",file,".png",sep=""))
png(filename=plotpath)
plot(x,y, main= file)
dev.off()
To add to these answers, if you have an R script containing calls that generate plots to screen (the native device), then these can all be saved to a pdf file (the default device for a non-interactive shell) "Rplots.pdf" (the default name) by redirecting the script into R from the terminal (assuming you are running linux or OS X), e.g.:
R < myscript.R --no-save
This could be converted to jpg/png as necessary
In some cases one wants to both save and print a base r plot. I spent a bit of time and came up with this utility function:
x = 1:10
basesave = function(expr, filename, print=T) {
#extension
exten = stringr::str_match(filename, "\\.(\\w+)$")[, 2]
switch(exten,
png = {
png(filename)
eval(expr, envir = parent.frame())
dev.off()
},
{stop("filetype not recognized")})
#print?
if (print) eval(expr, envir = parent.frame())
invisible(NULL)
}
#plots, but doesn't save
plot(x)
#saves, but doesn't plot
png("test.png")
plot(x)
dev.off()
#both
basesave(quote(plot(x)), "test.png")
#works with pipe too
quote(plot(x)) %>% basesave("test.png")
Note that one must use quote, otherwise the plot(x) call is run in the global environment and NULL gets passed to basesave().
dev.copy(png,'path/pngFile.png')
plot(YData ~ XData, data = mydata)
dev.off()
I am trying to create a plot and eventually save it as a file. But because I am making a lot of changes and want to test it out, I want to be able to view and save the plot at the same time. I have looked at this page to do what I want to do but in my system, it does not seem to be working as it is supposed to.
Here are my codes:
png('Save.png')
sample.df <- data.frame(group = c('A','B','A','C','B','A','A','C','B','C','C','C','B'),
X = c(2,11,3,4,1,6,3,7,5,9,10,2,8),
Y = c(3,8,5,2,7,9,3,6,6,1,3,4,10))
plot(Y ~ X, data = sample.df)
dev.copy(png, 'Save.png')
dev.off()
There are several issues (I am new to R so I might be missing something entirely):
(1) When I use png(), I cannot view the plot in RStudio so I used dev.copy() but it does not allow me to view my plot in R studio
(2) Even after I use dev.off(), I cannot view the saved file until I close the RStudio (says "Windows Photo Viewer can't open this picture because the picture is being edited in another program"). I need to restart every time so it is very inconvenient.
What am I doing wrong and how could I view and view saved file without restarting RStudio every time? Thank you in advance!
Addition
Based on Love Tätting's comments, when I run dev.list(), this is what I get.
> png('Save.png')
>
> sample.df <- data.frame(group = c('A','B','A','C','B','A','A','C','B','C','C','C','B'),
+ X = c(2,11,3,4,1,6,3,7,5,9,10,2,8),
+ Y = c(3,8,5,2,7,9,3,6,6,1,3,4,10))
>
> plot(Y ~ X, data = sample.df)
>
> dev.copy(png, 'Save.png')
png
3
> dev.off()
png
2
> dev.list()
png
2
> dev.off()
null device
1
> dev.list()
NULL
Why do I not get RStudioGD?
RStudio has its own device, "RStudioGD". You can see it with dev.list(), where it by default is the first and only one.
R's design for decoupling rendering and backend is by the abstraction of devices. Which ones you can use is platform and environment dependent. dev.list() shows the stack of current devices.
If I understand your problem correctly you want to display the graph first in RStudio, and then decide whether you want to save it or not. Depending on how often you save th image you could use the 'export' button in the plot pane in RStudio and save it manually.
Otherwise, your choice of trying to copy it would be the obvious one for me as well.
To my knowledge the device abstraction in R does not allow one to encapsulate the device as an object, so one for example could make it an argument to a function that does the actual plot. Since dev.set() takes an index as argument, passing the index as argument will be dependent on state of the stack of devices.
I have not come up with a clean solution to this myself and have sometimes retorted to bracketing the plot rendering code with a call to a certain device and saving it right after, and switching device depending on a global.
So, if you can, use RStudios export functionality, otherwise an abstraction would need to maintain the state of the global stack of devices and do extensive testing of its state as it is global and you cannot direct a plot call to a certain device, it simply plots to the current device (to my knowledge).
Edit after OP comment
It seems that it is somewhat different behaviour you are experiencing if you cannot watch the file after dev.off, but also need to quit RStudio. For some type of plot frameworks there is a need to call print on the graphical object to have it actually print to the file. Perhaps this is done by RStudio at shutdown as part of normal teardown procedures of open devices? In that ase the file should be empty if you forcibly look in its contents before quiting RStudio.
The other thing that sometimes work is to call dev.off twice. I don't know exactly why, but sometimes more devices get created than I have anticipated. After you have done dev.off, what does dev.list show?
Edit after OP's edit
I can see that you do, png(); dev.copy(); dev.off(). This will leave you with one more device opened than closed. You will still have the first graphics device that you started open as can be seen when you do the listing. You can simply remove dev.copy(). The image will be saved on dev.off() and should be able to open from the filesystem.
As to why you cannot see the RStudio graphics device, I am not entirely sure. It might be that other code is messing with your device stack. I would check in a clean session if it is there to make sure other code isn't tampering with the device stack. From RStudio forums and other SO questions there seem to have been plot pane related problems in RStudio that have resolved after updating RStudio to the latest. If that is a viable solution for you I would try that.
I've just added support for RStudio's RStudioGD device to the developer's version of R.devices package (I'm the author). This will allow you to do the following in RStudio:
library("R.devices")
sample.df <- data.frame(
group = c('A','B','A','C','B','A','A','C','B','C','C','C','B'),
X = c(2,11,3,4,1,6,3,7,5,9,10,2,8),
Y = c(3,8,5,2,7,9,3,6,6,1,3,4,10)
)
figs <- devEval(c("RStudioGD", "png"), name = "foo", {
plot(Y ~ X, data = sample.df)
})
You can specify any set of output target types, e.g. c("RStudioGD", "png", "pdf", "x11"). The devices that output to file will by default write the files in folder figures/ with filenames as <name>.<ext>, e.g. figures/foo.png in the above example.
The value of the call, figs, holds references to all figures produced, e.g. figs$png. You can open them directly from R using the operator !. For example:
> figs$png
[1] "figures/foo.png"
> !figs$png
[1] "figures/foo.png"
The latter call should show the PNG file using your system's PNG viewer.
Until I submit these updates to CRAN, you can install the developer's version (2.15.1.9000) as:
remotes::install_github("HenrikBengtsson/R.devices#develop")
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()
I do a lot of data exploration in R and I would like to keep every plot I generate (from the interactive R console). I am thinking of a directory where everything I plot is automatically saved as a time-stamped PDF. I also do not want this to interfere with the normal display of plots.
Is there something that I can add to my ~/.Rprofile that will do this?
The general idea is to write a script generating the plot in order to regenerate it. The ESS documentation (in a README) says it well under 'Philosophies for using ESS':
The source code is real. The objects are realizations of the
source code. Source for EVERY user modified object is placed in a
particular directory or directories, for later editing and
retrieval.
With any editor allows stepwise (or regionwise) execution of commands you can keep track of your work this way.
The best approach is to use a script file (or sweave or knitr file) so that you can just recreate all the graphs when you need them (into a pdf file or other).
But here is the start of an approach that does the basics of what you asked:
savegraphs <- local({i <- 1;
function(){
if(dev.cur()>1){
filename <- sprintf('graphs/SavedPlot%03d.pdf', i)
dev.copy2pdf( file=filename )
i <<- i + 1
}
}
})
setHook('before.plot.new', savegraphs )
setHook('before.grid.newpage', savegraphs )
Now just before you create a new graph the current one will be saved into the graphs folder of the current working folder (make sure that it exists). This means that if you add to a plot (lines, points, abline, etc.) then the annotations will be included. However you will need to run plot.new in order for the last plot to be saved (and if you close the current graphics device without running another plot.new then that last plot will not be saved).
This version will overwrite plots saved from a previous R session in the same working directory. It will also fail if you use something other than base or grid graphics (and maybe even with some complicated plots then). I would not be surprised if there are some extra plots on occasion that show up (when internally a plot is created to get some parameters, then immediatly replaced with the one of interest). There are probably other things that I have overlooked as well, but this might get you started.
you could write your own wrapper functions for your commonly used plot functions. This wrapper function would call both the on-screen display and a timestamped pdf version. You could source() this function in your ~/.Rprofile so that it's available every time you run R.
For latice's xyplot, using the windows device for the on-screen display:
library(lattice)
my.xyplot <- function(...){
dir.create(file.path("~","RPlots"))
my.chart <- xyplot(...)
trellis.device(device="windows",height = 8, width = 8)
print(my.chart)
trellis.device(device = "pdf",
file = file.path("~", "RPlots",
paste("xyplot",format(Sys.time(),"_%Y%m%d_%H-%M-%S"),
".pdf", sep = "")),
paper = "letter", width = 8, height = 8)
print(my.chart)
dev.off()
}
my.data <- data.frame(x=-100:100)
my.data$y <- my.data$x^2
my.xyplot(y~x,data=my.data)
As others have said, you should probably get in the habit of working from an R script, rather than working exclusively from the interactive terminal. If you save your scripts, everything is reproducible and modifiable in the future. Nonetheless, a "log of plots" is an interesting idea.
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)