I'm using this function to calculate the length of linestring per cell by ID and store in a list, convert each element of the list into a RasterLayer and turn that list into a RasterBrick. Notice that inside the function I use "left_join()" so that all rasters have the same number of cells. However, the final raster converts to RasterStack instead of RasterBrick, why does this happen?
library(tidyverse)
library(sf)
library(raster)
library(purrr)
id <- c("844", "844", "844", "844", "844","844", "844", "844", "844", "844",
"844", "844", "845", "845", "845", "845", "845","845", "845", "845",
"845","845", "845", "845")
lat <- c(-30.6456, -29.5648, -27.6667, -31.5587, -30.6934, -29.3147, -23.0538,
-26.5877, -26.6923, -23.40865, -23.1143, -23.28331, -31.6456, -24.5648,
-27.6867, -31.4587, -30.6784, -28.3447, -23.0466, -27.5877, -26.8524,
-23.8855, -24.1143, -23.5874)
long <- c(-50.4879, -49.8715, -51.8716, -50.4456, -50.9842, -51.9787, -41.2343,
-40.2859, -40.19599, -41.64302, -41.58042, -41.55057, -50.4576, -48.8715,
-51.4566, -51.4456, -50.4477, -50.9937, -41.4789, -41.3859, -40.2536,
-41.6502, -40.5442, -41.4057)
df <- tibble(id, lat, long)
#converting to sf
df.sf <- df %>%
sf::st_as_sf(coords = c("long", "lat"), crs = 4326)
I also have a sf grid created from points:
#creating grid
xy <- sf::st_coordinates(df.sf)
grid = sf::st_make_grid(sf::st_bbox(df.sf),
cellsize = .1, square = FALSE) %>%
sf::st_as_sf() %>%
dplyr::mutate(cell = 1:nrow(.))
#creating raster
r <- raster::raster(grid, res=0.1)
#creating linestring to each id
df.line <- df.sf %>%
dplyr::group_by(id) %>%
dplyr::summarize() %>%
sf::st_cast("LINESTRING")
#build_length_raster <- function(df.line) {
intersect_list <- by(
df.line,
df.line$id,
function(id_df) sf::st_intersection(grid, id_df) %>%
dplyr::mutate(length = as.numeric(sf::st_length(.))) %>%
sf::st_drop_geometry()
)
list_length_grid <- purrr::map(intersect_list, function(grid_id) {
grid_id %>% dplyr::left_join(x=grid, by="cell") %>%
dplyr::mutate(length=length) %>%
dplyr::mutate_if(is.numeric,coalesce,0)
})
list_length_raster <- purrr::map(list_length_grid, function(grid_id) {
raster::rasterize(grid_id, r, field="length", na.rm=F, background=0)
})
list_length_raster2 <- unlist(list_length_raster, recursive=F)
raster_brick <- raster::writeRaster(raster::brick(list_length_raster2 ),
names(list_length_raster2 ),
bylayer=TRUE, overwrite=TRUE)
#}
You use the argument bylayer=TRUE
asking for a separate file for each layer. A RasterBrick can only be created from a single file; hence you get a RasterStack.
Also, because you have a list of RasterLayers, it is more efficient to use stack
here instead of brick
.
s <- stack(list_length_raster2 )
This is because a RasterStack essentially is a list or RasterLayers. With brick you would combine all the values into a new structure, and that can be expensive.
And if you want a RasterBrick, do:
b <- raster::writeRaster(s, "test.tif", overwrite=T)
b
#class : RasterBrick
#dimensions : 87, 120, 10440, 2 (nrow, ncol, ncell, nlayers)
#resolution : 0.1, 0.1 (x, y)
#extent : -52.0787, -40.0787, -31.71421, -23.01421 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
#source : test.tif
#names : test.1, test.2
#min values : 0, 0
#max values : 21762.09, 11923.31
Or use terra
instead of raster
--- That is easier because the terra
SpatRaster
encompasses raster
's RasterLayer, Stack and Brick objects.
Below I show how you may do this with terra
(although I am not quite following all the logic of your script; my understanding is that you want to measure, for each grid cell, the length of the lines that cross it). You need terra >= 1.5-29 that you can install with
install.packages('terra', repos='https://rspatial.r-universe.dev')
Your example data
id <- c("844", "844", "844", "844", "844","844", "844", "844", "844", "844",
"844", "844", "845", "845", "845", "845", "845","845", "845", "845", "845","845", "845", "845")
lat <- c(-30.6456, -29.5648, -27.6667, -31.5587, -30.6934, -29.3147, -23.0538,
-26.5877, -26.6923, -23.40865, -23.1143, -23.28331, -31.6456, -24.5648,
-27.6867, -31.4587, -30.6784, -28.3447, -23.0466, -27.5877, -26.8524,
-23.8855, -24.1143, -23.5874)
long <- c(-50.4879, -49.8715, -51.8716, -50.4456, -50.9842, -51.9787, -41.2343,
-40.2859, -40.19599, -41.64302, -41.58042, -41.55057, -50.4576, -48.8715,
-51.4566, -51.4456, -50.4477, -50.9937, -41.4789, -41.3859, -40.2536,
-41.6502, -40.5442, -41.4057)
Create a SpatVector and a SpatRaster
library(terra)
m <- cbind(object=as.integer(as.factor(id)), part=1, x=long, y=lat)
v <- vect(m, type="lines", att=data.frame(id=unique(id)), crs="+proj=longlat")
r <- rast(v, res=1) # lower resolution for example
Apply the rasterizeGeom
method to each line
x <- lapply(1:length(v),
\(i) rasterizeGeom(v[i], r, "km")
)
x <- rast(x)
names(x) <- v$id
x
#class : SpatRaster
#dimensions : 9, 12, 2 (nrow, ncol, nlyr)
#resolution : 1, 1 (x, y)
#extent : -51.9787, -39.9787, -31.6456, -22.6456 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +datum=WGS84 +no_defs
#sources : memory
# memory
#names : 844, 845
#min values : 0, 0
#max values : 276.6844, 313.1531