3

The following code works great on individual rasters and gives me the information that I want:

r<-rast("LuckSpring_2001.tif")
activeCat(r)<-"Class_name"
r

f <- freq(r)
f$area <- f$count * 0.00009
f$percent = round(100 * f$area / sum(f$area), 1)
f

I'm wondering if there is a way to loop this code so I can apply it to multiple rasters and not have to do them all individually. A note that my rasters have different extents and class names.

0

2 Answers 2

5

You can do this by reading the rasters into a list object then iterating through the resulting list, defining a function that operates on each raster.

This creates the list object containing rasters.

rasters <- lapply(list.files(getwd(), pattern="tif$", 
                  full.names=TRUE), rast)

Now, we can operate on the list using lapply as our iterator and bind the results together.

results <- lapply(rasters, function(r) {
  activeCat(r) <- "Class_name"
  f <- freq(r)
  f$area <- f$count * res(r)[1]
  f$percent <- round(f$area / sum(f$area) * 100, 0))
})
( results <- do.call(rbind, results) )
2
  • That's definitely much cleaner than what I came up with! Thanks so much :) Commented Jun 8, 2023 at 15:39
  • 1
    @bigblue5295 Ah, but you did figure it out yourself! List objects are great for acting as "containers". You can then iterate through them using lapply. They come in quite handy and have numerous tidy related functions that can operate on them as well. Becoming well versed in using apply-type (apply, tapply, lapply, mapply) functions can make things considerably easier, and more efficient, as well. Commented Jun 8, 2023 at 17:51
2

I figured it out! Putting the code that worked for me here in case anybody else wants it.

    # Define the list of raster files 
    raster_files <- list.files(path=("C:/Users/"), pattern='\\.tif$', 
    full.names=TRUE)

    # Initialize an empty list to store the results
    result_list <- list()

    # Loop over each raster file
    for (file in raster_files) {
    # Read the raster file
    r <- rast(file)
    # Set the active category to "Class_name"
    activeCat(r) <- "Class_name"
    # Calculate frequency and area
    f <- freq(r)
    f$area <- f$count * 0.0009 #this number changes depending on resolution 
    f$percent <- round(100 * f$area / sum(f$area), 1)
    result_list[[file]] <- f
    }

    #List results
    for (i in seq_along(result_list)) {
    cat("Raster File:", names(result_list)[i], "\n")
    print(result_list[[I]])
    cat("\n")
    }

    #This makes a results table
    result_table <- bind_rows(result_list, .id = "raster_name")'
1
  • 1
    Tip: if you have some functionality that works as a little self-contained "block", write a function that takes parameters and returns the desired output. Then you can test this on single data items and put it in loops for when you have many. It also makes your code more readable. Your entire loop is then something like: for(file in files){result[[file]] = count_area_percent(file)} and it makes solutions using lapply (see J Evans' answer) neater too.
    – Spacedman
    Commented Jun 8, 2023 at 6:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.