rrasterspatialr-rasterterra

Conduct raster math on multiple rasters by matching file name strings


I have a set of rasters that I would like to subtract from another set of rasters, using simple raster math, but am having trouble matching the right rasters with their partners.

library(terra)

Simple raster math can be conducted easily between two rasters:

s <- rast(ncols = 22, nrows = 25, nlyrs = 1, xmin = 0, vals = 10)
p <- rast(ncols = 22, nrows = 25, nlyrs = 1, xmin = 0, vals = 8)

r <- s - p

However, I have a series of many rasters in a folder, and would like to conduct this math across many rasters, pairing them with their correct partners by matching strings in their files names.

My files look similar to this:

above_a.tif
above_b.tif
above_c.tif

below_a.tif
below_b.tif
below_c.tif

I would like to subtract all "below" rasters from all "above" rasters, based on their matching string at the end of their name. For example, I would like to subtract below_b.tif from above_b.tif .

I have tried the following to do this, but these code don't do what they need to: First, make a list of the two file types, which works well:

list_above <- list.files(pattern = 'above', all.files = T, full.names = F)

list_below <- list.files(pattern = 'below', all.files = T, full.names = F) 

Then, I tried subtracting them, but could not figure out how to incorporate the fact that I want to pair them by matching file name string:

temp_sub <- lapply(list_above, function(x) {
  to_subtract <- list_below
  subtracted <- x - to_subtract
  subtracted
})

Has someone done this before? It seems like something that would happen often with large spatial datasets. Maybe are you putting it into some kind of organized raster stack?


Solution

  • s <- terra::rast(ncols = 22, nrows = 25, nlyrs = 1, xmin = 0, vals = 10)
    p <- terra::rast(ncols = 22, nrows = 25, nlyrs = 1, xmin = 0, vals = 8)
    
    r <- s - p
    
    list_above <- list.files(pattern = "above", full.names = T)
    list_below <- list.files(pattern = "below", full.names = T)
    

    terra will treat your list as multilayer raster:

    s <- terra::rast(list_above)
    p <- terra::rast(list_below)
    
    s
    #> class       : SpatRaster 
    #> dimensions  : 25, 22, 3  (nrow, ncol, nlyr)
    #> resolution  : 8.181818, 7.2  (x, y)
    #> extent      : 0, 180, -90, 90  (xmin, xmax, ymin, ymax)
    #> coord. ref. : lon/lat WGS 84 (EPSG:4326) 
    #> sources     : above_a.tif  
    #>               above_b.tif  
    #>               above_c.tif  
    #> names       : lyr.1, lyr.1, lyr.1 
    #> min values  :    10,    10,    10 
    #> max values  :    10,    10,    10
    
    p
    #> class       : SpatRaster 
    #> dimensions  : 25, 22, 3  (nrow, ncol, nlyr)
    #> resolution  : 8.181818, 7.2  (x, y)
    #> extent      : 0, 180, -90, 90  (xmin, xmax, ymin, ymax)
    #> coord. ref. : lon/lat WGS 84 (EPSG:4326) 
    #> sources     : below_a.tif  
    #>               below_b.tif  
    #>               below_c.tif  
    #> names       : lyr.1, lyr.1, lyr.1 
    #> min values  :     8,     8,     8 
    #> max values  :     8,     8,     8
    

    And when you substract them, it will create another multilayer raster with proper values:

    r <- s - p
    r[[1]]
    #> class       : SpatRaster 
    #> dimensions  : 25, 22, 1  (nrow, ncol, nlyr)
    #> resolution  : 8.181818, 7.2  (x, y)
    #> extent      : 0, 180, -90, 90  (xmin, xmax, ymin, ymax)
    #> coord. ref. : lon/lat WGS 84 (EPSG:4326) 
    #> source(s)   : memory
    #> name        : lyr.1 
    #> min value   :     2 
    #> max value   :     2
    

    Created on 2024-01-08 with reprex v2.0.2