I've made a loop to create multiple boxplots. The thing is, I want to save all the boxplots without overwriting each other. Any suggestions?
This is my current code:
boxplot <- list()
for (x in 1:nrow(checkresults)){
boxplots <- boxplot(PIM[,x], MYC [,x], OBX[,x], WDR[,x], EV[,x],
main=colnames(PIM)[x],
xlab="PIM, MYC, OBX, WDR, EV")
}
Do you want to save them in some files, or save them to be able to look at them in different windows ?
If it is the first case, you can use a png, pdf or whatever function call inside your for loop :
R> for (i in 1:5) {
R> png(file=paste("plot",i,".png",sep=""))
R> plot(rnorm(10))
R> dev.off()
R> }
If you want to display them in separate windows, just use dev.new :
R> for (i in 1:5) {
R> dev.new()
R> plot(rnorm(10));
R> }
Just to add to #juba's answer, if you want to save the plots to a multi-page pdf file, then you don't have to use the paste command that #juba suggested. This
pdf("myboxplots.pdf")
for (x in seq_along(boxplots)){
boxplot(PIM[,x], MYC [,x], OBX[,x], WDR[,x],EV[,x],
main = colnames(PIM)[x],
xlab = "PIM, MYC, OBX, WDR, EV")
}
dev.off()
creates a single multi-page pdf document, where each page is a boxplot. If you want to store the boxplots in separate pdf documents, then use the file=paste command.
First, create a list of the right length - it just makes things easier and is good practice to allocate storage before filling objects in via a loop:
boxplots <- vector(mode = "list", length = nrow(checkresults))
Then we can loop over the data you want, assigning to each component of the boxplots list as we go, using the [[x]] notation:
for (x in seq_along(boxplots)){
boxplots[[x]] <- boxplot(PIM[,x], MYC [,x], OBX[,x], WDR[,x],EV[,x],
main = colnames(PIM)[x],
xlab = "PIM, MYC, OBX, WDR, EV")
}
Before, your code was overwriting the previous boxplot info during subsequent iterations.
Related
To minimize 3rd party package dependencies & reserve the ability to parallelize the code; this reproduceable example below is intended to create png images for each row step of a plot using R's Base graphics (no Tidyverse or GGPlot).
It, however, produces the entire series for each image, & not the intended iterative build required:
#
setwd("///images")
data(mtcars) # load DF
frames = 50 # set image qty rate
for(i in 1:frames){
# creating a name for each plot file with leading zeros
if (i < 10) {name = paste('000',i,'plot.png',sep='')}
if (i < 100 && i >= 10) {name = paste('00',i,'plot.png', sep='')}
if (i >= 100) {name = paste('0', i,'plot.png', sep='')}
png(name)
# plot(mtcars$mpg,type="l")
plot(mtcars$mpg)
dev.off()
}
my_cmd <- 'convert *.png -delay 5 -loop 5 mpg.gif'
system(my_cmd)
#
My own attempts to unsuccessfully resolve the issue include:
1) Remove the frame iteration & used nrows (mtcars) as the loop controlling agent?
2) Reference the row index somehow for each plot call?
3) Insert a sleep() call inside the loop after each plot?
4) Use the apply() function instead of a loop?
Any pointers or alternative coding to be more R efficient to make this work as intended?
Thanks.
This code will create one .png file for series of plots where each successive plot has one additional point on it:
# load data
data(mtcars)
# specify number of files to create (one per row of mtcars)
frames <- nrow(mtcars)
# figure out how many leading zeros will be needed in filename
ndigits <- nchar(as.character(frames))
for(i in 1:frames){
# name each file
zeros <- ndigits - nchar(as.character(i))
ichar <- paste0(strrep('0',zeros), i)
name <- paste0(ichar, 'plot.png')
# plot as .png
png(filename = name)
plot(x=1:i, y=mtcars$mpg[1:i], pch=20, col="blue",
xlim=c(0,frames), ylim=range(mtcars$mpg))
dev.off()
}
I generate a bunch of graphs and write them into a list variable, something like the following.
graphsListHolder <- list()
loop around the following code for as many plots as I make
filename <- paste some elements together to create a unique name
graphsListHolder[[filename]] <- p # p is the name of the ggplot plot
I save graphsListHolder as a .rds file.
Later I want to read in the res file, choose from plots in the graphsListHolder file and display with grid.arrange. I can hardcode the plot number and the following example works fine when run, plotting two graphs, one on top of the other.
grid.arrange(
graphsListHolder[[3]], graphsListHolder[[5]]
)
But if I construct a character variable temp like this (or variations on this)
temp <- "graphsListHolder[[3]], graphsListHolder[[5]]"
and change the grid.arrange code to
grid.arrange(
temp
)
I get
Error in gList(list("graphsListHolder[[3]], graphsListHolder[[5]]", wrapvp = list( :
only 'grobs' allowed in "gList"
In addition: Warning message:
In grob$wrapvp <- vp : Coercing LHS to a list
I also tried eval(parse(text = temp) without success.
I'm not sure how you want to choose them, but say you had a vector of the elements you wanted
x <- c(3,5)
Then you could do
grid.arrange(grobs=graphsListHolder[x])
Trying to turn arbitrary strings into executable code usually isn't a good idea. Often there are more "traditional" alternatives in R.
For example
graphsListHolder<-Map(function(x) {
ggplot(data.frame(x=1:10, y=x*1:10)) + geom_point(aes(x,y)) + ggtitle(x)}, 1:5)
x <- c(3,5)
grid.arrange(grobs=graphsListHolder[x])
I have a list, which contains 75 matrix with their names, and I want to do a plot for each matrix, and save each plot with the name that the matrix have.
My code do the plots with a loop and it works, I get 75 correct plots, but the problem is that the name of the plot file is like a vector "c(99,86,94....)",too long and I don´t know which one is.
I´m ussing that code, probably isn´t the best. I´m a beginner, and I have been looking for a solution one week, but it was impossible.
for (i in ssamblist) {
svg(paste("Corr",i,".svg", sep=""),width = 45, height = 45)
pairs(~CDWA+CDWM+HI+NGM2+TKW+YIELD10+GDD_EA,
data=i,lower.panel=panel.smooth, upper.panel=panel.cor,
pch=0, main=i)
dev.off()}
How put to a each plot his name?.
I try change "i" for names(i), but the name was the name of the first column,and only creates one plot. I try to do it with lapply but I could't.
PS: the plots are huge, and I have to expand the margins. I´m using Rstudio.
Thank you¡
Using for loop or apply:
# dummy data
ssamblist <- list(a = mtcars[1:10, 1:4], b = mtcars[11:20, 1:4], c = mtcars[21:30, 1:4])
# using for loop
for(i in names(ssamblist)) {
svg(paste0("Corr_", i, ".svg"))
pairs(ssamblist[[i]], main = i)
dev.off()}
# using apply
sapply(names(ssamblist), function(i){
svg(paste0("Corr_", i, ".svg"))
pairs(ssamblist[[i]], main = i)
dev.off()})
So I've created a loop that makes 10 individual plots:
for (k in 1:nrow(sites)) {
temp_title <- paste("site",k, "county", sites[k,2],"site",sites[k,3])
l <- which(hourly_nj_table$County.Code==sites[k,2]&hourly_nj_table$Site.Num==sites[k,3])#grab data for each site individually
temp_filename <- paste("/filepath",temp_title,".pdf")
PM_site <- hourly_nj_table[l,]
PM_site$realTime <- as.numeric(PM_site$Time.Local)
PM_mean_site <- aggregate(PM_site, by=list(PM_site$Time.Local),FUN="mean",na.rm=TRUE)
plot(PM_mean_site$realTime,PM_mean_site$Sample.Measurement, type="l",lwd=10,main=paste(temp_title),xlab="LocalTime",ylab="Ozone (ppm)")#,ylim=c(0,0.05))
}
But I would like to see how they compare on the same axis. Normally (if i'm just hardcoding it) I would add a new parameter and then create the next plot, but i'm unsure how to incorporate that into a loop.
The data all comes from one csv file if that helps..
Thanks!
You're really very close. Plot() gets the ball rolling, lines() will allow you to draw inside the plot:
for (k in 1:nrow(sites)) {
temp_title <- paste("site",k, "county", sites[k,2],"site",sites[k,3])
l <- which(hourly_nj_table$County.Code==sites[k,2]&hourly_nj_table$Site.Num==sites[k,3])#grab data for each site individually
temp_filename <- paste("/Users/bob111higgins/Documents/School/College/Rutgers/Atmospheric Research",temp_title,".pdf")
PM_site <- hourly_nj_table[l,]
PM_site$realTime <- as.numeric(PM_site$Time.Local)
PM_mean_site <- aggregate(PM_site, by=list(PM_site$Time.Local),FUN="mean",na.rm=TRUE) #Make it average by time of day so can make time series plots.
ifesle(k ==1 ,
plot(PM_mean_site$realTime,PM_mean_site$Sample.Measurement, type="l",lwd=10,main=paste(temp_title),xlab="LocalTime",ylab="Ozone (ppm)")#,ylim=c(0,0.05)),
lines(PM_mean_site$realTime,PM_mean_site$Sample.Measurement, lwd=10))
}
I'm sure there are better ways to go about this, but this is how I've done it in the past.
While fine-tuning parameters for plots I want to save all the test runs in different files so that they will not be lost. So far, I managed to do it using the code below:
# Save the plot as WMF file - using random numbers to avoid overwriting
number <- sample(1:20,1)
filename <- paste("dummy", number, sep="-")
fullname <- paste(filename, ".wmf", sep="")
# Next line actually creates the file
dev.copy(win.metafile, fullname)
dev.off() # Turn off the device
This code works, generating files with name "dummy-XX.wmf", where XX is a random number between 1 and 20, but it looks cumbersome and not elegant at all.
Is there any more elegant method to accomplish the same? Or even, to keep a count of how many times the code has been run and generate nice progressive numbers for the files?
If you really want to increment (to avoid overwriting what files already exist) you can create a small function like this one:
createNewFileName = function(path = getwd(), pattern = "plot_of_something", extension=".png") {
myExistingFiles = list.files(path = path, pattern = pattern)
print(myExistingFiles)
completePattern = paste0("^(",pattern,")([0-9]*)(",extension,")$")
existingNumbers = gsub(pattern = completePattern, replacement = "\\2", x = myExistingFiles)
if (identical(existingNumbers, character(0)))
existingNumbers = 0
return(paste0(pattern,max(as.numeric(existingNumbers))+1,extension))
}
# will create the file myplot1.png
png(filename = createNewFileName(pattern="myplot"))
hist(rnorm(100))
dev.off()
# will create the file myplot2.png
png(filename = createNewFileName(pattern="myplot"))
hist(rnorm(100))
dev.off()
If you are printing many plots, you can do something like
png("plot-%02d.png")
plot(1)
plot(1)
plot(1)
dev.off()
This will create three files "plot-01.png", "plot-02.png", "plot-03.png"
The filename you specify can take an sprintf-like format where the index of the plot in passed in. Note that counting is reset when you open a new graphics device so all calls to plot() will need to be done before calling dev.off().
Note however with this method, it will not look to see which files already exist. It will always reset the counting at 1. Also, there is no way to change the first index to anything other than 1.