loading R objects and creating graphs with rscript - r

I am loading all the .RData files in a directory one at a time. Depending on the objects within the .RData files, I want to create graphs. But the print statement returns NULL so my assignment statement to x is not working. What am I doing wrong?
for (i in dir("c:\\data", pattern = "^data"))
{
tmpenv <- new.env()
load(i, envir=tmpenv)
for (y in ls(envir=tmpenv))
{
x <- tmpenv$y
print(head(x))
}
}

Related

Batch-reading mesh3D objects with the 'file2mesh' function from the 'Morpho' package

I am trying to batch-read a series of ply-meshes (as mesh3D objects), in order to slide semilandmarks with 'slider3d'. However, when I try to use a loop to read those files, I am told that the object 'Mesh' could not be found. This indicates that a mesh object must first be created in order to then be altered in a loop. How do I solve this?
Is there a simple function in the 'rgl' package that I overlooked?
Or is there an alternative to read all 3D-meshes in one folder, and create a list that I can use to match files downstream?
library(Morpho)
FilesPLY <- list.files("HumerusPLY",pattern="*.ply")
for(j in 1:length(FilesPLY)){
Mesh[j] <- file2mesh(paste("HumerusPLY/",FilesPLY[j],sep=""), clean = TRUE, readcol = FALSE)
}
Error: Object 'Mesh' could not be found.
One way to solve the problem is by creating a list of empty files, and then reading the meshes into the empty files. Oddly enough the first read-out results in an error, but it sets up the system for the read-in. I don't understand the problem behind it, but it works. Thus, here is the temporary solution:
library(Morpho)
# Read ply-list from subfolder "HumerusPLY/"; Create Mesh series of objects, and fill them
FilesPLY <- list.files("HumerusPLY/",pattern="*.ply")
for(i in 1:length(FilesPLY)) {
assign(paste("Mesh",i,sep=""), i)
}
meshlist <- c(1:length(FilesPLY))
for (i in 1:length(meshlist)){
meshlist[i] <- paste("Mesh",meshlist[i],sep="")
}
meshlist <- noquote(meshlist)
ls()
##read ply-files; the second read fixes an error, but does not work without the first read
for(j in 1:length(meshlist)){
meshlist[j] <- file2mesh(paste("HumerusPLY/",FilesPLY[j],sep=""), clean = TRUE, readcol = FALSE)
}
for(j in 1:length(meshlist)){
meshlist[[j]] <- file2mesh(paste("HumerusPLY/",FilesPLY[j],sep=""), clean = TRUE, readcol = FALSE)
}

Using for loop to write data frame as dta file in R

I have data frames in a list a and I want to use a loop to save these as both rda and write as dta. I don't get why I get the error message that object data frame cannot be found:
for (f in a) {
for (name in 1:length(filenames)) {
save(as.data.frame(f),file = paste("~/Dropbox/Data_Insert/Panels/",name,end_rda,sep=""))
write.dta(as.data.frame(f),file = paste("~/Dropbox/Data_Insert/Panels/",name,end_dta,sep=""))
}
}
Error in save(as.data.frame(f), file = paste("~/Dropbox/Data_Insert/Panels/", :
object ‘as.data.frame(f)’ not found
So by f, this would be indexing the data frame in the list? I did as.data.frame(f) because when I only used f, I got the message:
The object "dataframe" must have class data.frame
I changed the code to for f in a, but it still returns an error saying that as.data.frame(f) not found.
I think that this is what you are trying to do. I assume that a is a list of data frames and filenames is a character vector of the same length.
for (i in 1:length(a)) {
to_save = as.data.frame(a[[i]])
save(to_save, file = paste0("~/Dropbox/Data_Insert/Panels/", filenames[i], end_rda))
write.dta(to_save, file = paste0("~/Dropbox/Data_Insert/Panels/", filenames[i], end_dta))
}
Note that save preserves the name of the R object, so when you load any of these files it will be loaded into the workspace with the name to_save. This seems bad. For individual R objects I would strongly encourage you to use saveRDS and create .RDS files instead of save. See, e.g., Ricardo's answer to this question for an example of Rda vs RDS.

How To Create R Data Frame From List In Loop

I'm having trouble returning data frames from a loop in R. I have a set of functions that reads in files and turns them into data frames for the larger project to use/visualize.
I have a list of file names to pass:
# list of files to read
frameList <-c("apples", "bananas", "pears")
This function iterates over the list and runs the functions to create the data frames if they are not already present.
populateFrames <- function(){
for (frame in frameList){
if (exists(frame) && is.data.frame(get(frame))){
# do nothing
}
else {
frame <- clean_data(gather_data(frame))
}
}
}
When executed, the function runs with no errors, but does not save any data frame to the environment.
I can manually run the same thing and that saves a data frame:
# manually create "apples" data frame
apples <- clean_data(gather_data(frameList[1]))
From my reading through similar questions here, I see that assign() is used for similar things. But in the same way as before, I can run the code manually fine; but when put inside the loop no data frame is saved to the environment.
# returns a data frame, "apples" to the environment
assign(x = frame[1], value = clean_data(gather_data(frame[1])))
Solutions, following the principle of "change as little about the OPs implementation as possible".
You have two problems here.
Your function is not returning anything, so any changes that happen are stuck in the environment of the function
I think you're expecting the re-assignment of framein the elsestatement to re-assign it to that element in frameList. It's not.
This is the NOT RECOMMENDED* way of doing this where you assign a variable in the function's parent environment. In this case you are populatingFrames as a side effect, mutating the frameList in the parent environment. Mutating the input is generally something you want to avoid if you want to practice defensive programming.
populateFrames <- function(){
for (i in seq_along(frameList)){
if (exists(frameList[[i]]) && is.data.frame(get(frameList[[i]]))){
# do nothing
}
else {
frameList[[i]] <<- clean_data(gather_data(frameList[[i]]))
}
}
}
This is the RECOMMENDED version where you return the new frameList (which means you have to assign it to a value).
populateFrames <- function(){
for (i in seq_along(frameList)){
if (exists(frameList[[i]]) && is.data.frame(get(frameList[[i]]))){
# do nothing
}
else {
frameList[[i]] <- clean_data(gather_data(frameList[[i]]))
}
}
frameList
}
Avoiding global variable assignments, which are typically a no-no, try lapply:
lapply(
frameList,
function(frame){
if(exists(frame) && is.data.frame(get(frame))){
frame
}else{
clean_data(gather_data(frame))
}
}
)

How to read all the files in a folder using R and create objects with the same file names?

I need to create a function in R that reads all the files in a folder (let's assume that all files are tables in tab delimited format) and create objects with same names in global environment. I did something similar to this (see code below); I was able to write a function that reads all the files in the folder, makes some changes in the first column of each file and writes it back in to the folder. But the I couldn't find how to assign the read files in to an object that will stay in the global environment.
changeCol1 <- function () {
filesInfolder <- list.files()
for (i in 1:length(filesInfolder)){
wrkngFile <- read.table(filesInfolder[i])
wrkngFile[,1] <- gsub(0,1,wrkngFile[,1])
write.table(wrkngFile, file = filesInfolder[i], quote = F, sep = "\t")
}
}
You are much better off assigning them all to elements of a named list (and it's pretty easy to do, too):
changeCol1 <- function () {
filesInfolder <- list.files()
lapply(filesInfolder, function(fname) {
wrkngFile <- read.table(fname)
wrkngFile[,1] <- gsub(0, 1, wrkngFile[,1])
write.table(wrkngFile, file=fname, quote=FALSE, sep="\t")
wrkngFile
}) -> data
names(data) <- filesInfolder
data
}
a_list_full_of_data <- changeCol1()
Also, F will come back to haunt you some day (it's not protected where FALSE and TRUE are).
add this to your loop after making the changes:
assign(filesInfolder[i], wrkngFile, envir=globalenv())
If you want to put them into a list, one way would be, outside your loop, declare a list:
mylist = list()
Then, within your loop, do like so:
mylist[[filesInfolder[i] = wrkngFile]]
And then you can access each object by looking at:
mylist[[filename]]
from the global env.

Garbage collection com object in R

I want to be able to open an excel session from R, write to it and then close the excel session from R. While I can do this all from within the same function, I am trying to generalize the code for the cleanup of excel. However, somehow when I make the call to gc() from a function by passing in the excel object, it does not garbage collect. Below is the code:
opentest<-function() {
excel<-comCreateObject("Excel.Application")
comSetProperty(excel,"Visible",T)
comSetProperty(excel,"DisplayAlerts",FALSE)
comSetProperty(excel, "SheetsInNewWorkbook", 1)
wb <- comGetProperty(excel, "Workbooks")
wb <- comInvoke(wb, "Add")
excel
}
cleanupexcel<-function(excelobj) {
comInvoke(excelobj,"Quit")
rm(excelobj, envir=globalenv())
eapply(env=globalenv(), gc)
}
With the following calls to the function:
excelobj<- opentest()
cleanupexcel(excelobj)
When I call the two functions above, I can still see the excel session running in my task manager. However, if I make the call to gc() after returning from cleanupexcel(), it kills the excel session successfully.
Any ideas on how I can gc successfully from a generic function or is there some other issue that I am having here?
Here's a small change to your code that should work (I'm on Linux now, so I can't test it).
The main fix is to wrap the excel instance in an environment and return that instead.
The close can then access the instance and then remove it (ensuring no reference to it remains) before calling gc():
opentest<-function() {
excel<-comCreateObject("Excel.Application")
comSetProperty(excel,"Visible",T)
comSetProperty(excel,"DisplayAlerts",FALSE)
comSetProperty(excel, "SheetsInNewWorkbook", 1)
wb <- comGetProperty(excel, "Workbooks")
wb <- comInvoke(wb, "Add")
# wrap excel in an environment
env <- new.env(parent=emptyenv())
env$instance <- excel
env
}
cleanupexcel<-function(excel) {
comInvoke(excel$instance,"Quit")
rm("instance", envir=excel)
gc()
}
myexcel <- opentest()
cleanupexcel(myexcel)
...Note that your old code requires the variable to be named "excelobj" since you remove it from within the cleanupexcel function. That's not great.
OK, there are very subtle issues at play, so here's a reproducible example without excel:
opentest<-function() {
excel<-new.env()
reg.finalizer(excel, function(x) { cat("FINALIZING EXCEL!\n") }, FALSE)
# wrap excel in an environment
env <- new.env(parent=emptyenv())
env$instance <- excel
env
}
cleanupexcel<-function(excel) {
cat(excel$instance,"\n")
rm("instance", envir=excel)
gc()
}
myexcel <- opentest()
cleanupexcel(myexcel)
# Prints "FINALIZING EXCEL!"

Resources