Skip to content

Commit

Permalink
Merge pull request #20 from emlab-ucsb/dev
Browse files Browse the repository at this point in the history
Fix #17
  • Loading branch information
jflowernet authored Apr 23, 2024
2 parents 8991bac + a966f7e commit 0d7f98c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 19 deletions.
4 changes: 3 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
Package: spatialgridr
Title: Grid spatial data for conservation planning purposes
Version: 0.0.0.9000
Version: 0.0.0.9001
Authors@R: person(given = "Jason", family = "Flower", email = "[email protected]", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-6731-8182"))
Description: An R package that allows easy gridding of spatial data. Principally intended for spatial conservation planning uses.
License: GPL (>= 3) + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.1
Depends:
R (>= 3.5.0)
Imports:
dplyr,
exactextractr,
Expand Down
98 changes: 80 additions & 18 deletions R/sf_to_grid.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,52 +27,96 @@ sf_to_grid <- function(dat, spatial_grid, matching_crs, name, feature_names, ant
{if(antimeridian) sf::st_shift_longitude(.) else .}

dat_cropped <- dat %>%
{if(antimeridian & !unique(sf::st_geometry_type(.)) %in% c("POINT", "MULTIPOINT")) {
{if(all(antimeridian & !(c("POINT", "MULTIPOINT") %in% unique(sf::st_geometry_type(.))))) {
sf::st_break_antimeridian(., lon_0 = 180) %>% sf::st_shift_longitude()}
else if(antimeridian & unique(sf::st_geometry_type(.)) %in% c("POINT", "MULTIPOINT")){
else if(all(antimeridian & (c("POINT", "MULTIPOINT") %in% unique(sf::st_geometry_type(.))))){
sf::st_shift_longitude(.)} else .} %>%
sf::st_crop(grid_temp) %>%
sf::st_transform(sf::st_crs(spatial_grid))
}

if(nrow(dat_cropped) == 0) stop("No data in grid.")

if(is.null(feature_names)){
if(is.null(name)) name <- "data"

if(nrow(dat_cropped) == 0){
message("No ", name, " in grid")
if(is_raster){
return(spatial_grid %>%
terra::subst(1,0) %>%
setNames(name))
} else{
return(spatial_grid %>%
dplyr::mutate({{name}} := 0, .before = ncol(.)))
}
}

dat_grouped <- dat_cropped %>%
dplyr::mutate({{name}} := 1, .before = 1) %>%
dplyr::group_by({{name}}) %>%
dplyr::summarise() %>%
dplyr::ungroup() %>%
{if(sf::st_geometry_type(., by_geometry = FALSE) == "GEOMETRY") sf::st_cast(., to = "MULTIPOLYGON") else .}
{if(all(c("POLYGON", "MULTIPOLYGON") %in% (sf::st_geometry_type(.) %>% unique() %>% as.character()))) sf::st_cast(., to = "MULTIPOLYGON") else .}

} else {
if(nrow(dat_cropped) == 0){
message("No data in grid")

layer_names <- unique(dat[[feature_names]])

if(is_raster){
return(spatial_grid %>%
terra::subst(1,0) %>%
rep(length(layer_names)) %>%
setNames(layer_names))
} else{
new_cols <- data.frame(matrix(data = 0, ncol= length(layer_names), nrow=nrow(spatial_grid), dimnames=list(NULL, layer_names)))
return(spatial_grid %>%
dplyr::bind_cols(new_cols))
}
}

dat_grouped <- dat_cropped %>%
dplyr::group_by(.data[[feature_names]]) %>%
dplyr::summarise() %>%
dplyr::ungroup() %>%
{if(sf::st_geometry_type(., by_geometry = FALSE) == "GEOMETRY") sf::st_cast(., to = "MULTIPOLYGON") else .}
{if(all(c("POLYGON", "MULTIPOLYGON") %in% (sf::st_geometry_type(.) %>% unique() %>% as.character()))) sf::st_cast(., to = "MULTIPOLYGON") else .}
}

if(is_raster){

nms <- dat_grouped[[1]]

exactextractr::coverage_fraction(spatial_grid, dat_grouped) %>%
temp_rast <- exactextractr::coverage_fraction(spatial_grid, dat_grouped) %>%
terra::rast() %>%
setNames(nms) %>%
terra::mask(spatial_grid) %>%
{if(apply_cutoff) terra::classify(., matrix(c(-1, cutoff, NA, cutoff, 1.2, 1), ncol = 3, byrow = TRUE), include.lowest = FALSE, right = FALSE) else .} %>%
.[[lapply(., function(x) !all(terra::values(x) == 0)) %>% unlist()]] #removes all zero layers and by default also all NA layers
{if(apply_cutoff) terra::classify(., matrix(c(-1, cutoff, 0, cutoff, 1.2, 1), ncol = 3, byrow = TRUE), include.lowest = FALSE, right = FALSE) else .}

#check if some features were cropped out; if so, need to add raster layers with zeroes in
if(is.null(feature_names)) {
return(temp_rast)
} else if(all(unique(dat[[feature_names]]) %in% nms)){
return(temp_rast)
} else{
missing_feature_nms <- setdiff(unique(dat[[feature_names]]), nms)

missing_features_rast <- spatial_grid %>%
terra::subst(1,0) %>%
rep(length(missing_feature_nms)) %>%
setNames(missing_feature_nms)

return(c(temp_rast, missing_features_rast))
}
} else{

grid_has_extra_cols <- if(ncol(spatial_grid)>1) TRUE else FALSE

if(grid_has_extra_cols) extra_cols <- sf::st_drop_geometry(spatial_grid)

spatial_grid_with_id <- spatial_grid %>%
spatial_grid_geom <- spatial_grid %>%
sf::st_geometry() %>%
sf::st_sf() %>%
sf::st_sf()

spatial_grid_with_id <- spatial_grid_geom %>%
dplyr::mutate(cellID = 1:nrow(.))

spatial_grid_with_area <- spatial_grid_with_id %>%
Expand All @@ -86,12 +130,13 @@ sf_to_grid <- function(dat, spatial_grid, matching_crs, name, feature_names, ant
intersected_data_list <- list()

for (layer in layer_names) {
temp_intersection <- sf::st_intersection(spatial_grid_with_id, dat_list[[layer]])
temp_intersection <- sf::st_intersection(spatial_grid_with_id, dat_list[[layer]]) %>%
{if(all(sf::st_is_valid(.))) . else sf::st_make_valid(.)}

if(nrow(temp_intersection)>0) {
intersected_data_list[[layer]] <- temp_intersection %>%
dplyr::mutate(area = as.numeric(sf::st_area(.))) %>%
sf::st_drop_geometry(.) %>%
sf::st_drop_geometry() %>%
dplyr::full_join(spatial_grid_with_area, ., by = c("cellID")) %>%
dplyr::mutate(perc_area = .data$area / .data$area_cell, .keep = "unused", .before = 1) %>%
dplyr::mutate(perc_area = dplyr::case_when(is.na(.data$perc_area) ~ 0,
Expand All @@ -104,15 +149,32 @@ sf_to_grid <- function(dat, spatial_grid, matching_crs, name, feature_names, ant
) %>%
dplyr::select({{layer}})
}}
} else{
intersected_data_list[[layer]] <- spatial_grid_geom %>%
dplyr::mutate({{layer}} := 0, .before = 1)
}
}
intersected_data_df <- lapply(intersected_data_list, function(x) sf::st_drop_geometry(x)) %>%
do.call(cbind, .)

if(length(intersected_data_list) == 0) stop("No data in grid")
nms <- colnames(intersected_data_df)

lapply(intersected_data_list, function(x) sf::st_drop_geometry(x) %>% dplyr::select(dplyr::where(~any(. != 0)))) %>%
do.call(cbind, .) %>%
intersected_data_sf <- intersected_data_df %>%
{if(grid_has_extra_cols) cbind(extra_cols, .) else .} %>%
sf::st_set_geometry(sf::st_geometry(intersected_data_list[[1]])) %>%
sf::st_set_geometry("geometry")
}

if(is.null(feature_names)) {
return(intersected_data_sf)
} else if(all(unique(dat[[feature_names]]) %in% nms)){
return(intersected_data_sf)
} else{
missing_feature_nms <- setdiff(unique(dat[[feature_names]]), nms)

new_cols <- data.frame(matrix(data = 0, ncol= length(missing_feature_nms), nrow=nrow(spatial_grid), dimnames=list(NULL, missing_feature_nms)))
return(intersected_data_sf %>%
dplyr::bind_cols(new_cols))

}
}
}

0 comments on commit 0d7f98c

Please sign in to comment.