Search code examples
rspatialterra

Specifying layers when using rast(..., type=xyz) to convert data.frame to SpatRaster in the terra package (R)


I have a simple csv file with lon/lat/time/values columns:

df <- data.frame(longitude=rep(c(10.5,11,12),10),
  latitude=rep(c(10.5,11,12),10),
  date= as.Date(rep(c("2012-01-01", "2012-02-01", "2012-03-01"), 10)),
  vals=rnorm(30,10,5))

I'd like to convert this to a SpatRaster using the S4 method for signature 'data.frame' rast(x, type="xyz", crs="", digits=6, extent=NULL), where each "date" would be a seperate layer.

Importing without the date works fine:

df.subset <- select(df,-date) 

tmp <- terra::rast(df.subset, type="xyz")

I've tried to split the SpatRaster by date but get a Error in .local(x, f, ...) : length(f) == nlyr(x) is not TRUE error:

split(tmp, as.factor(df$date))

I can think of an approach using a loop that

  1. splits the df by date: split(df, c("2012-01-01", "2012-02-01", "2012-03-01"))

  2. creates seperate SpatRasters for each individual date

  3. Use merge to combine individual SpatRasters with named layers

Is there a tidier way of doing this in terra?


Solution

  • Here is how you can use split or reshape

    Example data

    library(terra)
    set.seed(0)
    df <- data.frame(longitude=rep(seq(10,19,1), 3),
      latitude=rep(seq(10, 19,1), 3),
      date= as.Date(rep(c("2012-01-01", "2012-02-01", "2012-03-01"), each=10)),
      vals=rnorm(30,10,5))
    

    reshape

    w <- reshape(df, timevar="date", idvar=c("longitude", "latitude"), direction="wide")
    x <- rast(w, type="xyz")
    

    split

    r <- split(df[,-3], df$date)
    r <- lapply(r, \(i) rast(i, type="xyz")) 
    r <- rast(r)
    
    # and perhaps
    time(r) <- as.Date(names(r))
    
    r
    #class       : SpatRaster 
    #dimensions  : 10, 10, 3  (nrow, ncol, nlyr)
    #resolution  : 1, 1  (x, y)
    #extent      : 9.5, 19.5, 9.5, 19.5  (xmin, xmax, ymin, ymax)
    #coord. ref. :  
    #source(s)   : memory
    #names       : 2012-01-01, 2012-02-01, 2012-03-01 
    #min values  :    2.30025,   3.812308,   3.577003 
    #max values  :   22.02327,  13.817967,  15.428847 
    time (days)  : 2012-01-01 to 2012-03-01
    

    You could also do the splitting "manually", inside the lapply loop

    ud <- unique(df$date)
    x <- lapply(ud, \(d) rast(df[df$date == d, -3], type="xyz"))
    x <- rast(x)
    names(x) <- ud