The following code is a minimal example of what I have and what I am trying to achieve. The idea is I have a large chunk of code that builds up a plot in many steps. I want to save the plot as a png at different steps along the way.
This chunk works...
x<-runif(10)
y<-runif(10)
png(filename="Plot0.png")
plot(y~x)
abline(h=mean(y))
dev.off()
but when I split the plot chunks yet want to save each step individually there's a problem.
x<-runif(10)
y<-runif(10)
png(filename="Plot1.png")
plot(y~x)
dev.off()
png(filename="Plot2.png")
abline(h=mean(y))
dev.off()
The problem is plot.new has not been called yet. This I have searched but I can't seem to find the bits that make it work.
R handles basic plot that plot creates a new "sheet of paper" and other function such as abline can draw on top of it. Thus you cannot use abline without calling a plot first. You called dev.off which clears the previous plot, and therefore you don't have any plot to use abline with -> plot.new has not been called yet.
Basically you need to switch to the grid system to enable this.
You might want to consider switching to ggplot and saving the object along the way, or using ggsave.
Here's a solution using graphics which basically captures your base R plot on grid:
library(graphics)
x<-runif(10)
y<-runif(10)
plot(y~x)
pl <- recordPlot()
png(filename="Plot1.png")
grid::grid.newpage()
pl
dev.off()
abline(h=mean(y))
pl <- recordPlot()
png(filename="Plot2.png")
grid::grid.newpage()
pl
dev.off()
In ggplot, you can simply do:
library(ggplot2)
df = data.frame(
x<-runif(10),
y<-runif(10)
)
g = ggplot(df,aes(x=x,y=y))+geom_point()+theme_bw()
ggsave(g,file="Plot1.png")
g = g + geom_hline(yintercept=mean(y))
ggsave(g,file="Plot2.png")
Following the link given by duckmayr in the original question comments I was able to achieve the desired result. Throughout a construction one can simply include say p1<-recordplot() and then create the png of p1 at the end. I think that this is rather elegant.
x<-runif(10)
y<-runif(10)
dev.control(displaylist="enable")
plot(y~x)
p1 <- recordPlot()
abline(h=mean(y))
p2 <- recordPlot()
invisible(dev.off())
png(filename="Plot1.png")
p1
dev.off()
png(filename="Plot2.png")
p2
dev.off()
Related
I think I may have discovered a bug. I'm using levelplot in rasterVis, when I plot the rasters they show up fine in the raster window, however when I try and save them using png() the raster has lines through it.
library(raster)
library(rasterVis)
library(RColorBrewer)
col<-rasterTheme(region=brewer.pal(8,"YlOrRd"))
r<-raster(ncol=40,nrow=20)
r[] <- rnorm(n=ncell(r))
b<-"Title"
png(file=paste0(path,"\\",b,".png"), width=1800, height=1800, res=300)
plot<-levelplot(r,main=b,par.settings=col, margin=FALSE, scales=list(draw=FALSE))
print(plot)
dev.off()
In the plot window it shows up as it should:
But saved using png():
I figured it out, the margins parameter needs to be in the form of a list. Resolves the lines in the images.
plot<-levelplot(r,main=b,par.settings=col, margin=list(draw=FALSE,scales=list(draw=FALSE)))
I know most of the programers would refer me to 'LATTICE' or 'ggplot2' packages of R as a solution to this question, but there must be a way to do it with the base package. I want to plot multiple graphs with corresponding regression lines and correlation coefficients with simple loops. An easy example data may look like-
a=list(cbind(c(1,2,3), c(4,8,12)), cbind(c(5,15,25), c(10,30,50)))
par(mfrow=c(1,2))
lapply(1:length(a), function(i)
plot(a[[i]][,1], a[[i]][,2]))
lapply(1:length(a), function(i)
abline(lm(a[[i]][,2]~a[[i]][,1])))
require(plotrix)
lapply(1:length(a), function(i)
boxed.labels(a[[i]][,1][1], a[[i]][,2][3],
labels=paste(round(cor(a[[i]][,2], a[[i]][,1], use = "pairwise.complete.obs"),2)),
border=FALSE, adj=0.5, cex=0.8))
If you run the above script you'd notice that all linear lines and r-values will plot on the top of the last graph. Is there any way to write in the call for regression along with the plot command? Or any other clever way to deal with loops to plot regressions on corresponding figures?? It works fine for a single plot (shown below), but I'm working with a considerably large list!
plot(a[[1]][,1], a[[1]][,2])
abline(lm(a[[1]][,2]~a[[1]][,1]))
boxed.labels(a[[1]][,1][1], a[[1]][,2][3],
labels=paste(round(cor(a[[1]][,2], a[[1]][,1], use = "pairwise.complete.obs"),2)),
border=FALSE, adj=0.5, cex=0.8)
Once you call plot(), you start drawing in a new "cell". So if you want to add more to the plot before moving on to the next one, make sure you do all of your drawing before calling the next plot()
For example
a=list(cbind(c(1,2,3), c(4,8,12)), cbind(c(5,15,25), c(10,30,50)))
par(mfrow=c(1,2))
lapply(a, function(d) {
d <- setNames(data.frame(d), c("x","y"))
plot( y~x, d )
abline( lm( y ~ x, d ) )
boxed.labels(min(d$x), max(d$y),
labels=paste(round(cor(d$y, d$x, use = "pairwise.complete.obs"),2)),
border=FALSE, adj=0.5, cex=0.8)
})
Note how we do all the drawing inside a single lapply() so that abline and boxed.labels are called in between the multiple plot calls rather than after they are all done.
If I wanted to do this with the bars of the different calls to barplot(add=T) overlapping, that's fine and dandy. But say I want tthem to be plotted on the same plot, but with the first call having a ylim from 0:1 then the second call from 1:2 etc. I tried:
for(i in 1:length(files)) {
file <- as.matrix(read.table(files[i], header=F, sep=" ") )
if(i==1) barplot(file, beside=T, col=1:i, border=NA, ylim = c(0,length(files)))
if(i>1) barplot(file, beside=T, col=1:i, border=NA, ylim = c(i-1,i) ,xpd=T, add=T)
}
but that overlays them. How can I do it so that theyre on the same image but not overlapping if that makes sense. I envisage something like this http://img585.imageshack.us/img585/5439/romak13.png
If you're doing something like this, I'd recommend using ggplot2, as it's much easier.
Here's some sample code:
library(ggplot2)
data(diamonds)
ggplot(diamonds,aes(x=carat,y=price,fill=color))+
geom_histogram(stat='identity')+
facet_grid('cut~.',scale='free')+labs("Graph Title")
The output looks like this:
The interpretation of this particular graph is a bit strange, considering the nature of the data set, but if you follow the same format, you should be able to get a decent-looking graph. If anyone has any better data examples, let me know.
I am modifying a graph built with ggplot by altering the data produced by ggplot_build (for a reason similar to Include space for missing factor level used in fill aesthetics in geom_boxplot). As far as I understand the help I found on this topic, I should be able to save the result by applying ggplot_gtable and arrangeGrob before calling ggsave on the results (Saving grid.arrange() plot to file).
However I obtain an error "plot should be a ggplot2 plot", also with this simple reproductible example:
require('ggplot2')
require('gridExtra')
df <- data.frame(f1=factor(rbinom(100, 1, 0.45), label=c("m","w")),
f2=factor(rbinom(100, 1, 0.45), label=c("young","old")),
boxthis=rnorm(100))
g <- ggplot(aes(y = boxthis, x = f2, fill = f1), data = df) + geom_boxplot()
dd <- ggplot_build(g)
# Printing the graph works:
print(arrangeGrob(ggplot_gtable(dd)))
# Saving the graph doesn't:
ggsave('test.png',arrangeGrob(ggplot_gtable(dd)))
Can anybody explain why this does not work ? Is there a way to use ggsave after modifying the data by using ggplot_build() ?
(My version of the packages are gridExtra_0.9.1 and ggplot2_0.9.3.1)
it does not work because ggsave wants an object of class ggplot, while you're passing a grob. arrangeGrob will sometimes trick ggsave in pretending inheritance from ggplot, but only when at least one of the grobs belongs to this class; here, however, you're only passing a gtable.
Perhaps the easiest workaround is to clone ggsave and bypass the class check,
ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]
Edit: The dev version of ggplot2 no longer requires this hack*, as ggsave now works with any grob.
*PS: this hack works no longer, as arrangeGrob now returns a gtable, and its print method does not draw on a device.
A work around is to plot the gtable object with grid.draw() and then use dev.copy() to transfer the plot to a file.
Remember to use also dev.off() just afterward.
When using the pdf() function in R for saving a plot in an external file, we can specify width and/or height to adjust the size of the plot. However, there are situations when we obtain multiple plot (say using par(mfrow=c(2,4))). In this situation, it's kind of difficult to determine what is the best width and height for the PDF file in order to have all plots displayed properly. Is there a way to let R automatically "fit the plots" in the PDF file? I searched the arguments in pdf() and tried some, but the results are not satisfactory. Thank you very much!
How about something using ggplot?
require(ggplot2)
# Bogus data
x <- rnorm(10000)
y <- as.factor(round(rnorm(10000, mean=10, sd=2), 0))
df <- data.frame(vals=x, factors=y)
myplot <- ggplot(data=df, aes(x=vals)) +
geom_density() +
facet_wrap(~ factors)
ggsave(filename="~/foo.pdf", plot=myplot, width=8, height=10, units="in")
EDIT: Should you need to print over multiple pages, see this question.