Search code examples
rloopsdirectoryasciiraster

Read Multiple raster with the same name contained in different folders


I am a R beginner and I want to read multiple ASCII text files with the same name but located in different folders. I have a folder that contains other folders named after different species (e.g. spp1). Inside each species folder, different there are folders for different models (e.g. model1) and, inside that there are ASCII files with the same name (e.g. var1.asc).

Example listing:

$ find path -type f
path/spp1/model1/var1.asc
path/spp1/model2/var1.asc
path/spp2/model1/var1.asc
path/spp2/model2/var1.asc

For each species, I need to read the ASCII files of all models it has and calculate the median of the values between models.

I tried first to create the file path for the spp1, for example:

## Create a list file with the the species ##
setwd("mypath")
data <-list.files(pattern=".csv")
## Create the names of all the species by reading the files and deleting 4 characters (".csv") ##
for (i in 1:length(names)){
   names <- substr(data[i],1,nchar(data[i])-4)

## Then i tried to read in loop the ascii files only saves me the last ascii, not a list of all ##
## Once i have the names i create all the paths for the species ##
   path <- paste0("mypath", names)
## Then i create the subfolders for each model with and list that contains this names ##
   path_m <- paste0(path, Model[i])
   for (i in 1:length(names)){
      models <- list.files(path_m,
                     pattern = ".asc",
                     full.names = TRUE)
      stack <- raster::stack(models)}

## Calculate the median ##
   median(models)
   }

I would appreciate any help and thank you so much for your time.


Edit

The name variable it is defined here as:

names <- substr(data[i],1,nchar(data[i])-4)

The original code is (formatted by editor):

library(raster)

## crear un listado de los nombres de mis especies ##
BASEDIR <- "D:/7_Doctorado/Sceloporus/3_Models/kuenm"

data <- list.files(file.path(BASEDIR, "1_Joint"), pattern=".csv")

for (i in 1:length(data)) {
    names <- substr(data[1], start=1, stop=nchar(data[1]) - 4)

    path_cal <- file.path(BASEDIR, paste0("ResultCalibracion_", names))
    setwd(path_cal)
    cal_res <- read.csv("best_candidate_models_OR_AICc.csv")
    row_names <- cal_res[, 1]

    for (i in 1:length(row_names)) {
        path <- file.path(BASEDIR,
                          paste0("Final_Models_", names),
                          paste0(row_names[i],"_NE"))
        models <- list.files(path,
                             pattern = "M_median.asc",
                             full.names = TRUE)
        stack <- raster::stack(models)
    }
    median_sp <- median(models)
    sd_sp <- sd(models)
    setwd(file.path(BASEDIR, "2_Models"))
    writeRaster(median_sp, filename=paste0(names, "_median"), format="ascii")
    writeRaster(sd_sp, filename=paste0(names, "_sd"), format="ascii")
}

It is hard to understand if you don't have the full context, that is why I prefer to explain the logic behind my question. The code above generates no errors, but the loop only reads the last ASCII file.


Solution

  • I was editing your question (indenting and simplifying the code a bit to facilitate its reading) and maybe I found the error.

    In the original code you added, the first statement of the outer loop reads:

    names <- substr(data[1], start=1, stop=nchar(data[1]) - 4)
    

    But it probably should use data[i] (with a lower case letter i instead of a digit 1).

    To avoid this kind of error, R allows iterating over vectors or lists directly, without the need of indexes. For example, the beginning of the loop:

    for (i in 1:length(data)) {
        names <- substr(data[i], start=1, stop=nchar(data[i]) - 4)
    

    Could be rewritten as:

    for (filename in data) {
        names <- substr(filename, start=1, stop=nchar(filename) - 4)
    

    Or even using a specialized function to remove the filename extension:

    for (filename in data) {
        names <- tools::file_path_sans_ext(filename)
        # Or as you knew the extension ("$" marks end-of-string):
        names <- sub('\\.asc$', '', filename)
    

    Using these kinds of dialects prevents that types of lookalike character typos and off-by-one bugs that are common when using bare indices.