R terra rasterization create vertical white lines - r

I have a raster raster_coarse at 0.25 resolution
class : SpatRaster
dimensions : 26, 31, 1 (nrow, ncol, nlyr)
resolution : 0.25, 0.25 (x, y)
extent : -87.75, -80, 24.5, 31 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : layer1
min value : 0.08839285
max value : 0.11517857
I have another raster raster_fine at finer resolution
class : SpatRaster
dimensions : 2377, 2758, 1 (nrow, ncol, nlyr)
resolution : 0.002777778, 0.002777778 (x, y)
extent : -87.6361, -79.97499, 24.39723, 31.00001 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : finer_res
min value : 0
max value : 1
Here's what I am trying to do. I want to populate every pixel in raster_fine with the values from raster_coarse. The way I approached this is:
# check the resolution difference
res_drop <- res(raster_coarse)[1]/res(raster_fine)[1] # 89.99999.
# disaggregate the raster_coarse
raster_coarse <- terra::disagg(raster_coarse, fact = res_drop)
# convert to points
raster_coarse_df <- as.data.frame(raster_coarse, xy = T, na.rm = TRUE)
raster_coarse_pts <- terra::vect(raster_coarse_df, geom = c("x", "y"), crs(raster_fine))
# create a blank canvas
canvas <- terra::rast(xmin = ext(raster_fine)[1],
xmax = ext(raster_fine)[2],
ymin = ext(raster_fine)[3],
ymax = ext(raster_fine)[4],
resolution = res(raster_fine),
crs = crs(raster_fine))
# populate the blank canvas with raster_coarse_pts
raster_coarse <- terra::rasterize(x = raster_coarse_pts , y = canvas, field = "layer1", fun = max, touches = T, background = NA)
raster_coarse
class : SpatRaster
dimensions : 2377, 2758, 1 (nrow, ncol, nlyr)
resolution : 0.002777778, 0.002777778 (x, y)
extent : -87.6361, -79.97499, 24.39723, 31.00001 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : lyr.1
min value : 0.08839285
max value : 0.11517857
plot(raster_coarse)
I am not able to understand why the vertical white lines are coming from?

Example data
library(terra)
r <- rast(nrow=26, ncol=31, ext=c(-87.75, -80, 24.5, 31))
f <- geodata::gadm("USA", level=1, path=".")
f <- f[f$NAME_1 == "Florida", ]
values(r) <- runif(ncell(r))
r <- mask(r, f)
fine <- rast(nrow=2377, ncol=2758, ext=c(-87.6361, -79.97499, 24.39723, 31.00001))
The solution is to use resample
rr <- resample(r, x, "near")
Instead of the nearest neighbor you could use, for example, bilinear interpolation:
rr <- resample(r, x)
The white lines occur because with your method there will be cells that are not covered. To better understand that you could crop out a small area and plot the points on top of the raster.

Related

Reorder each pixel of a SpatRaster by size

I have a SpatRaster with 100 layers, each corresponding to a result of a bootstrapping analysis (all slightly different variations but pretty much the same). I want to reorder each pixel so that the first layer is the smallest of each respective pixel, second layer is second smallest, etc.
It can be converted to a data.frame with 102 columns (x, y, result1, ...), but I don't know how to order each row of a data.frame by size and exclude columns at the same time.
You can use sort to order the values of each grid cell. Illustrated below
Example data
library(terra)
r <- rast(ncol=5, nrow=5)
values(r) <- 30
x <- rast(c(a=r, b=r/10, c=r/100))
x
#class : SpatRaster
#dimensions : 5, 5, 3 (nrow, ncol, nlyr)
#resolution : 72, 36 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#sources : memory
# memory
# memory
#names : a, b, c
#min values : 30, 3, 0.3
#max values : 30, 3, 0.3
Solution
y <- sort(x)
y
#class : SpatRaster
#dimensions : 5, 5, 3 (nrow, ncol, nlyr)
#resolution : 72, 36 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#source : memory
#names : a, b, c
#min values : 0.3, 3, 30
#max values : 0.3, 3, 30

match extent of two rasters in R

I have two raster:
raster1
class : SpatRaster
dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
raster2
class : SpatRaster
dimensions : 720, 1440, 1 (nrow, ncol, nlyr)
resolution : 0.25, 0.25 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84
I want to run zonal stastics to calculate sum of smaller raster raster1 on bigger raster raster2:
terra::zonal(raster1, raster2, fun = sum, as.raster=T, filename = 'zonal.tif')
Error: [zonal] dimensions and/or extent do not match
I wasn't sure why the extent are not matching until I did this
terra::ext(raster1)
SpatExtent : -180.000001017276, 180.000001017276, -90.0000010172997, 90.0000010172997 (xmin, xmax, ymin, ymax)
terra::ext(raster2)
SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
which shows that raster1 extent have some imprecision. What are different ways I can fix this?
EDIT: I tried the suggestion in the comment
terra::crs(raster2) <- sf::st_crs(4326)$wkt
terra::crs(raster1) <- sf::st_crs(4326)$wkt
terra::ext(raster2)
SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
terra::ext(raster1)
SpatExtent : -180.000001017276, 180.000001017276, -90.0000010172997, 90.0000010172997 (xmin, xmax, ymin, ymax)
But my extent are still not matching
The error message is
Error: [zonal] dimensions and/or extent do not match
In this case, that clearly refers to the difference is dimensions, which are
#dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
#dimensions : 720, 1440, 1 (nrow, ncol, nlyr)
I do not think the small difference in the extent is relevant at all.
To make the dimensions match you can use disagg or aggregate with a factor of 30.
If the crs of raster2 is different from that of raster1 you can (in this case, where you clearly have two global lon/lat rasters) fix that with
crs(raster2) <- crs(raster1)
And for good measure, you could in this case also do
ext(raster2) <- ext(raster1)
Mismatching extents don't stop zonal working, so I think that error message is wrong. Here's two rasters that only differ in their CRS:
> library(terra)
terra 1.5.21
> raster1 = rast()
> raster1[]=1:360
> raster2 = rast()
> raster2[]=1:360
> crs(raster1) = ""
> zonal(raster1, raster2)
Error: [zonal] dimensions and/or extent do not match
I guess it could be argued that a different CRS means a different extent in the same way that "23" is different to "23 km". But the extent and the dimensions are all the same according to these tests:
> ext(raster1) == ext(raster2)
[1] TRUE
> dim(raster1) == dim(raster2)
[1] TRUE TRUE TRUE
Rasters with a different extent work fine with zonal (once I've set the CRSs to match):
> ext(raster2) = c(-180.01, 180.01, -90.01, 90.01)
> crs(raster2) = ""
> z = zonal(raster1, raster2)
>
If you do want to change an extent, you can use ext(r) = ... as above, but you should try and figure out why extents don't match. Likely its because you have data on points and you may have cells extending out from points...

convert raster from coarse to finer resolution

This is my raster properties:
class : RasterLayer
dimensions : 3001, 3000, 9003000 (nrow, ncol, ncell)
resolution : 0.12, 0.034 (x, y)
extent : -180, 180, -40.034, 62 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : test.tif
names : test
I want to convert this into a raster with a resolution of 0.008333333 in both x and y direction
library(raster)
tar_res <- 0.008333333
disagg_raster <- disaggregate(my_raster,
fact = c(res(my_raster)[1]/tar_res, res(my_raster)[2]/tar_res))
disagg_raster
class : RasterLayer
dimensions : 12004, 42000, 504168000 (nrow, ncol, ncell)
resolution : 0.008571429, 0.0085 (x, y)
extent : -180, 180, -40.034, 62 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
How do I get the resolution to be 0.008333333 in both x and y direction?
If you cannot get there by (dis) aggregating you can use resample instead.
# example data
library(terra)
r <- rast(nrow=3001, ncol=3000, ymin=-40.034, ymax=62)
# create empty template with the desired geometry
tmp <- rast(r)
res(tmp) <- 1/120
ymax(tmp) <- ymax(r)
# resample
x <- resample(r, tmp)
See here for a more general and longer answer.

Terra Spatial Correlation between two raster

I am trying to calculate the spatial correlation between two rasters. I have two large rasters with the same extent, resolution, etc
class : RasterLayer
dimensions : 45598, 53241, 2427683118 (nrow, ncol, ncell)
resolution : 30, 30 (x, y)
extent : 273366.8, 1870597, 367780.7, 1735721 (xmin, xmax, ymin, ymax)```
These layers have massive NAs cells
I tried to use terra::focalCor with the stack of those layers.
corr=focalCor(layerstack, w=9, cor)
But I have this issue
Error in v[[j - 1]] <- t(sapply(1:nrow(Y), function(i, ...) fun(X[i, ], :
more elements supplied than there are to replace
Any ideas or suggestions?
Cheers
It would have been easier to provide a specific answer with actual data provided to be able to reproduce your issue, but in this case it seems like you imported your gridded data using raster::raster() creating a RasterLayer object, but according to ?focalCor, x has clearly to be a SpatRaster with at least two layers.
So, try terra::rast(c("grid_1.tif", "grid_2.tif")) |> terra::focalCor(w = 9, cor) instead.
Edit:
Thanks for your reprex. I dared to reduce dimensions and modify the extent a little bit in order to reduce processing time:
library(terra)
r <- rast(ncols = 100, nrows = 100,
xmin = 0, xmax = 25, ymin = 0, ymax = 25,
crs = "epsg:4326")
r1 <- init(r, fun = runif)
r2 <- init(r, fun = runif)
r_stack <- c(r1, r2)
r_stack_cor_5 <- focalCor(r_stack, w = 5, cor)
r_stack_cor_5
#> class : SpatRaster
#> dimensions : 100, 100, 1 (nrow, ncol, nlyr)
#> resolution : 0.25, 0.25 (x, y)
#> extent : 0, 25, 0, 25 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
#> source : memory
#> name : lyr1
#> min value : -0.6476946
#> max value : 0.6948594
r_stack_cor_25 <- focalCor(r_stack, w = 25, cor)
r_stack_cor_25
#> class : SpatRaster
#> dimensions : 100, 100, 1 (nrow, ncol, nlyr)
#> resolution : 0.25, 0.25 (x, y)
#> extent : 0, 25, 0, 25 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
#> source : memory
#> name : lyr1
#> min value : -0.1020998
#> max value : 0.1045798
I used fun = cor instead of function(x, y) cor(x, y) but the result is the same according to all.equal(). However, your example seems to work - and I'm failing to recognize the issue at the moment.

Extract NetCDF variable that have more than 4 dimension using brick function in raster package

I want to extract a variable called NVEL from the netCDF file which has five dimensions (i, j, tile, k, time)
where i is longitude, j is latitude, k is the level of depths
I want to extract NVEL(i, j, tile=3, k=1st level, time)
the input file can be downloaded from here https://drive.google.com/file/d/12NQp_uLr_IZLLU6Fzr555gKGGJlrRE4H/view?usp=sharing
NVEL<- brick("NVEL_1992_01.nc", varname= "NVEL", lvar=1, nl=1)
NVEL <- NVEL[[which(getZ(NVEL) == 3)]]
This does not work.
How to deal with a variable of 5 dimensions?
I see that this returns 50 (k) * 13 (tiles) * 1 (time) = 650 layers
library(terra)
f <- "NVEL_1992_01.nc"
x <- rast(f)
x
#class : SpatRaster
#dimensions : 90, 90, 650 (nrow, ncol, nlyr)
#resolution : 1, 1 (x, y)
#extent : -0.5, 89.5, -0.5, 89.5 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +datum=WGS84 +no_defs
#data source : NVEL_1992_01.nc
#names : NVE_1, NVE_2, NVE_3, NVE_4, NVE_5, NVE_6, ...
The order is k-wise (and tile-wise within tiles). See (the rather lengthy) output from
terra::describe(f)
You can extract that information like this:
d <- describe(f, print=FALSE)
d <- unlist(strsplit(d, "\n"))
i <- grep("NETCDF_DIM_k=", d)
j <- grep("NETCDF_DIM_tile=", d)
k <- sapply(strsplit(d[i], "="), function(x) x[2])
tile <- sapply(strsplit(d[j], "="), function(x) x[2])
kt <- paste0("k", k, "_tile", tile)
names(x) <- kt
x
#class : SpatRaster
#dimensions : 90, 90, 650 (nrow, ncol, nlyr)
#resolution : 1, 1 (x, y)
#extent : -0.5, 89.5, -0.5, 89.5 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +datum=WGS84 +no_defs
#data source : NVEL_1992_01.nc
#names : k0_tile0, k0_tile1, k0_tile2, k0_tile3, k0_tile4, k0_tile5, ...
This should happen automatigically in a future version. You can continue with terra (very similar to raster) or take the data back to a RasterBrick by doing
b <- brick(x*1)
(multiplying to get the values out of the file)

Resources