ia200
ia200

Reputation: 349

How to subset a SpatRasterDataset from the terra package?

I am trying to select several rasters from a SpatRasterDataset using the terra package in R. However when I try to select x rasters at once, the names show only the first x raster names, regardless of which rasters I try to select. Selecting a single raster seems to work fine, although the name given to it is not present.

So how do I properly subset a SpatRasterDataset keeping the correct names associated with rasters?

Reproducible example:

# Create SpatRasterDataset
r1 <- rast(matrix(1:100, nrow=10, ncol=10))
r2 <- rast(matrix(200:101, nrow=10, ncol=10))
r3 <- rast(matrix(c(2,200), nrow=10, ncol=10))
s <- sds(r1,r2,r3)

# Name rasters
names(s) <- c("A","B","C")
names(s)

# Add to list
l <- list(s)
l[[1]]
l[[1]][1:2] # shows rasters A,B
l[[1]][2:3] # also shows rasters A,B
l[[1]][c("B","C")] # shows rasters A,B
l[[1]][3] 
image(l[[1]][3]) # shows correct raster

# Subset SpatRasterDataset
s2 <- l[[1]][2:3] # select two rasters
names(s2) # names A, B
s2[1] # actually raster B
s2[2] # actually raster C

s3 <- l[[1]][3] # select one rasters
names(s3) # has some other name
s3 # has correct raster

Upvotes: 2

Views: 2380

Answers (2)

Anthony Martinez
Anthony Martinez

Reputation: 160

The answer provided by @robert-hijmans still results in unexpected behavior when subsetting a SpatRasterDataset with multi-layer sub-datasets. Here is an example with a SDS with the following structure:

s (`SpatRasterDataset`)
|-r1 (`SpatRaster`, multi-layer; "variable" or "sub-dataset")
  |-r1_1 (`SpatRaster`, single-layer; "layer")
  |-r1_2
  |-r1_3
|-r2
  |-r2_1
  |-r2_2
  |-r2_3
|-r3
  |-r3_1
  |-r3_2
  |-r3_3
# Create an SDS with 3 3-layer variables
r <- c(
  rast(matrix(1:100, nrow=10, ncol=10)),
  rast(matrix(200:101, nrow=10, ncol=10)),
  rast(matrix(c(2,200), nrow=10, ncol=10))
)

r1 <- deepcopy(r)
set.names(r1, c("r1_1", "r1_2", "r1_3"))

r2 <- deepcopy(r)
set.names(r2, c("r2_1", "r2_2", "r2_3"))

r3 <- deepcopy(r)
set.names(r3, c("r3_1", "r3_2", "r3_3"))

s <- sds(r1, r2, r3)
varnames(s) <- c("r1", "r2", "r3")

s_subset_1 <- s[2:3]
names(s_subset_1)  # Expect "r2" "r3" 
# [1] "r1" "r2"

names(s_subset_1$r1)
# [1] "r2_1" "r2_2" "r2_3"

So subsetting with an index does work, but the variable names are wrong. This is the simple solution I came up with - just setting the varnames with the character vector used to subset the SDS.

#' Subset SpatRasterDataFrame
#'
#' @param sds SpatRasterDataFrame
#' @param vars A character vector of variable names to be kept in the SDS
#'   sub-datasets
#'
#' @return A subset SpatRasterDataset where only the variables in `vars` are
#'   retained
subset_sds <- function(sds, vars) {
  sds_out <- sds[match(vars, varnames(sds))]
  varnames(sds_out) <- vars
  return(sds_out)
}

s_subset_2 <- subset_sds(s, c("r2", "r3"))

varnames(s_subset_2)
# [1] "r2" "r3"

names(s_subset_2$r2)
# [1] "r2_1" "r2_2" "r2_3"

Upvotes: 0

Robert Hijmans
Robert Hijmans

Reputation: 47146

The names of a SpatRasterDataset do not correspond to the (layer) names of a SpatRaster.

With your example

library(terra)
r1 <- rast(matrix(1:100, nrow=10, ncol=10))
r2 <- rast(matrix(200:101, nrow=10, ncol=10))
r3 <- rast(matrix(c(2,200), nrow=10, ncol=10))
s <- sds(r1,r2,r3)
names(s) <- c("A","B","C")

You can subset SpatRasterDataset s like this to get a new SpatRasterDataset:

s[2:3]
s[3, drop=FALSE]

Or like this to get a SpatRaster

s[3]

"A", "B", and "C" are names of the sub-datasets (variables), not the (layer) names of the SpatRasters. These cannot be the same because each sub-dataset has a single name, whereas a SpatRaster can have many (layer-) names.

For example, you might have

rr1 <- c(r1, r2, r3)
names(rr1) <- c("x", "y", "z")
rr2 <- rr1[[1:2]] / 10
rr3 <- r1 * 10
ss <- sds(rr1,rr2,rr3)
names(ss) <- c("A","B","C")

ss 
#class       : SpatRasterDataset 
#subdatasets : 3 
#dimensions  : 10, 10 (nrow, ncol)
#nlyr        : 3, 2, 1 
#resolution  : 1, 1  (x, y)
#extent      : 0, 10, 0, 10  (xmin, xmax, ymin, ymax)
#coord. ref. :  
#source(s)   : memory 
#names       : A, B, C 

ss[1]
#class       : SpatRaster 
#dimensions  : 10, 10, 3  (nrow, ncol, nlyr)
#resolution  : 1, 1  (x, y)
#extent      : 0, 10, 0, 10  (xmin, xmax, ymin, ymax)
#coord. ref. :  
#sources     : memory  
               memory  
               memory  
#varnames    : a 
#              b 
#              c 
#names       :   x,   y,   z 
#min values  :   1, 101,   2 

A SpatRaster can have a variable name which you can set with

varnames(r1) <- "A" 

but that is probably not what you are after.

Upvotes: 1

Related Questions