Multiple plots in a for loop with Sweave - r

My chunk in Sweave:
<<fig=TRUE,echo=FALSE>>=
for(i in 1:10) {
plot(rep(i,10))
dev.new()
}
#
In the resulting pdf I get only one plot (from the first iteration). I would like to have all of the 10 plots printed. What am I doing wrong? I tried replacing dev.new() with frame() and plot.new() but nothing happened.

As #rawr suggests the easiest solution is to switch to knitr (there's really no reason at all not to!) and put fig.keep="all" in your code chunk options (if you switch to knitr you don't need fig=TRUE any more ... including figures works automatically, fig.keep="none" is the analogue of fig=FALSE)
Alternatively, if you want to stick with vanilla Sweave, check the Sweave manual p. 17:
A.9 Creating several figures from one figure chunk does not work
Consider that you want to create several graphs in a loop similar to
<<fig=TRUE>>
for (i in 1:4) plot(rnorm(100)+i)
#
This will currently not work, because Sweave allows only one graph per figure chunk. The simple reason is that Sweave opens a postscript device before executing the code and closes it
afterwards. If you need to plot in a loop, you have to program it along the lines of
<<results=tex,echo=FALSE>>=
for(i in 1:4){
file=paste("myfile", i, ".eps", sep="")
postscript(file=file, paper="special", width=6, height=6)
plot(rnorm(100)+i)
dev.off()
cat("\\includegraphics{", file, "}\n\n", sep="")
}
#

Related

Why am I unable to see multiple plots appear with a for loop?

This is my code which is part of a larger script.
for(d1 in names(survD)){
survfit1 <- survfit(Surv(time=survD[[d1]][,"time"],
event=survD[[d1]][,"death"],type='right')~1)
png(paste(survPath,"/surv_",d1,".png",sep=""))
plot(survfit1,xlab="Years",ylab="Survival probability",xmax=xmax1)
}
I don't have a good idea of what this code does yet, so I'm trying to look at each individual plot to see what it is. The problem is, whenever I run this in the R command line in the terminal in linux, nothing appears. I have to use dev.off() multiple times and then rerun this code:
plot(survfit1)
for something to appear. How can I see all the plots?
Sounds like this is really what you want:
for(d1 in names(survD)){
survfit1 <- survfit(Surv(time=survD[[d1]][,"time"],
event=survD[[d1]][,"death"],type='right')~1)
x11() ## open up new graphical window for each plot (to avoid overwriting)
plot(survfit1,xlab="Years",ylab="Survival probability",
xmax=xmax1, main = d1) ## use different titles to distinguish those plots
}
This will produce plots on normal graphical windows.
If you want to use the original code, you'd better do this way:
for(d1 in names(survD)){
survfit1 <- survfit(Surv(time=survD[[d1]][,"time"],
event=survD[[d1]][,"death"],type='right')~1)
png(paste(survPath,"/surv_",d1,".png",sep=""))
plot(survfit1,xlab="Years",ylab="Survival probability",xmax=xmax1)
dev.off()
}
Then, have a look at the directory given by getwd(). All the plots are saved in png files.
Calling Sys.sleep(.1) might help during the for loop. Maybe try:
for(d1 in names(survD)){
survfit1 <- survfit(Surv(time=survD[[d1]][,"time"],
event=survD[[d1]][,"death"],type='right')~1)
Sys.sleep(.1)
png(paste(survPath,"/surv_",d1,".png",sep="", collapse="))
plot(survfit1,xlab="Years",ylab="Survival probability",xmax=xmax1)
dev.off()
}

how do you print ggplot output inside a for loop in sweave [duplicate]

My chunk in Sweave:
<<fig=TRUE,echo=FALSE>>=
for(i in 1:10) {
plot(rep(i,10))
dev.new()
}
#
In the resulting pdf I get only one plot (from the first iteration). I would like to have all of the 10 plots printed. What am I doing wrong? I tried replacing dev.new() with frame() and plot.new() but nothing happened.
As #rawr suggests the easiest solution is to switch to knitr (there's really no reason at all not to!) and put fig.keep="all" in your code chunk options (if you switch to knitr you don't need fig=TRUE any more ... including figures works automatically, fig.keep="none" is the analogue of fig=FALSE)
Alternatively, if you want to stick with vanilla Sweave, check the Sweave manual p. 17:
A.9 Creating several figures from one figure chunk does not work
Consider that you want to create several graphs in a loop similar to
<<fig=TRUE>>
for (i in 1:4) plot(rnorm(100)+i)
#
This will currently not work, because Sweave allows only one graph per figure chunk. The simple reason is that Sweave opens a postscript device before executing the code and closes it
afterwards. If you need to plot in a loop, you have to program it along the lines of
<<results=tex,echo=FALSE>>=
for(i in 1:4){
file=paste("myfile", i, ".eps", sep="")
postscript(file=file, paper="special", width=6, height=6)
plot(rnorm(100)+i)
dev.off()
cat("\\includegraphics{", file, "}\n\n", sep="")
}
#

Plot in nowhere

I am using the function plotMDS() of package limma that makes a plot by the simple plot() format of R, and also returns the position of the points on the plot as output. I want to use the output of plotMDS() to produce my own beautiful plot.
Is there any way to run plotMDS() without having it's plot really generated? The reason I ask so is that I have already casted the output to a PDF file and I don't want the original plot of the plotMDS() to be there!
Thanks #BenBolker, it can be done like this:
pdf("Some file")
...
dev.new() # Putting new plots to nowhere
mds <- plotMDS(data)
dev.off() # Restoring new plots to the PDF file
plot(...) # Making the desired plot using mds
...
dev.off() # Closing PDF file
Looking at your answer it seems like this might be a reasonable alternative:
mds <- plotMDS(data)
pdf("Some file")
...
plot(...) # Making the desired plot using mds
...
dev.off() # Closing PDF file
I don't know exactly what you're doing but if you're interested in reproducible documents then you could also use the knitr package to create your output. It would be very easy to suppress a single plot and then plot later using knitr.

Save ggplot within a function

I'm trying to save a ggplot within a function using graphics devices. But I found the code produces empty graphs. Below is a very very simple example.
library(ggplot2)
ff <- function(){
jpeg("a.jpg")
qplot(1:20, 1:20)
dev.off()
}
ff()
If I only run the content of the function, everything is fine. I know that using ggsave() will do the thing that I want, but I am just wondering why jpeg() plus dev.off() doesn't work. I tried this with different versions of R, and the problem persists.
You should use ggsave instead of the jpeg(); print(p); dev.off() sequence. ggsave is a wrapper that does exactly what you intend to do with your function, except that it offers more options and versatility. You can specify the type of output explicitly, e.g. jpg or pdf, or it will guess from your filename extension.
So your code might become something like:
p <- qplot(1:20, 1:20)
ggsave(filename="a.jpg", plot=p)
See ?ggsave for more details
The reason why the original behaviour in your code doesn't worked is indeed a frequently asked question (on stackoverlflow as well as the R FAQs on CRAN). You need to insert a print statement to print the plot. In the interactive console, the print is silently execututed in the background.
These plots have to be printed:
ff <- function(){
jpeg("a.jpg")
p <- qplot(1:20, 1:20)
print(p)
dev.off()
}
ff()
This is a very common mistake.

Print to PDF in a for loop

I want to loop over a plot and put the result of the plot in a PDF.
The following code is used to do this:
What this does is loop 3 times and plot 3 different plots from the iris dataset. Then it should save it to the C:/ drive. The PDF files are created, but are corrupted.
for(i in 1:3){
pdf(paste("c:/", i, ".pdf", sep=""))
plot(cbind(iris[1], iris[i]))
dev.off()
}
To drawn lattice plots on the device, one needs to print the object produced by a call to one of the lattice graphics functions. Normally, in interactive use, R auto prints objects if not assigned. In loops however, auto printing does not work, so one must arrange for the object to be printed, usually by wrapping it in print().
Here is an example (please excuse my abuse of the formula notation ;-):
require(lattice)
for(i in 1:3) {
pdf(paste("plot", i, ".pdf", sep = ""))
print(xyplot(iris[,1] ~ iris[,i], data = iris))
dev.off()
}
This produces the three plots on a pdf device.
Is a file name that contains "c:/" a valid file name on your OS? That looks like part of the working directory that you'd want to set before calling pdf. I get an error telling me it can't open that file:
Error in pdf(paste("c:/", i, ".pdf", sep = "")) :
cannot open file 'c:/1.pdf'
If I drop the "c:/" bit from the file name, three PDFs are generated properly. Also, if you move the dev.off() outside of the for loop, you'll get a single PDF with three pages instead of three PDFs. May or may not be what you want...
for(i in 1:3){
pdf(paste("plot", i,".pdf",sep=""))
plot(cbind(iris[1],iris[i]))
dev.off()
}

Resources