Skip to content

Commit

Permalink
Merge pull request #23 from emlab-ucsb/dev
Browse files Browse the repository at this point in the history
Fix Github actions failing due to missing dependencies
  • Loading branch information
jflowernet authored May 24, 2024
2 parents 2e9ae64 + 34c6518 commit 529aedf
Show file tree
Hide file tree
Showing 17 changed files with 165 additions and 152 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
PKG_SYSREQS: false

steps:
- uses: actions/checkout@v4
Expand All @@ -39,6 +40,10 @@ jobs:
http-user-agent: ${{ matrix.config.http-user-agent }}
use-public-rspm: true

- name: dependencies on Linux
if: runner.os == 'Linux'
run: sudo sh -c apt-get -y install libcurl4-gnutls-dev libssl-dev libgeos-dev make git libgdal-dev gdal-bin libproj-dev libsqlite3-dev libudunits2-dev pandoc librdf0-dev libicu-dev libxml2-dev libfreetype6-dev libjpeg-dev libpng-dev libtiff-dev libfontconfig1-dev libfribidi-dev libharfbuzz-dev

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
Expand Down
26 changes: 13 additions & 13 deletions R/get_boundary.R
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
#' Get polygon(s) for an area of interest
#' Get boundaries for an area of interest
#'
#' Marine and land areas can be obtained. For marine areas, the `mrp_get` function from the `mregions2` package is used to retrieve an area (e.g. an EEZ) from [Marine Regions](https://marineregions.org/gazetteer.php). For land areas, the package [`rnaturalearth`](https://github.com/ropensci/rnaturalearth/) is used.
#' Marine and land boundaries can be obtained. For marine boundaries, the `mrp_get` function from the `mregions2` package is used to retrieve the boundary (e.g. an EEZ) from [Marine Regions](https://marineregions.org/gazetteer.php). For land boundaries, the package [`rnaturalearth`](https://github.com/ropensci/rnaturalearth/) is used.
#'
#' @param name `character` name of the country or area. If `NULL` all areas are returned. If an incorrect `name` is input, a list of all possible names will be provided along with the error message.
#' @param type `character` the area type. Can be one of:
#' * `eez`: Exclusive Economic Zone (EEZ; 200nm), differ slightly from the the [UN Convention on the Law of the Sea (UNCLOS)](https://www.un.org/depts/los/convention_agreements/texts/unclos/part5.htm) definition because the archipelagic waters and the internal waters of a country are included
#' @param name `character` name of the country or region. If `NULL` all boundaries of `type` are returned. If an incorrect `name` is input, the user is given a list of valid names to chose from.
#' @param type `character` the boundary type. Can be one of:
#' * `eez`: Exclusive Economic Zone (EEZ; 200nm). These EEZs differ slightly from the the [UN Convention on the Law of the Sea (UNCLOS)](https://www.un.org/depts/los/convention_agreements/texts/unclos/part5.htm) definition because the archipelagic waters and the internal waters of a country are included.
#' * `12nm`: 12 nautical miles zone (Territorial Seas), defined in [UNCLOS](https://www.un.org/Depts/los/convention_agreements/texts/unclos/part2.htm)
#' * `24nm`: 14 nautical miles zone (Contiguous Zone), defined in [UNCLOS](https://www.un.org/Depts/los/convention_agreements/texts/unclos/part2.htm)
#' * `ocean`: Global Oceans and Seas as compiled by the Flanders Marine Data Centre. Names are: "Arctic Ocean", "Baltic Sea", "Indian Ocean", "Mediterranean Region", "North Atlantic Ocean", "North Pacific Ocean", "South Atlantic Ocean", "South China and Easter Archipelagic Seas", "South Pacific Ocean", and "Southern Ocean".
#' * `countries`: country boundaries
#'
#' More details on the marine areas can be found on the [Marine Regions website](https://marineregions.org/sources.php), and for land area, the [Natural Earth website](https://www.naturalearthdata.com/features/). Note that this function retrieves data from Natural Earth at the highest resolution (1:10m).
#' More details on the marine boundaries can be found on the [Marine Regions website](https://marineregions.org/sources.php), and for land boundaries, the [Natural Earth website](https://www.naturalearthdata.com/features/). Note that this function retrieves data from Natural Earth at the highest resolution (1:10m).
#'
#' @param country_type `character` must be either `country` or `sovereign`. Some countries have many territories that it has jurisdiction over. For example, Australia, France and the U.K. have jurisdiction over many overseas islands. Using `sovereign` returns the main country and all the territories, whereas using `country` returns just the main country. More details about what is a country via the `rnaturalearth` package [vignette](https://cran.r-project.org/web/packages/rnaturalearth/vignettes/what-is-a-country.html)
#'
#' @return 'sf' object of the area requested
#' @return 'sf' polygon or multipolygon object of the boundary requested
#' @export
#'
#' @examples
#' #Marine area examples:
#' #Marine boundary examples:
#' if(require("mregions2")){
#'australia_mainland_eez <- get_boundary(name = "Australia")
#'plot(australia_mainland_eez["geometry"])
Expand All @@ -28,7 +28,7 @@
#'plot(australia_including_territories_eez["geometry"])
#' }
#'
#'#Land area examples:
#'#Land boundary examples:
#'if(require("rnaturalearth")){
#'australia_land <- get_boundary(name = "Australia", type = "countries")
#'plot(australia_land["geometry"])
Expand All @@ -55,11 +55,11 @@ get_boundary <- function(name = "Australia", type = "eez", country_type = "count
if(!(country_type %in% country_types) & type != "ocean") stop(message = "'country_type' must be one of: ", paste(country_types, collapse = ", "))

if(type %in% mregions_types){
rlang::check_installed("mregions2", reason = "to use `get_boundary()` to access marine areas", action = \(pkg, ...) remotes::install_github("lifewatch/mregions2"))
rlang::check_installed("mregions2", reason = "to use `get_boundary()` to access marine boundaries", action = \(pkg, ...) remotes::install_github("lifewatch/mregions2"))
query_type <- mregions_types_lookup[which(mregions_types == type)]

if(is.null(name)) {
message("You have requested all ", type, " areas, the download will take several minutes.")
message("You have requested all ", type, " boundaries, the download will take several minutes.")
return(mregions2::mrp_get(query_type))
}
mregions_country_type <- ifelse(type == "ocean", "name", mregions_country_types_lookup[which(country_types == country_type)])
Expand All @@ -75,8 +75,8 @@ get_boundary <- function(name = "Australia", type = "eez", country_type = "count

eval(parse(text = paste0("mregions2::mrp_get(\"", query_type, "\", cql_filter = \"", mregions_country_type, " = '", name, "'\")")))
} else{
rlang::check_installed("rnaturalearth", reason = "to use `get_boundary()` to access land boundaries")
rlang::check_installed("rnaturalearthhires", reason = "to use `get_boundary()` to access marine areas", action = \(pkg, ...) remotes::install_github("ropensci/rnaturalearthhires"))
rlang::check_installed("rnaturalearth", reason = "to use `get_boundary()` to access land boundaries", action = \(pkg, ...) remotes::install_github("ropensci/rnaturalearth"))
rlang::check_installed("rnaturalearthhires", reason = "to use `get_boundary()` to access high resolution land boundaries", action = \(pkg, ...) remotes::install_github("ropensci/rnaturalearthhires"))

rnaturalearth_country_type <- rnaturalearth_country_types_lookup[which(country_types == country_type)]

Expand Down
38 changes: 19 additions & 19 deletions R/get_data_in_grid.R
Original file line number Diff line number Diff line change
@@ -1,51 +1,51 @@
#' Get gridded or cropped data from input data
#'
#' @param area_polygon `sf` polygon
#' @param spatial_grid `sf` or `terra::rast()` planning grid
#' @param boundary `sf` object with boundary of the area(s) you want gridded data for, e.g an EEZ or country. Boundaries can be obtained using `get_boundary()`
#' @param spatial_grid `sf` or `terra::rast()` grid created using `get_grid()`
#' @param dat `sf` or `terra::rast()` data to be gridded/ cropped
#' @param meth `character` method to use for for gridding/ resampling/ reprojecting raster data. If NULL (default), function checks if data values are binary (all 0, 1, NA, or NaN) in which case method is set to "mode" for sf output or "near" for raster output. If data is non-binary, method is set to "average" for sf output or "mean" for raster output. Note that different methods are used for sf and raster as `exactextractr::exact_extract()` is used for gridding to sf planning grid, whereas `terra::project()`/`terra::resample()` is used for transforming/ gridding raster data.
#' @param meth `character` method to use for for gridding/ resampling/ reprojecting raster data. If NULL (default), function checks if data values are binary (all 0, 1, NA, or NaN) in which case method is set to "mode" for sf output or "near" for raster output. If data is non-binary, method is set to "average" for sf output or "mean" for raster output. Note that different methods are used for sf and raster as `exactextractr::exact_extract()` is used for gridding to sf spatial grid, whereas `terra::project()`/`terra::resample()` is used for transforming/ gridding raster data.
#' @param name `character` to name the data output; unless `feature_names` is supplied, in which case that column is used as the feature names
#' @param feature_names `character` (`sf` data only) column with feature names that will be used for grouping of input data. If NULL, `sf` data is assumed to represent a single features, e.g. one habitat or species.
#' @param antimeridian `logical` can be set to true if the `area_polygon` or `spatial_grid` for which data will be extracted crosses the antimeridian and the data source is in lon-lat (EPSG:4326) format. If set to `NULL` (default) the function will try to check if the antimeridian is crossed and set this appropriately. Note that if you are using an `area_polygon` or `spatial_grid` that crosses the antimeridian and have data that is not in lon-lat
#' @param antimeridian `logical` can be set to true if the `boundary` or `spatial_grid` for which data will be extracted crosses the antimeridian and the data source is in lon-lat (EPSG:4326) format. If set to `NULL` (default) the function will try to check if the antimeridian is crossed and set this appropriately. Note that if you are using an `boundary` or `spatial_grid` that crosses the antimeridian and have data that is not in lon-lat
#' @param cutoff `numeric` (`sf` data only) cover fraction value between 0 and 1; if gridded output is required (i.e. a `spatial_grid` is provided), how much of each grid cell should be covered by an sf feature for it to be classified as that feature type
#'
#' @param apply_cutoff `logical` (`sf` data only) if gridded output is required (i.e. a `spatial_grid` is provided), `FALSE` will return an `sf` object with the % coverage of each feature in each grid cell, as opposed to a binary presence/ absence. `feature_names` should be provided.
#'
#' @return `sf` or `terra::rast()` object; cropped and intersected data in same format as `dat` if an `area_polygon` is provided, otherwise `sf` or `terra::rast()` gridded data depending on the format of the planning grid provided
#' @return `sf` or `terra::rast()` object; cropped and intersected data in same format as `dat` if an `boundary` is provided, otherwise `sf` or `terra::rast()` gridded data depending on the format of the spatial grid provided
#'
#' @export
#'
#' @examples
#' # ridges data for area of Pacific
#' ridges <- system.file("extdata", "ridges.rds", package = "spatialgridr") |> readRDS()
#' # use get_boundary() to get polygon of Samoa's Exclusive Economic Zone
#' # use get_boundary() to get Samoa's Exclusive Economic Zone
#' samoa_eez <- get_boundary(name = "Samoa")
#'
#' # You need a suitable projection for your area of interest, https://projectionwizard.org is useful for this purpose. For spatial planning, equal area projections are normally best.
#' # You need a suitable projection for your area of interest, https://projectionwizard.org is useful for this purpose. If you are doing spatial planning, equal area projections are normally best.
#' samoa_projection <- '+proj=laea +lon_0=-172.5 +lat_0=0 +datum=WGS84 +units=m +no_defs'
#'
#' # Create a planning grid with 5km sized planning units
#' planning_grid <- get_grid(area_polygon = samoa_eez, projection_crs = samoa_projection, resolution = 5000)
#' # Get ridges data, which is vector data in sf format, in the planning grid
#' ridges_gridded <- get_data_in_grid(spatial_grid = planning_grid, dat = ridges)
#' # Create a spatial grid with 5km square cells
#' samoa_grid <- get_grid(boundary = samoa_eez, projection_crs = samoa_projection, resolution = 5000)
#' # Get ridges data, which is vector data in sf format, in the spatial grid
#' ridges_gridded <- get_data_in_grid(spatial_grid = samoa_grid, dat = ridges)
#' terra::plot(ridges_gridded)
#'
#' #Get some raster data on cold water corals for the same planning grid
#' #Get some raster data on cold water corals for the same spatial grid
#' cold_coral <- system.file("extdata", "cold_coral.tif", package = "spatialgridr") |> terra::rast()
#' coral_gridded <- get_data_in_grid(spatial_grid = planning_grid, dat = cold_coral)
#' coral_gridded <- get_data_in_grid(spatial_grid = samoa_grid, dat = cold_coral)
#' terra::plot(coral_gridded)
get_data_in_grid <- function(area_polygon = NULL, spatial_grid = NULL, dat = NULL, meth = NULL, name = NULL, feature_names = NULL, antimeridian = NULL, cutoff = 0.5, apply_cutoff = TRUE){
get_data_in_grid <- function(boundary = NULL, spatial_grid = NULL, dat = NULL, meth = NULL, name = NULL, feature_names = NULL, antimeridian = NULL, cutoff = 0.5, apply_cutoff = TRUE){
if(is.null(dat)){
stop("Please provide some input data")
}
check_grid_or_polygon(spatial_grid, area_polygon)
check_grid_or_polygon(spatial_grid, boundary)

dat <- data_from_filepath(dat)

matching_crs <- check_matching_crs(area_polygon, spatial_grid, dat)
matching_crs <- check_matching_crs(boundary, spatial_grid, dat)

antimeridian <- if(is.null(antimeridian)){
sf_object <- if(is.null(spatial_grid)) area_polygon else{
sf_object <- if(is.null(spatial_grid)) boundary else{
if(check_sf(spatial_grid)) spatial_grid else terra::as.polygons(spatial_grid) %>% sf::st_as_sf()
}
check_antimeridian(sf_object, dat)
Expand All @@ -72,8 +72,8 @@ get_data_in_grid <- function(area_polygon = NULL, spatial_grid = NULL, dat = NUL
}
}

if(!is.null(area_polygon)){
get_raw_data(area_polygon, dat, meth, matching_crs, antimeridian)
if(!is.null(boundary)){
get_raw_data(boundary, dat, meth, matching_crs, antimeridian)

} else if(check_raster(dat)){
ras_to_grid(dat, spatial_grid, matching_crs, meth, name, antimeridian)
Expand Down
41 changes: 21 additions & 20 deletions R/get_grid.R
Original file line number Diff line number Diff line change
@@ -1,55 +1,56 @@
#' Create a planning grid raster for an area of interest
#' Create a spatial grid
#'
#' @description This function creates a planning grid for area of interest.
#' @description Creates a spatial grid, in `terra::rast()` of `sf` format, for areas within the boundaries provided
#'
#' @details
#' This function uses `sf::st_make_grid()` to create an `sf` planning grid. The default ordering of this grid type is from bottom to top, left to right. In contrast, the planning grid resulting from a `raster` object is ordered from top to bottom, left to right. To preserve consistency across the data types, we have reordered the `sf` planning grid to also fill from top to bottom, left to right.
#' This function uses `sf::st_make_grid()` to create `sf` grids. The default ordering of this grid type is from bottom to top, left to right. In contrast, the `terra::rast()` grid is ordered from top to bottom, left to right. To preserve consistency across the data types, we have reordered `sf` grids to also fill from top to bottom, left to right.
#'
#' @param area_polygon an sf polygon or multipolygon object of the area of interest (e.g., a country's EEZ)
#' @param projection_crs a suitable crs for the area of interest; for prioritization work, best practices is to use a local, equal area projection
#' @param boundary `sf` object with boundary of the area(s) you want a grid for, e.g an EEZ or country. Boundaries can be obtained using `get_boundary()`
#' @param projection_crs a suitable crs for the area of interest
#' @param option the desired output format, either "raster", "sf_square" (vector), or "sf_hex" (vector); default is "raster"
#' @param resolution numeric; the desired planning unit (grid cell) resolution in units (usually metres or degrees) of the projection_crs: `sf::st_crs(projection_crs, parameters = TRUE)$units_gdal`
#' @param sf_method string; should the planning unit be returned based on the `"centroid"` of the planning unit falling within the area_polygon, or any `"overlap"` of the planning unit with the area_polygon. `"overlap"` will be significantly slower.
#' @param resolution `numeric`; the desired grid cell resolution in units (usually metres or degrees) of the projection_crs: `sf::st_crs(projection_crs, parameters = TRUE)$units_gdal`
#' @param sf_method `string`. Only for `sf` grids:
#' * `"centroid"` a cell will be included in the grid if the centroid of the cell falls within the `boundary`, or if there is any `"overlap"` with the boundary. `"overlap"` will be significantly slower.
#'
#' @return A `terra::rast()` of `sf` planning grid of the same resolution and crs provided
#' @return A `terra::rast()` of `sf` grid with resolution and crs provided
#' @export
#'
#' @examples
#' # use get_boundary() to get a polygon of Samoa's Exclusive Economic Zone
#' samoa_eez <- get_boundary(name = "Samoa")
#' # You need a suitable projection for your area of interest, https://projectionwizard.org is useful for this purpose. For spatial planning, equal area projections are normally best.
#' samoa_projection <- '+proj=laea +lon_0=-172.5 +lat_0=0 +datum=WGS84 +units=m +no_defs'
#' # Create a planning grid with 5 km (5000 m) resolution covering the `samoa_eez` in a projection specified by `projection_crs`.
#' planning_grid <- get_grid(area_polygon = samoa_eez, projection_crs = samoa_projection, resolution = 5000)
#' # Create a grid with 5 km (5000 m) resolution covering the `samoa_eez` in a projection specified by `projection_crs`.
#' samoa_grid <- get_grid(boundary = samoa_eez, projection_crs = samoa_projection, resolution = 5000)

get_grid <- function(area_polygon, projection_crs, option = "raster", resolution = 5000, sf_method = "centroid"){
get_grid <- function(boundary, projection_crs, option = "raster", resolution = 5000, sf_method = "centroid"){

# Add repeated errors for area_polygon
if(!check_sf(area_polygon)) {
stop("area_polygon must be an sf object")}
# Add repeated errors for boundary
if(!check_sf(boundary)) {
stop("boundary must be an sf object")}

if(!(option %in% c("raster", "sf_square", "sf_hex"))) stop("option must be either 'raster', 'sf_square' or 'sf_hex'")

area_polygon <- area_polygon %>%
boundary <- boundary %>%
sf::st_geometry() %>%
sf::st_sf() %>%
{if(sf::st_crs(area_polygon) == projection_crs) . else sf::st_transform(., projection_crs)}
{if(sf::st_crs(boundary) == projection_crs) . else sf::st_transform(., projection_crs)}

if(option == "raster") {
area_polygon %>%
boundary %>%
terra::rast(resolution = resolution) %>%
terra::rasterize(area_polygon, ., touches=FALSE, field = 1)
terra::rasterize(boundary, ., touches=FALSE, field = 1)

} else{
grid_out <- if(option == "sf_square") sf::st_make_grid(area_polygon, cellsize = resolution, square = TRUE) %>% sf::st_sf() else sf::st_make_grid(area_polygon, cellsize = resolution, square = FALSE) %>% sf::st_sf()
grid_out <- if(option == "sf_square") sf::st_make_grid(boundary, cellsize = resolution, square = TRUE) %>% sf::st_sf() else sf::st_make_grid(boundary, cellsize = resolution, square = FALSE) %>% sf::st_sf()

if (sf_method == "centroid"){
grid_intersect <- sf::st_centroid(grid_out)
} else if (sf_method == "overlap"){
grid_intersect <- grid_out
}

overlap <- sf::st_intersects(grid_intersect, area_polygon) %>%
overlap <- sf::st_intersects(grid_intersect, boundary) %>%
lengths() > 0
grid_out[overlap,] %>%
dplyr::bind_cols(sf::st_coordinates(sf::st_centroid(.)) %>%
Expand Down
Loading

0 comments on commit 529aedf

Please sign in to comment.