If raster value NA search and extract the nearest non-NA pixel

后端 未结 3 2126
既然无缘
既然无缘 2021-02-15 10:11

On extracting values of a raster to points I find that I have several NA\'s, and rather than use a buffer and fun arguments of extra

3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-15 10:41

    This is a raster-based solution, by first filling the NA pixels with the nearest non-NA pixel value. Note however, that this does not take into account the position of a point within a pixel. Instead, it calculates the distances between pixel centers to determine the nearest non-NA pixel.

    First, it calculates for each NA raster pixel the distance and direction to the nearest non-NA pixel. The next step is to calculate the coordinates of this non-NA cell (assumes projected CRS), extract its value and to store this value at the NA location.

    Starting data: a projected raster, with identical values as in the answer from koekenbakker:

    set.seed(2)
    # set projected CRS
    r <- raster(ncol=10,nrow=10, xmn=0, xmx=10, ymn=0,ymx=10, crs='+proj=utm +zone=1') 
    r[] <- 1:10
    r[sample(1:ncell(r), size = 25)] <- NA
    
    # create sample points
    xy = data.frame(x=runif(10,1,10), y=runif(10,1,10))
    
    # use normal extract function to show that NAs are extracted for some points
    extracted <- raster::extract(x = r, y = xy)
    

    Calculate the distance and direction from all NA pixels to the nearest non-NA pixel:

    dist <- distance(r)  
    # you can also set a maximum distance: dist[dist > maxdist] <- NA
    direct <- direction(r, from=FALSE)
    

    Retrieve coordinates of NA pixels

    # NA raster
    rna <- is.na(r) # returns NA raster
    
    # store coordinates in new raster: https://stackoverflow.com/a/35592230/3752258 
    na.x <- init(rna, 'x')
    na.y <- init(rna, 'y')
    
    # calculate coordinates of the nearest Non-NA pixel
    # assume that we have a orthogonal, projected CRS, so we can use (Pythagorean) calculations
    co.x <- na.x + dist * sin(direct)
    co.y <- na.y + dist * cos(direct)
    
    # matrix with point coordinates of nearest non-NA pixel
    co <- cbind(co.x[], co.y[]) 
    

    Extract values of nearest non-NA cell with coordinates 'co'

    # extract values of nearest non-NA cell with coordinates co
    NAVals <- raster::extract(r, co, method='simple') 
    r.NAVals <- rna # initiate new raster
    r.NAVals[] <- NAVals # store values in raster
    

    Fill the original raster with the new values

    # cover nearest non-NA value at NA locations of original raster
    r.filled <- cover(x=r, y= r.NAVals)
    
    sampled <- raster::extract(x = r.filled, y = xy)
    
    # compare old and new values
    print(data.frame(xy, extracted, sampled))
    
    #           x        y extracted sampled
    # 1  5.398959 6.644767         6       6
    # 2  2.343222 8.599861        NA       3
    # 3  4.213563 3.563835         5       5
    # 4  9.663796 7.005031        10      10  
    # 5  2.191348 2.354228        NA       3
    # 6  1.093731 9.835551         2       2
    # 7  2.481780 3.673097         3       3
    # 8  8.291729 2.035757         9       9
    # 9  8.819749 2.468808         9       9 
    # 10 5.628536 9.496376         6       6
    

    Note that point 5 takes another value than the answer of Koekenbakker, since this method does not take into account the position of the point within a pixel (as mentioned above). If this is important, this solution might not be appropriate. In other cases, e.g. if the raster cells are small compared to the point accuracy, this raster-based method should give good results.

提交回复
热议问题