Search code examples
rterra

Addition of attribute data to classified raster giving weird results in terra R


I have a raster data that I have classified into 3 classes. Then I want to add values to each class. I am using the following code

library(terra)

f <- system.file("ex/elev.tif", package="terra") 
r <- rast(f)

# classify the values into three groups
m <- c(min(global(r, "min", na.rm=TRUE)), 275, 1,
       275, 410, 2,
       410, max(global(r, "max", na.rm=TRUE)), 3)

#Reclassify the raster stack
rclmat <- matrix(m, ncol=3, byrow=TRUE)
rc <- classify(r, rclmat, include.lowest=TRUE)
plot(rc)

#Add some values to raster attribute table
rc$code <- c(0.002, 0.0056, 0.0124)

#Generate raster using the new column
y <- as.numeric(rc, 2)
plot(y)

enter image description here

As you can see the second plot is weird. How can I rectify it?


Solution

  • Your example data

    library(terra)
    r <- rast(system.file("ex/elev.tif", package="terra") )
    m <- c(-Inf, 275, 1,
               275, 410, 2,
               410, Inf, 3)
    rclmat <- matrix(m, ncol=3, byrow=TRUE)
    rc <- classify(r, rclmat, include.lowest=TRUE)
    

    To assign attributes, you must use levels(x)<- (see ?levels). You use $<- but that creates a new layer.

    levels(rc) <- data.frame(ID=1:3, code=c(0.002, 0.0056, 0.0124))
    rc
    #class       : SpatRaster 
    #dimensions  : 90, 95, 1  (nrow, ncol, nlyr)
    #resolution  : 0.008333333, 0.008333333  (x, y)
    #extent      : 5.741667, 6.533333, 49.44167, 50.19167  (xmin, xmax, ymin, ymax)
    #coord. ref. : lon/lat WGS 84 (EPSG:4326) 
    #source(s)   : memory
    #categories  : code 
    #name        :   code 
    #min value   :  0.002 
    #max value   : 0.0124 
    

    If you now wanted to put the "code" values in the cells, you could proceed with

    y <- as.numeric(rc, 1)
    

    (it should be 1 rather than 2 as you only have one category.)

    You could also do that with

    rc <- classify(r, rclmat, include.lowest=TRUE)
    s <- subst(rc, 1:3, c(0.002, 0.0056, 0.0124))
    

    ut if that is the output you want, you should use these values in classify, so that you can do this in one step.

    m <- c(-Inf, 275, 0.002,  
            275, 410, 0.0056,
            410, Inf, 0.0124)
    
    rclmat <- matrix(m, ncol=3, byrow=TRUE)
    rc <- classify(r, rclmat, include.lowest=TRUE)
    

    Note that you can further simplify your original (not the one above) call to classify:

    rc <- classify(r, c(-Inf, 275, 410, Inf), include.lowest=TRUE)