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.
Related
I have a function that takes a call xm, where xm is a learnt machine learning model. Is there a way tht within the function I can print the name of xm rather than the summary of the model which is what happens when you print(xm)
For example, my function generates graphs that I am saving within the function
modsummary <- function(xm){
mypath <- file.path("C:","Users","Documents",paste("rf_fit_hmeas_random", ".png", sep = ""))
png(file = mypath)
print(plot(xm))
dev.off()
}
modsummary(rf_fit)
What I am trying to do is set this up in way so that it will paste xm (in this case rf_fit) so that it automatically detecs the function called and replaces xm_hmeas_random each time a different model is called.
Thank you
Yes, you can use deparse(substitute(xm)) to get this.
So it would be..
modsummary <- function(xm){
mypath <- file.path("C:/","Users/","Documents/",paste0(deparse(substitute(xm)), "_hmeas_random.png"))
png(file = mypath)
print(plot(xm))
dev.off()
}
modsummary(rf_fit)
I've added in the slashes (/) between your directory names and switched to using paste0() which negates the need to specify a separator.
I am trying to run a simple 5 lines command but over 9000 different files. I wrote the following for loop
setwd("/Users/morandin/Desktop/Test")
output_file<- ("output_file.txt")
files <- list.files("/Users/morandin/Desktop/Test")
for(i in files) {
chem.w.in <- scan(i, sep=",")
pruned.tree<-drop.tip(mytree,which(chem.w.in %in% NA))
plot(pruned.tree)
pruned.tree.ja.chem.w.in <- phylo4d(pruned.tree, c(na.omit(chem.w.in)))
plot(pruned.tree.ja.chem.w.in)
out <- abouheif.moran(pruned.tree.ja.chem.w.in)
print(out)
}
Hey I am editing my question: the above code does the for loop perfectly now (thanks for all your help). I am still having an issue with the output.
I can redirect the entire output using R through bash commands but I would need the name of the processed file. My output looks like this:
class: krandtest
Monte-Carlo tests
Call: as.krandtest(sim = matrix(res$result, ncol = nvar, byrow = TRUE),
obs = res$obs, alter = alter, names = test.names)
Number of tests: 1
Adjustment method for multiple comparisons: none
Permutation number: 999
Test Obs Std.Obs Alter Pvalue
1 dt 0.1458514 0.7976225 greater 0.2
other elements: adj.method call
Is there a way to print Pvalue results and name of the file (element i)??
Thanks
Since Paul Hiemstra's answer answered #1, here's an answer to #2, assuming that by "answers" you mean "the printed output of abouheif.moran(pruned.tree.ja.chem.w.in)".
Use cat() with the argument append = true. For example:
output_file = "my_output_file.txt"
for(i in files) {
# do stuff
# make plots
out <- abouheif.moran(pruned.tree.ja.chem.w.in)
out <- sprintf("-------\n %s:\n-------\n%s\n\n", i, out)
cat(out, file = output_file, append = TRUE)
}
This will produce a file called my_output_file.txt that looks like:
-------
file_1:
-------
output_goes_here
-------
file_2:
-------
output_goes_here
Obviously the formatting is entirely up to you; I just wanted to demonstrate what could be done here.
An alternative solution would be to sink() the entire script, but I'd rather be explicit about it. A middle road might be to sink() just a small piece of the code, but except in extreme cases it's a matter of preference or style.
I suspect what is going wrong here is that list.files() by default returns a list of only the names of the files, not the entire path to the file. Setting full.names to TRUE will fix this issue. Note that you will not have to add the txt add the filename as list.files() already returns the full path to an existing file.
Hi I am performing a task on a text file chosen from file.choose which just separates out the lines and then adds a new number to each separation.
I would like to name the outputted file the same as file.choose but instead of .txt I would like it to be called .fa. So far I have
fileConn<-file("outputtbb.txt")
longlist <- readLines(file.choose())
lvls1 <- unique(longlist)
cat(paste0("Sequence>", seq_along(lvls1), "\n", lvls1, collapse="\n"), file=fileConn)
close(fileConn)
I know its something to do with changing file=fileConn but cant figure out how to manipulate it and all I get is outputtbb.
Please help!
You could seperate the readLines(file.choose()) to two lines.
filename <- file.choose()
longlist <- readLines(filename)
You now have file name available as a variable and you can bend it, you can twist it all day long (no reference to iPhone 6 bending intended).
To change endings, assuming no ".txt" appears anywhere else in the file name, this would work
x <- "file.txt"
sub(".txt", replacement = ".fa", x = x)
[1] "file.fa"
I have an R script that reads a certain type of file (nexus files of phylogenetic trees), whose name ends in *.trees.txt. It then applies a number of functions from an R package called bGMYC, available here and creates 3 pdf files. I would like to know what I should do to make the script loop through the files for each of 14 species.
The input files are in a separate folder for each species, but I can put them all in one folder if that facilitates the task. Ideally, I would like to output the pdf files to a folder for each species, different from the one containing the input file.
Here's the script
# Call Tree file
trees <- read.nexus("L_boscai_1411_test2.trees.txt")
# To use with different species, substitute "L_boscai_1411_test2.trees.txt" by the path to each species tree
#Store the number of tips of the tree
ntips <- length(trees$tip.label[[1]])
#Apply bgmyc.single
results.single <- bgmyc.singlephy(trees[[1]], mcmc=150000, burnin=40000, thinning=100, t1=2, t2=ntips, start=c(1,1,ntips/2))
#Create the 1st pdf
pdf('results_single_boscai.pdf')
plot(results.single)
dev.off()
#Sample 50 trees
n <- sample(1:length(trees), 50)
trees.sample <- trees[n]
#Apply bgmyc.multiphylo
results.multi <- bgmyc.multiphylo(trees.sample, mcmc=150000, burnin=40000, thinning=100, t1=2, t2=ntips, start=c(1,1,ntips/2))
#Create 2nd pdf
pdf('results_boscai.pdf') # Substitute 'results_boscai.pdf' by "*speciesname.pdf"
plot(results.multi)
dev.off()
#Apply bgmyc.spec and spec.probmat
results.spec <- bgmyc.spec(results.multi)
results.probmat <- spec.probmat(results.multi)
#Create 3rd pdf
pdf('trees_boscai.pdf') # Substitute 'trees_boscai.pdf' by "trees_speciesname.pdf"
for (i in 1:50) plot(results.probmat, trees.sample[[i]])
dev.off()
I've read several posts with a similar question, but they almost always involve .csv files, refer to multiple files in a single folder, have a simpler script or do not need to output files to separate folders, so I couldn't find a solution to my specific problem.
Shsould I use a for loop or could I create a function out of this script and use lapply or another sort of apply? Could you provide me with sample code for your proposed solution or point me to a tutorial or another reference?
Thanks for your help.
It really depends on the way you want to run it.
If you are using linux / command line job submission, it might be best to look at
How can I read command line parameters from an R script?
If you are using GUI (Rstudio...) you might not be familiar with this, so I would solve the problem
as a function or a loop.
First, get all your file names.
files = list.files(path = "your/folder")
# Now you have list of your file name as files. Just call each name one at a time
# and use for loop or apply (anything of your choice)
And since you would need to name pdf files, you can use your file name or index (e.g loop counter) and append to the desired file name. (e.g. paste("single_boscai", "i"))
In your case,
files = list.files(path = "your/folder")
# Use pattern = "" if you want to do string matching, and extract
# only matching files from the source folder.
genPDF = function(input) {
# Read the file
trees <- read.nexus(input)
# Store the index (numeric)
index = which(files == input)
#Store the number of tips of the tree
ntips <- length(trees$tip.label[[1]])
#Apply bgmyc.single
results.single <- bgmyc.singlephy(trees[[1]], mcmc=150000, burnin=40000, thinning=100, t1=2, t2=ntips, start=c(1,1,ntips/2))
#Create the 1st pdf
outname = paste('results_single_boscai', index, '.pdf', sep = "")
pdf(outnam)
plot(results.single)
dev.off()
#Sample 50 trees
n <- sample(1:length(trees), 50)
trees.sample <- trees[n]
#Apply bgmyc.multiphylo
results.multi <- bgmyc.multiphylo(trees.sample, mcmc=150000, burnin=40000, thinning=100, t1=2, t2=ntips, start=c(1,1,ntips/2))
#Create 2nd pdf
outname = paste('results_boscai', index, '.pdf', sep = "")
pdf(outname) # Substitute 'results_boscai.pdf' by "*speciesname.pdf"
plot(results.multi)
dev.off()
#Apply bgmyc.spec and spec.probmat
results.spec <- bgmyc.spec(results.multi)
results.probmat <- spec.probmat(results.multi)
#Create 3rd pdf
outname = paste('trees_boscai', index, '.pdf', sep = "")
pdf(outname) # Substitute 'trees_boscai.pdf' by "trees_speciesname.pdf"
for (i in 1:50) plot(results.probmat, trees.sample[[i]])
dev.off()
}
for (i in 1:length(files)) {
genPDF(files[i])
}
I have the need to build a function that will plot multiple pdfs, read them in, combine the results (different sized pdfs), save the combined file and delete the initial files. I'm getting hung up on the initial part of interactively plotting multiple plots to external pdfs. The problem is I need a way of pausing in the for loop, waiting for the plot and then moving on after receiving the plot. I thought readLines was the way to go (and it may be) but this did not work (i.e. no plot was produced).
How can I make R pause between pdf take the plot, move onto dev.off and reiterate through the process again? The desired outcome is to have three files in the wd called file1.pdf, file2.pdf and file3.pdf. Again, after running the loop/lapply, this process will be interactive.
This is a MWE of the problem:
widths <- c(10, 9, 8)
heights <- c(11, 9, 7)
file <- "foo.pdf"
lapply(1:3, function(i) { #will askfor/take 3 plots interactively
qo <- gsub(".pdf", paste0(i, ".pdf"), file, fixed = TRUE)
cat("plot now...")
pdf(file=qo, width = widths[i], height = heights[i])
#pause command here
dev.off()
})
#the interactive part
plot(1:10)
plot(1:13)
plot(1:15)
EDIT 1 Related question: Determine ghostscript version
EDIT 2 Here's a link to the package I used this information to create -click here-
Is it as simple as this?
for(i in 1:3){
cat(i, "\n")
cat("plot now...")
readLines(n=1)
}
This stops to read a single line from stdin, i.e. the console. Press Enter to carry on.
Are you looking for something like this?
widths <- c(10, 9, 8)
heights <- c(11, 9, 7)
file <- "foo.pdf"
lapply(1:3, function(i) {
qo <- gsub(".pdf", paste0(i, ".pdf"), file, fixed = TRUE)
pdf(file=qo, width = widths[i], height = heights[i])
# Reads string interactively
input <- scan("", what = "character", nmax=1, quiet=TRUE)
# Executes `input` as a command (possibly, needs extra check)
eval(parse(text=input))
dev.off()
})
This results in three files: foo1.pdf, foo2.pdf and foo3.pdf with plots produced using commands you typed interactively.