├── .gitignore ├── data ├── SolTin_ebird.rda ├── SolTin_gbif.rda ├── SolTin_parks.rda ├── SolTin_range.rda ├── SolTin_polygon.rda └── SolTin_covariates.rda ├── tests ├── testthat.R └── testthat │ ├── ebird.RData │ ├── gbif.RData │ ├── parks.RData │ ├── range.RData │ ├── region.RData │ ├── covariates.RData │ ├── parks_polygons.RData │ ├── test-SolTin_ebird.R │ ├── test-GetNearestCovariate.R │ ├── test-SolTin_gbif.R │ ├── test-SolTin_range.R │ ├── test-SolTin_polygon.R │ ├── test-SolTin_parks.R │ ├── test-AddDistToRangeToSpatialPoints.R │ ├── test-SolTin_covariates.R │ ├── test-MakePointsPolygonStack.R │ ├── test-MakeBinomStack.R │ ├── test-MakePointsStack.R │ ├── test-MakeIntegrationStack.R │ ├── test-AddDistToRangeToStack.R │ ├── test-MakeProjectionGrid.R │ └── test-FitModel.R ├── data-raw ├── SolTinamou.RData ├── SolTinBoundary.RData └── FormatSolTinData.R ├── .Rbuildignore ├── vignettes ├── SolitaryTinomou_files │ └── figure-html │ │ ├── MakeMesh-1.png │ │ ├── ReadSpeciesData-1.png │ │ └── MakeCovariateSpDataFrame-1.png └── SolitaryTinomou.Rmd ├── NEWS.md ├── NAMESPACE ├── PointedSDMs.Rproj ├── man ├── SolTin_range.Rd ├── SolTin_gbif.Rd ├── SolTin_ebird.Rd ├── SolTin_polygon.Rd ├── SolTin_parks.Rd ├── SolTin_covariates.Rd ├── AddDistToRangeToSpatialPoints.Rd ├── GetNearestCovariate.Rd ├── AddDistToRangeToStack.Rd ├── MakeProjectionGrid.Rd ├── MakeSpatialRegion.Rd ├── MakeIntegrationStack.Rd ├── MakePointsStack.Rd ├── MakePointsPolygonStack.Rd ├── MakeBinomStack.Rd └── FitModel.Rd ├── DESCRIPTION ├── README.md ├── README.Rmd ├── R ├── GetNearestCovariate.R ├── AddDistToRangeToStack.R ├── AddDistToRangeToSpatialPoints.R ├── MakeIntegrationStack.R ├── MakePointsStack.R ├── data.R ├── MakePointsPolygonStack.R ├── MakeProjectionGrid.R ├── MakeBinomStack.R ├── FitModel.R └── MakeSpatialRegion.R └── README.html /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | inst/doc 5 | -------------------------------------------------------------------------------- /data/SolTin_ebird.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data/SolTin_ebird.rda -------------------------------------------------------------------------------- /data/SolTin_gbif.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data/SolTin_gbif.rda -------------------------------------------------------------------------------- /data/SolTin_parks.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data/SolTin_parks.rda -------------------------------------------------------------------------------- /data/SolTin_range.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data/SolTin_range.rda -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(PointedSDMs) 3 | 4 | test_check("PointedSDMs") 5 | -------------------------------------------------------------------------------- /data/SolTin_polygon.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data/SolTin_polygon.rda -------------------------------------------------------------------------------- /data-raw/SolTinamou.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data-raw/SolTinamou.RData -------------------------------------------------------------------------------- /data/SolTin_covariates.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data/SolTin_covariates.rda -------------------------------------------------------------------------------- /tests/testthat/ebird.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/ebird.RData -------------------------------------------------------------------------------- /tests/testthat/gbif.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/gbif.RData -------------------------------------------------------------------------------- /tests/testthat/parks.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/parks.RData -------------------------------------------------------------------------------- /tests/testthat/range.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/range.RData -------------------------------------------------------------------------------- /tests/testthat/region.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/region.RData -------------------------------------------------------------------------------- /data-raw/SolTinBoundary.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/data-raw/SolTinBoundary.RData -------------------------------------------------------------------------------- /tests/testthat/covariates.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/covariates.RData -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^data-raw$ 4 | ^README\.Rmd$ 5 | ^README\.html$ 6 | ^README-.*\.png$ 7 | -------------------------------------------------------------------------------- /tests/testthat/parks_polygons.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/tests/testthat/parks_polygons.RData -------------------------------------------------------------------------------- /vignettes/SolitaryTinomou_files/figure-html/MakeMesh-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/vignettes/SolitaryTinomou_files/figure-html/MakeMesh-1.png -------------------------------------------------------------------------------- /vignettes/SolitaryTinomou_files/figure-html/ReadSpeciesData-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/vignettes/SolitaryTinomou_files/figure-html/ReadSpeciesData-1.png -------------------------------------------------------------------------------- /vignettes/SolitaryTinomou_files/figure-html/MakeCovariateSpDataFrame-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oharar/PointedSDMs/HEAD/vignettes/SolitaryTinomou_files/figure-html/MakeCovariateSpDataFrame-1.png -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # PointedSDMs 0.2 2 | 3 | * Added a `NEWS.md` file to track changes to the package. 4 | * Added a test suite 5 | * Updated FitModel() so that it can take a formula as an input 6 | * Updated the vignette 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(AddDistToRangeToSpatialPoints) 4 | export(AddDistToRangeToStack) 5 | export(FitModel) 6 | export(GetNearestCovariate) 7 | export(MakeBinomStack) 8 | export(MakeIntegrationStack) 9 | export(MakePointsPolygonStack) 10 | export(MakePointsStack) 11 | export(MakeProjectionGrid) 12 | export(MakeSpatialRegion) 13 | import(INLA) 14 | import(methods) 15 | import(sp) 16 | import(stats) 17 | -------------------------------------------------------------------------------- /PointedSDMs.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /tests/testthat/test-SolTin_ebird.R: -------------------------------------------------------------------------------- 1 | context("ebird") 2 | 3 | test_that("ebird data are OK", { 4 | # skip_on_cran() 5 | data("SolTin_ebird") 6 | 7 | # Choice of row 5 is arbitrary 8 | Row5 <- structure(list(X = -47.0212, Y = -24.3836), .Names = c("X", "Y"), row.names = 5L, class = "data.frame") 9 | expect_is(SolTin_ebird, "data.frame") 10 | # check summary 11 | expect_equal(dim(SolTin_ebird), c(315,2)) 12 | expect_equal(names(SolTin_ebird), c("X", "Y")) 13 | expect_equal(SolTin_ebird[5,], Row5) 14 | }) 15 | -------------------------------------------------------------------------------- /tests/testthat/test-GetNearestCovariate.R: -------------------------------------------------------------------------------- 1 | context("GetNearestCovariate") 2 | 3 | test_that("GetNearestCovariate works correctly", { 4 | # skip_on_cran() 5 | load("covariates.RData") 6 | data("SolTin_ebird") 7 | NearestCovs <- GetNearestCovariate(points=SolTin_ebird, covs=covariates) 8 | 9 | expect_is(NearestCovs, "SpatialPointsDataFrame") 10 | expect_equal(names(NearestCovs), c("Forest", "NPP", "Altitude")) 11 | 12 | expect_equal(as.numeric(NearestCovs@data[1,]), c(78.43434, 17889.67273, 554.0293), tolerance=1.0e-5) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/test-SolTin_gbif.R: -------------------------------------------------------------------------------- 1 | context("gbif") 2 | 3 | test_that("gbif data are OK", { 4 | # skip_on_cran() 5 | data("SolTin_gbif") 6 | 7 | # Choice of row 5 is arbitrary 8 | Row5 <- structure(list(X = -55.73333, Y = -26.11667), 9 | .Names = c("X", "Y"), row.names = 12L, class = "data.frame") 10 | expect_is(SolTin_gbif, "data.frame") 11 | # check summary 12 | expect_equal(dim(SolTin_gbif), c(63,2)) 13 | expect_equal(names(SolTin_gbif), c("X", "Y")) 14 | expect_equal(SolTin_gbif[5,], Row5) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-SolTin_range.R: -------------------------------------------------------------------------------- 1 | context("range") 2 | 3 | test_that("range data are OK", { 4 | # skip_on_cran() 5 | data("SolTin_range") 6 | 7 | # Choice of row 5 is arbitrary 8 | Row5 <- structure(list(X = -48.3625001482669, Y = -25.9567037505888), 9 | .Names = c("X", "Y"), row.names = 5L, class = "data.frame") 10 | expect_is(SolTin_range, "data.frame") 11 | # check summary 12 | expect_equal(dim(SolTin_range), c(66,2)) 13 | expect_equal(names(SolTin_range), c("X", "Y")) 14 | expect_equal(SolTin_range[5,], Row5) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-SolTin_polygon.R: -------------------------------------------------------------------------------- 1 | context("polygon") 2 | 3 | test_that("polygon data are OK", { 4 | # skip_on_cran() 5 | data("SolTin_polygon") 6 | 7 | # Choice of row 5 is arbitrary 8 | Row5 <- structure(list(X = -59.7624990079937, Y = -35.1067028718932), 9 | .Names = c("X", "Y"), row.names = 5L, class = "data.frame") 10 | expect_is(SolTin_polygon, "data.frame") 11 | # check summary 12 | expect_equal(dim(SolTin_polygon), c(115,2)) 13 | expect_equal(names(SolTin_polygon), c("X", "Y")) 14 | expect_equal(SolTin_polygon[5,], Row5) 15 | }) 16 | -------------------------------------------------------------------------------- /man/SolTin_range.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{SolTin_range} 5 | \alias{SolTin_range} 6 | \title{Points of polygon for solitary timanou range map} 7 | \format{A data frame with the coordinates of vertives of the polygon of the expert 8 | range map for the Solitary Tinomou. 9 | \describe{ 10 | \item{\code{X}}{Longitude} 11 | \item{\code{Y}}{Latitude} 12 | }} 13 | \usage{ 14 | SolTin_range 15 | } 16 | \description{ 17 | Points of polygon for solitary timanou range map 18 | } 19 | \keyword{datasets} 20 | -------------------------------------------------------------------------------- /man/SolTin_gbif.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{SolTin_gbif} 5 | \alias{SolTin_gbif} 6 | \title{Recorded Observations of the Solitary Tinomou, from GBIF} 7 | \format{A data frame with the coordinates of observations as two variables: 8 | \describe{ 9 | \item{\code{X}}{Longitude} 10 | \item{\code{Y}}{Latitude} 11 | }} 12 | \source{ 13 | \url{http://www.gbif.org/} 14 | } 15 | \usage{ 16 | SolTin_gbif 17 | } 18 | \description{ 19 | Recorded Observations of the Solitary Tinomou, from GBIF 20 | } 21 | \keyword{datasets} 22 | -------------------------------------------------------------------------------- /man/SolTin_ebird.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{SolTin_ebird} 5 | \alias{SolTin_ebird} 6 | \title{Recorded Observations of the Solitary Tinomou, from eBird} 7 | \format{A data frame with the coordinates of observations as two variables: 8 | \describe{ 9 | \item{\code{X}}{Longitude} 10 | \item{\code{Y}}{Latitude} 11 | }} 12 | \source{ 13 | \url{http://ebird.org/} 14 | } 15 | \usage{ 16 | SolTin_ebird 17 | } 18 | \description{ 19 | Recorded Observations of the Solitary Tinomou, from eBird 20 | } 21 | \keyword{datasets} 22 | -------------------------------------------------------------------------------- /tests/testthat/test-SolTin_parks.R: -------------------------------------------------------------------------------- 1 | context("parks") 2 | 3 | test_that("parks data are OK", { 4 | # skip_on_cran() 5 | data("SolTin_parks") 6 | 7 | # Choice of row 5 is arbitrary 8 | Row5 <- structure(list(X = -40.625, Y = -19.813369, area = 0.0453750068466116, Present = FALSE), 9 | .Names = c("X", "Y", "area", "Present"), row.names = 5L, class = "data.frame") 10 | expect_is(SolTin_parks, "data.frame") 11 | # check summary 12 | expect_equal(dim(SolTin_parks), c(26,4)) 13 | expect_equal(names(SolTin_parks), c("X", "Y", "area", "Present")) 14 | expect_equal(SolTin_parks[5,], Row5) 15 | }) 16 | -------------------------------------------------------------------------------- /man/SolTin_polygon.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{SolTin_polygon} 5 | \alias{SolTin_polygon} 6 | \title{Points of polygon for region of study for solitary timanou} 7 | \format{A data frame with the coordinates of vertives of the polygon of the region 8 | where the covariates are recorded for the Solitary Tinomou. 9 | \describe{ 10 | \item{\code{X}}{Longitude} 11 | \item{\code{Y}}{Latitude} 12 | }} 13 | \usage{ 14 | SolTin_polygon 15 | } 16 | \description{ 17 | Points of polygon for region of study for solitary timanou 18 | } 19 | \keyword{datasets} 20 | -------------------------------------------------------------------------------- /tests/testthat/test-AddDistToRangeToSpatialPoints.R: -------------------------------------------------------------------------------- 1 | context("AddDistToRangeToSpatialPoints") 2 | 3 | test_that("AddDistToRangeToSpatialPoints works correctly", { 4 | # skip_on_cran() 5 | data("SolTin_covariates") 6 | data("SolTin_ebird") 7 | load("range.RData") 8 | load("covariates.RData") 9 | NearestCovs <- GetNearestCovariate(points=SolTin_ebird, covs=covariates) 10 | RangeAdded <- AddDistToRangeToSpatialPoints(data = NearestCovs, polynoms = range, scale=FALSE) 11 | 12 | expect_is(RangeAdded, "SpatialPointsDataFrame") 13 | expect_equal(ncol(RangeAdded@data)-ncol(NearestCovs@data), 1) 14 | expect_equal(sum(RangeAdded@data$DistToPoly1==0), 303) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-SolTin_covariates.R: -------------------------------------------------------------------------------- 1 | context("covariates") 2 | 3 | test_that("covariates data are OK", { 4 | # skip_on_cran() 5 | data("SolTin_covariates") 6 | 7 | # Choice of row 5 is arbitrary 8 | Row5 <- structure(list(X = -56.375, Y = -26.618063, Forest = 52.49803922, NPP = 8476.479412, Altitude = 91.02156863), 9 | .Names = c("X", "Y", "Forest", "NPP", "Altitude"), row.names = 5L, class = "data.frame") 10 | expect_is(SolTin_covariates, "data.frame") 11 | # check summary 12 | expect_equal(dim(SolTin_covariates), c(7152,5)) 13 | expect_equal(names(SolTin_covariates), c("X", "Y", "Forest", "NPP", "Altitude")) 14 | expect_equal(SolTin_covariates[5,], Row5) 15 | }) 16 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: PointedSDMs 2 | Type: Package 3 | Title: Fit Models derived from Point Processes to Species Distributions using 4 | INLA 5 | Version: 0.2.1.9004 6 | Date: 2017-04-19 7 | Author: Bob O'Hara 8 | Maintainer: Bob O'Hara 9 | Description: A package to fit models based on point processes to a variety of data types. 10 | Depends: R (>= 2.10), 11 | INLA, 12 | sp, 13 | Imports: deldir, geosphere, Matrix, raster, rgeos, splancs, methods 14 | License: GPL-3 15 | LazyData: TRUE 16 | RoxygenNote: 6.0.1 17 | Suggests: knitr, 18 | rmarkdown, 19 | spatstat, 20 | mapview, 21 | RColorBrewer, 22 | parallel, 23 | testthat 24 | VignetteBuilder: knitr 25 | -------------------------------------------------------------------------------- /man/SolTin_parks.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{SolTin_parks} 5 | \alias{SolTin_parks} 6 | \title{Recorded Observations of the Solitary Tinomou, from parks} 7 | \format{A data frame with the coordinates of centroids of national parks plus 8 | the area and whether the Solitary Tinomou was recorded as present: 9 | \describe{ 10 | \item{\code{X}}{Longitude} 11 | \item{\code{Y}}{Latitude} 12 | \item{\code{area}}{Area of the park, } 13 | \item{\code{Present}}{Logical, whether the species is recorded as present in the park.} 14 | }} 15 | \source{ 16 | \url{http://www.gbif.org/} 17 | } 18 | \usage{ 19 | SolTin_parks 20 | } 21 | \description{ 22 | Recorded Observations of the Solitary Tinomou, from parks 23 | } 24 | \keyword{datasets} 25 | -------------------------------------------------------------------------------- /man/SolTin_covariates.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{SolTin_covariates} 5 | \alias{SolTin_covariates} 6 | \title{Covariate information for teh region around therange of the solitary tinomou} 7 | \format{A data frame with the coordinates of centroids of national parks plus 8 | the area and whether the Solitary Tinomou was recorded as present: 9 | \describe{ 10 | \item{\code{X}}{Longitude} 11 | \item{\code{Y}}{Latitude} 12 | \item{\code{Forest}}{Percentage of area covered by forest} 13 | \item{\code{NPP}}{Net Primary Productivity} 14 | \item{\code{Altitude}}{Altitude} 15 | }} 16 | \usage{ 17 | SolTin_covariates 18 | } 19 | \description{ 20 | Covariate information for teh region around therange of the solitary tinomou 21 | } 22 | \keyword{datasets} 23 | -------------------------------------------------------------------------------- /man/AddDistToRangeToSpatialPoints.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/AddDistToRangeToSpatialPoints.R 3 | \name{AddDistToRangeToSpatialPoints} 4 | \alias{AddDistToRangeToSpatialPoints} 5 | \title{Function to add distance to a polygon to a spatial points object} 6 | \usage{ 7 | AddDistToRangeToSpatialPoints(data, polynoms, scale = FALSE) 8 | } 9 | \arguments{ 10 | \item{data}{SpatialPoints* object} 11 | 12 | \item{polynoms}{A spatialpolygonsdataframe.} 13 | 14 | \item{scale}{Should the distance be scaled by dividing by the mean of the non-zero distances? (defaults to FALSE, either logical or numeric).} 15 | } 16 | \value{ 17 | A spatial points data frame with distances to the polygon added. 18 | } 19 | \description{ 20 | Function to add distance to a polygon to a spatial points object 21 | } 22 | -------------------------------------------------------------------------------- /tests/testthat/test-MakePointsPolygonStack.R: -------------------------------------------------------------------------------- 1 | context("MakePointsPolygonStack") 2 | 3 | test_that("MakePointsPolygonStack works correctly", { 4 | # skip_on_cran() 5 | data("SolTin_covariates") 6 | load("parks_polygons.RData") 7 | load("region.RData") 8 | # load("covariates.RData") 9 | 10 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 11 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, 12 | meshpars=Meshpars, proj = CRS("+proj=longlat +ellps=WGS84")) 13 | 14 | Parks <- MakePointsPolygonStack(polys=parks.polygons, data=SolTin_covariates, 15 | coords=c("X","Y"), mesh=Mesh$mesh) 16 | 17 | 18 | expect_is(Parks, "inla.data.stack") 19 | expect_equal(Parks$data$nrow, 26) 20 | expect_equal(Parks$data$data$Ntrials, rep(1, Parks$data$nrow)) 21 | }) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | PointedSDMs 4 | =========== 5 | 6 | This is an R package to fit SDMs in R using a point process formulation. It uses INLA to do the fitting, so a lot of the functions are written to re-format Spatial data so tha INLA can use it. 7 | 8 | This is now defunct: go to [Philip Mostert's repo](https://github.com/PhilipMostert/PointedSDMs) for the updated version. 9 | 10 | Installation 11 | ------------ 12 | 13 | At the moment this package is not public, so you will either have a zip file, which you can use with install.packages(), or you will have access to hte GitHub repository, so 14 | 15 | `R devtools::install_github("oharar/PointedSDMs")` 16 | 17 | should work. 18 | 19 | Usage 20 | ----- 21 | 22 | Check out the vignette: 23 | 24 | `R vignette("SolitaryTinomou")` 25 | -------------------------------------------------------------------------------- /man/GetNearestCovariate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/GetNearestCovariate.R 3 | \name{GetNearestCovariate} 4 | \alias{GetNearestCovariate} 5 | \title{Function to get covariate values nearest the data/integration point} 6 | \usage{ 7 | GetNearestCovariate(points, covs) 8 | } 9 | \arguments{ 10 | \item{points}{Points for which we need covariates. Either a SpatialPoints* object or a matrix with coordinates in columns.} 11 | 12 | \item{covs}{Covariates, with coordinates in first and second columns, or a SpatialPointsDataFrame object.} 13 | } 14 | \value{ 15 | A SpatialPointsDataFrame with the original points plus the data from the closest point. 16 | 17 | If there are ties, this will use the first element. 18 | } 19 | \description{ 20 | Function to get covariate values nearest the data/integration point 21 | } 22 | -------------------------------------------------------------------------------- /tests/testthat/test-MakeBinomStack.R: -------------------------------------------------------------------------------- 1 | context("MakeBinomStack") 2 | 3 | test_that("MakeBinomStack works correctly", { 4 | # skip_on_cran() 5 | load("parks.RData") 6 | load("covariates.RData") 7 | load("region.RData") 8 | load("range.RData") 9 | 10 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 11 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, 12 | meshpars=Meshpars, proj = CRS("+proj=longlat +ellps=WGS84")) 13 | stk.parks <- MakeBinomStack(observs=parks, data=covariates, mesh=Mesh$mesh, presname='Present', 14 | polynoms = range, tag='parks', InclCoords=TRUE) 15 | 16 | expect_is(stk.parks, "inla.data.stack") 17 | expect_equal(length(stk.parks), 3) 18 | expect_equal(names(stk.parks), c("A", "data", "effects")) 19 | expect_equal(stk.parks$data$nrow, length(parks)) 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/test-MakePointsStack.R: -------------------------------------------------------------------------------- 1 | context("MakePointsStack") 2 | 3 | test_that("MakePointsStack works correctly", { 4 | # skip_on_cran() 5 | load("ebird.RData") 6 | load("covariates.RData") 7 | load("region.RData") 8 | load("range.RData") 9 | 10 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 11 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, 12 | meshpars=Meshpars, proj = CRS("+proj=longlat +ellps=WGS84")) 13 | 14 | stk.eBird <- MakePointsStack(presences=ebird, data=covariates, mesh=Mesh$mesh, 15 | polynoms = range, tag='ebird', InclCoords=TRUE) 16 | 17 | 18 | expect_is(stk.eBird, "inla.data.stack") 19 | expect_equal(length(stk.eBird), 3) 20 | expect_equal(names(stk.eBird), c("A", "data", "effects")) 21 | expect_equal(stk.eBird$data$nrow, length(ebird)) 22 | }) 23 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, echo = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "README-" 12 | ) 13 | ``` 14 | # PointedSDMs 15 | 16 | This is an R package to fit SDMs in R using a point process formulation. It uses INLA to do the fitting, so a lot of the functions are written to re-format Spatial data so tha INLA can use it. 17 | 18 | ## Installation 19 | 20 | At the moment this package is not public, so you will either have a zip file, which you can use with install.packages(), or you will have access to hte GitHub repository, so 21 | 22 | ```R 23 | devtools::install_github("oharar/PointedSDMs") 24 | ``` 25 | 26 | should work. 27 | 28 | ## Usage 29 | 30 | Check out the vignette: 31 | 32 | ```R 33 | vignette("SolitaryTinomou") 34 | ``` 35 | -------------------------------------------------------------------------------- /man/AddDistToRangeToStack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/AddDistToRangeToStack.R 3 | \name{AddDistToRangeToStack} 4 | \alias{AddDistToRangeToStack} 5 | \title{Function to add distance to a list of polygons (e.g. range map) to a stack} 6 | \usage{ 7 | AddDistToRangeToStack(in.stk, coords, polynoms, scale = FALSE) 8 | } 9 | \arguments{ 10 | \item{in.stk}{INLA data stack.} 11 | 12 | \item{coords}{Names of geographic coordinates used in in.stk.} 13 | 14 | \item{polynoms}{List of polygons (a spatialpolygonsdataframe will work).} 15 | 16 | \item{scale}{Should the distance be scaled by dividing by the mean of the non-zero distances? (defaults to FALSE, eitehr logical or numeric).} 17 | } 18 | \value{ 19 | An INLA stack, with the distance to the polygon added 20 | } 21 | \description{ 22 | Function to add distance to a list of polygons (e.g. range map) to a stack 23 | } 24 | -------------------------------------------------------------------------------- /tests/testthat/test-MakeIntegrationStack.R: -------------------------------------------------------------------------------- 1 | context("MakeIntegrationStack") 2 | 3 | test_that("MakeIntegrationStack works correctly", { 4 | # skip_on_cran() 5 | load("region.RData") 6 | load("covariates.RData") 7 | 8 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 9 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, 10 | meshpars=Meshpars, proj = CRS("+proj=longlat +ellps=WGS84")) 11 | stk.ip <- MakeIntegrationStack(mesh=Mesh$mesh, data=covariates, area=Mesh$w, 12 | tag='ip', InclCoords=TRUE) 13 | 14 | expect_is(stk.ip, "inla.data.stack") 15 | expect_equal(names(stk.ip), c("A", "data", "effects")) 16 | expect_equal(stk.ip$A@Dim, c(595,1190)) 17 | 18 | expect_equal(stk.ip$data$nrow, 595) 19 | expect_equal(sum(is.na(stk.ip$data$data$resp.1)), 0) 20 | expect_equal(sum(is.na(stk.ip$data$data$resp.2)), 595) 21 | expect_equal(length(is.na(stk.ip$effects$ncol)), 7) 22 | }) 23 | -------------------------------------------------------------------------------- /man/MakeProjectionGrid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/MakeProjectionGrid.R 3 | \name{MakeProjectionGrid} 4 | \alias{MakeProjectionGrid} 5 | \title{Function to create stack for predictions} 6 | \usage{ 7 | MakeProjectionGrid(nxy, mesh, data, tag = "pred", coordnames = c("X", "Y"), 8 | boundary = NULL, intercept = TRUE) 9 | } 10 | \arguments{ 11 | \item{nxy}{Number of points in x and y directions.} 12 | 13 | \item{mesh}{INLA mesh.} 14 | 15 | \item{data}{Data frame with columns for coordinates, and others are covariates.} 16 | 17 | \item{tag}{Name for tag for the stack (defaults to "points").} 18 | 19 | \item{coordnames}{Names of coorinates (defaults to X and Y)} 20 | 21 | \item{boundary}{Boundary of region to project onto. Defaults to NULL, when the boundary of the mesh will be used. Either of class SpatialPolygons or two columns with the coorinates of the polygon} 22 | 23 | \item{intercept}{Logical: should an intercept be added? Defaults to TRUE} 24 | } 25 | \value{ 26 | An INLA stack onto which new data can be projected 27 | } 28 | \description{ 29 | Function to create stack for predictions 30 | } 31 | -------------------------------------------------------------------------------- /man/MakeSpatialRegion.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/MakeSpatialRegion.R 3 | \name{MakeSpatialRegion} 4 | \alias{MakeSpatialRegion} 5 | \title{Function to set up spatial structure for region} 6 | \usage{ 7 | MakeSpatialRegion(data = NULL, coords = c("X", "Y"), meshpars, 8 | bdry = NULL, proj = CRS("+proj=utm")) 9 | } 10 | \arguments{ 11 | \item{data}{Data (as data frame, with points having locations, or as a SpatialPointsDataFrame). Can be NULL, if bdry is not NULL.} 12 | 13 | \item{coords}{Names of columns for coordinates (X & Y) in data. Ignored if data is NULL.} 14 | 15 | \item{meshpars}{List of parameters to be sent to inla.mesh.2d().} 16 | 17 | \item{bdry}{Polygon of boundary for region, of class Polygon. If \code{NULL}, draws a boundary around the points.} 18 | 19 | \item{proj}{Projection to use if data is not a projection. Defaults to utm (hopefully).} 20 | } 21 | \value{ 22 | A list with 3 elements: 23 | . mesh: mesh (from inla.mesh.2d) 24 | . spde: spde object for Matern model (from inla.spde2.matern) 25 | . w: weights for each point in mesh 26 | } 27 | \description{ 28 | Function to set up spatial structure for region 29 | } 30 | -------------------------------------------------------------------------------- /tests/testthat/test-AddDistToRangeToStack.R: -------------------------------------------------------------------------------- 1 | context("AddDistToRangeToStack") 2 | 3 | test_that("AddDistToRangeToStack works correctly", { 4 | # skip_on_cran() 5 | load("region.RData") 6 | load("covariates.RData") 7 | load("range.RData") 8 | 9 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 10 | 11 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, meshpars=Meshpars, 12 | proj = CRS("+proj=longlat +ellps=WGS84")) 13 | stk.ip <- MakeIntegrationStack(mesh=Mesh$mesh, data=covariates, area=Mesh$w, 14 | tag='ip', InclCoords=TRUE) 15 | stk.ip.dists <- AddDistToRangeToStack(in.stk=stk.ip, coords=c("X", "Y"), 16 | polynoms = range, scale=FALSE) 17 | 18 | 19 | expect_equal(names(stk.ip.dists), c("A", "data", "effects")) 20 | expect_equal(stk.ip.dists$A@Dim, c(595,1190)) 21 | 22 | expect_equal(stk.ip.dists$data$nrow, 595) 23 | expect_equal(sum(is.na(stk.ip.dists$data$data$resp.1)), 0) 24 | expect_equal(sum(is.na(stk.ip.dists$data$data$resp.2)), 595) 25 | expect_equal(length(stk.ip.dists$effects$ncol), 8) 26 | expect_equal(stk.ip.dists$effects$names[[8]], "DistToPoly1") 27 | }) 28 | -------------------------------------------------------------------------------- /man/MakeIntegrationStack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/MakeIntegrationStack.R 3 | \name{MakeIntegrationStack} 4 | \alias{MakeIntegrationStack} 5 | \title{Function to create stack for integration points} 6 | \usage{ 7 | MakeIntegrationStack(mesh, data, area, tag = "mesh", coordnames = c("X", 8 | "Y"), InclCoords = FALSE) 9 | } 10 | \arguments{ 11 | \item{mesh}{INLA mesh (e.g., \code{$mesh} of object generated by \code{\link{MakeSpatialRegion}}).} 12 | 13 | \item{data}{\code{data.frame} with at least columns "X" and "Y" (or \code{coordnames}) giving locations, plus optional other covariate. Alternatively, a \code{SpatialPointsDataFrame} object.} 14 | 15 | \item{area}{Area around each integration point (e.g., the \code{$w} element of the object generated by \code{\link{MakeSpatialRegion}}).} 16 | 17 | \item{tag}{name for the stack.} 18 | 19 | \item{coordnames}{Names for coordinates in data (if \code{data} is not a \code{SpatialPointsDataFrame}).} 20 | 21 | \item{InclCoords}{should coordinates be included in data? (defaults to \code{FALSE}).} 22 | } 23 | \value{ 24 | An INLA stack for integration 25 | } 26 | \description{ 27 | Function to create stack for integration points 28 | } 29 | -------------------------------------------------------------------------------- /R/GetNearestCovariate.R: -------------------------------------------------------------------------------- 1 | #' Function to get covariate values nearest the data/integration point 2 | #' 3 | #' @param points Points for which we need covariates. Either a SpatialPoints* object or a matrix with coordinates in columns. 4 | #' @param covs Covariates, with coordinates in first and second columns, or a SpatialPointsDataFrame object. 5 | #' @return A SpatialPointsDataFrame with the original points plus the data from the closest point. 6 | #' 7 | #' If there are ties, this will use the first element. 8 | #' 9 | #' @export 10 | GetNearestCovariate <- function(points, covs) { 11 | if(class(covs)!="SpatialPointsDataFrame") { 12 | covs <- SpatialPointsDataFrame(coords = covs[,1:2], data = covs[,-(1:2)]) 13 | } 14 | if(class(points)!="SpatialPointsDataFrame") { 15 | points <- SpatialPoints(points) 16 | } 17 | 18 | Nearest <- apply(points@coords, 1, function(pt, pts) { 19 | dists <- spDistsN1(pts, pt, longlat = TRUE) 20 | which(dists==min(dists))[1] # need [1] in case min() is not unique. But if it's not, doesn't matter 21 | }, pts=covs) 22 | 23 | points.df <- SpatialPointsDataFrame(coords=points@coords, 24 | data = covs@data[Nearest, , drop=FALSE], 25 | proj4string = CRS(proj4string(covs))) 26 | return(points.df) 27 | } 28 | -------------------------------------------------------------------------------- /man/MakePointsStack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/MakePointsStack.R 3 | \name{MakePointsStack} 4 | \alias{MakePointsStack} 5 | \title{Function to create stack for presence only points} 6 | \usage{ 7 | MakePointsStack(data, presences, tag = "points", intercept = TRUE, mesh, 8 | coordnames = NULL, InclCoords = FALSE, polynoms = NULL, scale = FALSE) 9 | } 10 | \arguments{ 11 | \item{data}{\code{SpatialPointsDataFrame} of covariates.} 12 | 13 | \item{presences}{\code{SpatialPoints} object of presences.} 14 | 15 | \item{tag}{Name for this stack (defaults to "points").} 16 | 17 | \item{intercept}{should an intercept be added? Defaults to \code{TRUE}.} 18 | 19 | \item{mesh}{INLA mesh.} 20 | 21 | \item{coordnames}{Names of coordinates.} 22 | 23 | \item{InclCoords}{should coordinates be included in data? (defaults to \code{FALSE})} 24 | 25 | \item{polynoms}{If not \code{NULL}, a \code{SpatialPolygons} object, with (for example) range maps.} 26 | 27 | \item{scale}{Should the distance be scaled by dividing by the mean of the non-zero distances? Defaults to \code{FALSE}, either logical or numeric. Ignored if \code{polynoms} is \code{NULL}.} 28 | } 29 | \value{ 30 | An INLA stack with points 31 | } 32 | \description{ 33 | Function to create stack for presence only points 34 | } 35 | -------------------------------------------------------------------------------- /man/MakePointsPolygonStack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/MakePointsPolygonStack.R 3 | \name{MakePointsPolygonStack} 4 | \alias{MakePointsPolygonStack} 5 | \title{Function to create stack for small presence/absence polygons} 6 | \usage{ 7 | MakePointsPolygonStack(polys, data, coords = c("X", "Y"), mesh, 8 | polydatanames = NULL, respName = "Present", tol = 0.1, 9 | tag = "polygon", InclCoords = FALSE) 10 | } 11 | \arguments{ 12 | \item{polys}{Spatial polygon data frame.} 13 | 14 | \item{data}{Data frame with columns for coordinates, and others are covariates.} 15 | 16 | \item{coords}{Names for columns with coordinates in data.} 17 | 18 | \item{mesh}{INLA mesh.} 19 | 20 | \item{polydatanames}{Names of covariate data in polygon object. Defaults to NULL, which means no covariate data at polygon level.} 21 | 22 | \item{respName}{Name for response (e.g. presence/absence). Might be possible to use >1, but haven't tried.} 23 | 24 | \item{tol}{Tolerance for converting points to spatial pixels.} 25 | 26 | \item{tag}{Name for tag for the stack (defaults to "points").} 27 | 28 | \item{InclCoords}{Boolean, should coordinates be included in data (defaults to FALSE).} 29 | } 30 | \value{ 31 | An INLA stack, which will be treated as points in the analysis. 32 | } 33 | \description{ 34 | Function to create stack for small presence/absence polygons 35 | } 36 | -------------------------------------------------------------------------------- /tests/testthat/test-MakeProjectionGrid.R: -------------------------------------------------------------------------------- 1 | context("MakeProjectionGrid") 2 | 3 | test_that("MakeProjectionGrid works correctly", { 4 | # skip_on_cran() 5 | load("region.RData") 6 | load("covariates.RData") 7 | 8 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 9 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, 10 | meshpars=Meshpars, proj = CRS("+proj=longlat +ellps=WGS84")) 11 | Nxy.scale <- 1 # use this to change the resolution of the predictions 12 | Boundary <- Mesh$mesh$loc[Mesh$mesh$segm$int$idx[,2],] # get the boundary of the region 13 | Nxy <- round(c(diff(range(Boundary[,1])), diff(range(Boundary[,2])))/Nxy.scale) 14 | stk.pred <- MakeProjectionGrid(nxy=Nxy, mesh=Mesh$mesh, data=covariates, 15 | tag='pred', boundary=Boundary) 16 | 17 | expect_is(stk.pred, "list") 18 | expect_equal(length(stk.pred), 3) 19 | expect_equal(names(stk.pred), c("stk", "xy.in", "predcoords")) 20 | 21 | expect_is(stk.pred$stk, "inla.data.stack") 22 | expect_equal(names(stk.pred$stk), c("A", "data", "effects")) 23 | expect_equal(stk.pred$stk$A@Dim, c(446,964)) 24 | 25 | expect_is(stk.pred$xy.in, "logical") 26 | expect_equal(length(stk.pred$xy.in), 930) 27 | 28 | 29 | expect_is(stk.pred$predcoords, "matrix") 30 | expect_equal(dim(stk.pred$predcoords), c(446, 2)) 31 | expect_equal(colnames(stk.pred$predcoords), c("X", "Y")) 32 | }) 33 | -------------------------------------------------------------------------------- /R/AddDistToRangeToStack.R: -------------------------------------------------------------------------------- 1 | #' Function to add distance to a list of polygons (e.g. range map) to a stack 2 | #' 3 | #' @param in.stk INLA data stack. 4 | #' @param coords Names of geographic coordinates used in in.stk. 5 | #' @param polynoms List of polygons (a spatialpolygonsdataframe will work). 6 | #' @param scale Should the distance be scaled by dividing by the mean of the non-zero distances? (defaults to FALSE, eitehr logical or numeric). 7 | #' 8 | #' @return An INLA stack, with the distance to the polygon added 9 | #' 10 | #' @export 11 | #' @import sp 12 | AddDistToRangeToStack <- function(in.stk, coords, polynoms, scale=FALSE) { 13 | if(!is.logical(scale) & !is.numeric(scale)) stop("scale should be numeric or logial") 14 | if(is.numeric(scale) & !(scale>0)) stop("scale should be positive") 15 | if(!all(coords%in%names(in.stk$effects$ncol))) stop("Coordinates not in effects") 16 | 17 | # calculate distances 18 | UsePts <- apply(!is.na(in.stk$effects$data[,coords]), 1, all) 19 | Locations <- SpatialPoints(in.stk$effects$data[UsePts,coords], proj4string = CRS(proj4string(polynoms))) 20 | 21 | Dists <- AddDistToRangeToSpatialPoints(data = Locations, polynoms = polynoms, scale=scale) 22 | 23 | # Add distance to stack 24 | in.stk$effects$data[,names(Dists@data)] <- NA 25 | in.stk$effects$data[UsePts,names(Dists@data)] <- Dists@data 26 | in.stk$effects$ncol <- rep(1,ncol(in.stk$effects$data)) 27 | attr(in.stk$effects$ncol, "names") <- names(in.stk$effects$data) 28 | in.stk$effects$names[names(Dists@data)] <- names(Dists@data) 29 | 30 | in.stk 31 | } 32 | -------------------------------------------------------------------------------- /man/MakeBinomStack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/MakeBinomStack.R 3 | \name{MakeBinomStack} 4 | \alias{MakeBinomStack} 5 | \title{Function to create stack for presence only points} 6 | \usage{ 7 | MakeBinomStack(data, observs, tag = "points", intercept = TRUE, mesh, 8 | presname = "NPres", trialname = "Ntrials", coordnames = NULL, 9 | InclCoords = FALSE, polynoms = NULL, scale = FALSE) 10 | } 11 | \arguments{ 12 | \item{data}{SpatialPointsDataFrame of covariates.} 13 | 14 | \item{observs}{SpatialPoints object of presences and trials.} 15 | 16 | \item{tag}{Name for tag for the stack (defaults to "points").} 17 | 18 | \item{intercept}{Boolean, should an intercept be added? Defaults to TRUE.} 19 | 20 | \item{mesh}{INLA mesh.} 21 | 22 | \item{presname}{Names of presences column in observs. Defaults to "NPres". 23 | Note that this column can also be logical.} 24 | 25 | \item{trialname}{Names of column of number of columns in observs. 26 | Defaults to "Ntrials", ignored if presences column is logical.} 27 | 28 | \item{coordnames}{Names of coordinates.} 29 | 30 | \item{InclCoords}{Boolean, shoiuld coordinates be included in data (defaults to FALSE).} 31 | 32 | \item{polynoms}{If not NULL, a SpatialPolygons object, with (for example) range maps.} 33 | 34 | \item{scale}{Should the distance be scaled by dividing by the mean of the non-zero distances? 35 | Defaults to FALSE, either logical or numeric. Ignored if polynoms is NULL.} 36 | } 37 | \value{ 38 | An INLA stack with binomial data: include Ntrials, which is the number of trials 39 | } 40 | \description{ 41 | Function to create stack for presence only points 42 | } 43 | -------------------------------------------------------------------------------- /man/FitModel.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/FitModel.R 3 | \name{FitModel} 4 | \alias{FitModel} 5 | \title{Fit a model with INLA} 6 | \usage{ 7 | FitModel(..., formula = NULL, CovNames = NULL, mesh, spat.ind = "i", 8 | predictions = FALSE, tag.pred = "pred", control.fixed = NULL, 9 | waic = FALSE, dic = FALSE) 10 | } 11 | \arguments{ 12 | \item{...}{Data stacks.} 13 | 14 | \item{formula}{If not \code{NULL} (the default), the formula to be used in the model fitting. 15 | Does not have to contain the spatial term if \code{spat.ind} is specified.} 16 | 17 | \item{CovNames}{Names of covariates to use. If \code{NULL} will use all in stack effects.} 18 | 19 | \item{mesh}{INLA mesh.} 20 | 21 | \item{spat.ind}{Index for spatial mesh. Defaults to \code{i} (which is used elsewhere n this package). 22 | Set to \code{NULL} if no spatial term is wanted.} 23 | 24 | \item{predictions}{Boolean: should predictions (on the linear scale) be made? Defaults to \code{FALSE}.} 25 | 26 | \item{tag.pred}{Name of tag for predictions. Defaults to "pred".} 27 | 28 | \item{control.fixed}{List of arguments to be passed to INLA via control.fixed (e.g. parameters of priors of fixed effects). Default is \code{NULL}.} 29 | 30 | \item{waic}{Should wAIC be calculated? Defaults to \code{FALSE}.} 31 | 32 | \item{dic}{Should DIC be calculated? Defaults to \code{FALSE}.} 33 | } 34 | \value{ 35 | If predictions is \code{TRUE}, a list with 36 | - model: an object of class INLA, with the results of the analysis in them. 37 | . predictions: Posterior means and standard deviationsfor linear predictor for predictions. Note that 38 | If predictions is FALSE, just the model. 39 | } 40 | \description{ 41 | Fit a model with INLA 42 | } 43 | -------------------------------------------------------------------------------- /R/AddDistToRangeToSpatialPoints.R: -------------------------------------------------------------------------------- 1 | #' Function to add distance to a polygon to a spatial points object 2 | #' @param data SpatialPoints* object 3 | #' @param polynoms A spatialpolygonsdataframe. 4 | #' @param scale Should the distance be scaled by dividing by the mean of the non-zero distances? (defaults to FALSE, either logical or numeric). 5 | #' 6 | #' @return A spatial points data frame with distances to the polygon added. 7 | #' 8 | #' @export 9 | #' @import sp 10 | #' @import INLA 11 | AddDistToRangeToSpatialPoints <- function(data, polynoms, scale=FALSE) { 12 | if(!grepl("^SpatialPoints", class(data))) stop("data should be a SpatialPoints* object") 13 | if(!is.logical(scale) & !is.numeric(scale)) stop("scale should be numeric or logial") 14 | if(is.numeric(scale) & !(scale>0)) stop("scale should be positive") 15 | 16 | # calculate distances 17 | DistToPolys <- sapply(seq_along(polynoms), function(wh, Polys, dat) { 18 | NPl <- over(x=dat, y=Polys[wh,]) 19 | if(!is.vector(NPl)) NPl <- NPl[,1] # hopefully this works! 20 | NotInPoly <- is.na(NPl) # NA if points not in a polygon 21 | Dist <- as.numeric(NotInPoly) 22 | if(any(NotInPoly==1)) { 23 | Dist[NotInPoly] <- geosphere::dist2Line(p=dat[NotInPoly,], line=Polys[wh,])[,"distance"] 24 | } 25 | Dist 26 | }, Polys=polynoms, dat=data) 27 | 28 | # scale distances 29 | if(is.logical(scale)) DistToPolys <- sweep(DistToPolys, 2, apply(DistToPolys, 2, function(x) mean(x[x>0])), "/") 30 | if(is.numeric(scale)) DistToPolys <- DistToPolys/scale 31 | if(!is.null(names(polynoms@polygons))) { 32 | colnames(DistToPolys) <- names(polynoms@polygons) 33 | } else { 34 | colnames(DistToPolys) <- paste0("DistToPoly", seq_along(polynoms@polygons)) 35 | } 36 | # Add distance to stack 37 | if(class(data)!="SpatialPointsDataFrame") { 38 | data <- SpatialPointsDataFrame(data, data=as.data.frame(DistToPolys)) 39 | } else { 40 | data@data[,colnames(DistToPolys)] <- DistToPolys 41 | } 42 | data 43 | } 44 | -------------------------------------------------------------------------------- /R/MakeIntegrationStack.R: -------------------------------------------------------------------------------- 1 | #' Function to create stack for integration points 2 | #' 3 | #' @param mesh INLA mesh (e.g., \code{$mesh} of object generated by \code{\link{MakeSpatialRegion}}). 4 | #' @param data \code{data.frame} with at least columns "X" and "Y" (or \code{coordnames}) giving locations, plus optional other covariate. Alternatively, a \code{SpatialPointsDataFrame} object. 5 | #' @param area Area around each integration point (e.g., the \code{$w} element of the object generated by \code{\link{MakeSpatialRegion}}). 6 | #' @param tag name for the stack. 7 | #' @param coordnames Names for coordinates in data (if \code{data} is not a \code{SpatialPointsDataFrame}). 8 | #' @param InclCoords should coordinates be included in data? (defaults to \code{FALSE}). 9 | #' @return An INLA stack for integration 10 | #' 11 | #' @export 12 | #' @import INLA 13 | MakeIntegrationStack <- function(mesh, data, area, tag='mesh', 14 | coordnames=c("X","Y"), InclCoords=FALSE) { 15 | if(class(data)!="SpatialPointsDataFrame" & !all(coordnames%in%names(data))) stop("Coordinates not in the data") 16 | 17 | if(class(data)=="SpatialPointsDataFrame") { 18 | coordnames <- colnames(data@coords) 19 | Names <- colnames(data@data) 20 | } else { 21 | Names <- names(data)[!names(data)%in%coordnames] 22 | } 23 | if(InclCoords) Names <- c(coordnames, Names) 24 | 25 | Points <- cbind(c(mesh$loc[,1]), c(mesh$loc[,2])) 26 | colnames(Points) <- coordnames 27 | NearestCovs <- GetNearestCovariate(points=Points, covs=data) 28 | NearestCovs$Intercept <- rep(1,nrow(NearestCovs)) 29 | if(InclCoords) { 30 | NearestCovs@data[,colnames(NearestCovs@coords)] <- NearestCovs@coords 31 | } 32 | 33 | # Projector matrix for integration points. 34 | projmat.ip <- Matrix::Diagonal(mesh$n, rep(1, mesh$n)) # from mesh to integration points 35 | 36 | stk.ip <- inla.stack(data=list(resp=cbind(rep(0,mesh$n), NA), e=area), 37 | A=list(1,projmat.ip), tag=tag, 38 | effects=list(NearestCovs@data, list(i=1:mesh$n))) 39 | return(stk.ip) 40 | } 41 | -------------------------------------------------------------------------------- /R/MakePointsStack.R: -------------------------------------------------------------------------------- 1 | #' Function to create stack for presence only points 2 | #' 3 | #' @param data \code{SpatialPointsDataFrame} of covariates. 4 | #' @param presences \code{SpatialPoints} object of presences. 5 | #' @param tag Name for this stack (defaults to "points"). 6 | #' @param intercept should an intercept be added? Defaults to \code{TRUE}. 7 | #' @param mesh INLA mesh. 8 | #' @param coordnames Names of coordinates. 9 | #' @param InclCoords should coordinates be included in data? (defaults to \code{FALSE}) 10 | #' @param polynoms If not \code{NULL}, a \code{SpatialPolygons} object, with (for example) range maps. 11 | #' @param scale Should the distance be scaled by dividing by the mean of the non-zero distances? Defaults to \code{FALSE}, either logical or numeric. Ignored if \code{polynoms} is \code{NULL}. 12 | #' 13 | #' @return An INLA stack with points 14 | #' 15 | #' @export 16 | #' @import INLA 17 | MakePointsStack <- function(data, presences, tag="points", intercept=TRUE, mesh, 18 | coordnames=NULL, InclCoords=FALSE, polynoms = NULL, 19 | scale = FALSE) { 20 | if(is.null(coordnames)) coordnames <- colnames(data@coords) 21 | if(!is.null(polynoms)) { 22 | if(class(polynoms) != "SpatialPolygonsDataFrame" & class(polynoms) != "SpatialPolygons") 23 | stop("polynoms should be a spatial polygon") 24 | } 25 | 26 | NearestCovs <- GetNearestCovariate(points=presences, covs=data) 27 | if(InclCoords) { data@data[,coordnames] <- data@coords } 28 | if(intercept) NearestCovs@data[,paste("int",tag,sep=".")] <- 1 # add intercept 29 | if(!is.null(polynoms)) { 30 | NearestCovs <- AddDistToRangeToSpatialPoints(data = NearestCovs, polynoms = polynoms, scale=scale) 31 | } 32 | 33 | # Projector matrix from mesh to data. 34 | projmat <- inla.spde.make.A(mesh, as.matrix(NearestCovs@coords)) # from mesh to point observations 35 | 36 | stk.pp <- inla.stack(data=list(resp=cbind(rep(1,nrow(NearestCovs)), NA), 37 | e=rep(0, nrow(NearestCovs))), 38 | A=list(1,projmat), tag=tag, 39 | effects=list(NearestCovs@data, list(i=1:mesh$n))) 40 | 41 | return(stk.pp) 42 | } 43 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | #' Covariate information for teh region around therange of the solitary tinomou 2 | #' 3 | #' @format A data frame with the coordinates of centroids of national parks plus 4 | #' the area and whether the Solitary Tinomou was recorded as present: 5 | #' \describe{ 6 | #' \item{\code{X}}{Longitude} 7 | #' \item{\code{Y}}{Latitude} 8 | #' \item{\code{Forest}}{Percentage of area covered by forest} 9 | #' \item{\code{NPP}}{Net Primary Productivity} 10 | #' \item{\code{Altitude}}{Altitude} 11 | #' } 12 | #' 13 | "SolTin_covariates" 14 | 15 | #' Recorded Observations of the Solitary Tinomou, from eBird 16 | #' 17 | #' @format A data frame with the coordinates of observations as two variables: 18 | #' \describe{ 19 | #' \item{\code{X}}{Longitude} 20 | #' \item{\code{Y}}{Latitude} 21 | #' } 22 | #' 23 | #' @source \url{http://ebird.org/} 24 | "SolTin_ebird" 25 | 26 | #' Recorded Observations of the Solitary Tinomou, from GBIF 27 | #' 28 | #' @format A data frame with the coordinates of observations as two variables: 29 | #' \describe{ 30 | #' \item{\code{X}}{Longitude} 31 | #' \item{\code{Y}}{Latitude} 32 | #' } 33 | #' 34 | #' @source \url{http://www.gbif.org/} 35 | "SolTin_gbif" 36 | 37 | #' Recorded Observations of the Solitary Tinomou, from parks 38 | #' 39 | #' @format A data frame with the coordinates of centroids of national parks plus 40 | #' the area and whether the Solitary Tinomou was recorded as present: 41 | #' \describe{ 42 | #' \item{\code{X}}{Longitude} 43 | #' \item{\code{Y}}{Latitude} 44 | #' \item{\code{area}}{Area of the park, } 45 | #' \item{\code{Present}}{Logical, whether the species is recorded as present in the park.} 46 | #' } 47 | #' 48 | #' @source \url{http://www.gbif.org/} 49 | "SolTin_parks" 50 | 51 | #' Points of polygon for region of study for solitary timanou 52 | #' 53 | #' @format A data frame with the coordinates of vertives of the polygon of the region 54 | #' where the covariates are recorded for the Solitary Tinomou. 55 | #' \describe{ 56 | #' \item{\code{X}}{Longitude} 57 | #' \item{\code{Y}}{Latitude} 58 | #' } 59 | #' 60 | "SolTin_polygon" 61 | 62 | #' Points of polygon for solitary timanou range map 63 | #' 64 | #' @format A data frame with the coordinates of vertives of the polygon of the expert 65 | #' range map for the Solitary Tinomou. 66 | #' \describe{ 67 | #' \item{\code{X}}{Longitude} 68 | #' \item{\code{Y}}{Latitude} 69 | #' } 70 | #' 71 | "SolTin_range" 72 | 73 | -------------------------------------------------------------------------------- /R/MakePointsPolygonStack.R: -------------------------------------------------------------------------------- 1 | #' Function to create stack for small presence/absence polygons 2 | #' 3 | #' @param polys Spatial polygon data frame. 4 | #' @param data Data frame with columns for coordinates, and others are covariates. 5 | #' @param coords Names for columns with coordinates in data. 6 | #' @param mesh INLA mesh. 7 | #' @param polydatanames Names of covariate data in polygon object. Defaults to NULL, which means no covariate data at polygon level. 8 | #' @param respName Name for response (e.g. presence/absence). Might be possible to use >1, but haven't tried. 9 | #' @param tol Tolerance for converting points to spatial pixels. 10 | #' @param tag Name for tag for the stack (defaults to "points"). 11 | #' @param InclCoords Boolean, should coordinates be included in data (defaults to FALSE). 12 | #' 13 | #' @return An INLA stack, which will be treated as points in the analysis. 14 | #' 15 | #' @export 16 | #' @import sp 17 | #' @import INLA 18 | 19 | MakePointsPolygonStack <- function(polys, data, coords=c("X","Y"), mesh, polydatanames=NULL, 20 | respName="Present", tol=1e-1, tag="polygon", InclCoords=FALSE) { 21 | if(!all(coords%in%names(data))) stop("Coordinates not in the data") 22 | sp.points.df <- SpatialPointsDataFrame(data[,coords], data=data, proj4string = CRS("+proj=longlat +datum=WGS84")) 23 | sp.pixels <- SpatialPixels(sp.points.df, tolerance = tol) 24 | data.spdf <- SpatialPixelsDataFrame(sp.pixels, data, tolerance = tol) # this might also leave the Lon and Lat columns in your SpatialPixelsDataFrame which you can manually remove 25 | data.raster <- raster::brick(data.spdf) 26 | 27 | dat <- as.data.frame(raster::extract(data.raster, polys, small=TRUE, fun=mean)) 28 | dat[,respName] <- as.numeric(polys@data[,respName]) 29 | if(!is.null(polydatanames)) dat[,polydatanames] <- polys@data[,polydatanames] 30 | dat$X <- coordinates(polys)[,1] 31 | dat$Y <- coordinates(polys)[,2] 32 | 33 | Area <- sapply(polys@polygons, function(x) x@area) # area of each polygon 34 | if(InclCoords) { 35 | CovEffects <- dat 36 | } else { 37 | CovEffects <- dat[,!names(dat)%in%coords] 38 | } 39 | # CovEffects$Intercept=1 40 | 41 | projmat <- inla.spde.make.A(mesh, as.matrix(dat[,c("X","Y")])) # from mesh to presence/absence 42 | stk <- inla.stack(data=list(resp=cbind(NA, dat[,respName]), Ntrials=rep(1, nrow(dat)), e=Area), 43 | A=list(1,projmat), tag=tag, effects=list(CovEffects, list(i=1:mesh$n))) 44 | stk 45 | } 46 | -------------------------------------------------------------------------------- /R/MakeProjectionGrid.R: -------------------------------------------------------------------------------- 1 | #' Function to create stack for predictions 2 | #' @param nxy Number of points in x and y directions. 3 | #' @param mesh INLA mesh. 4 | #' @param data Data frame with columns for coordinates, and others are covariates. 5 | #' @param tag Name for tag for the stack (defaults to "points"). 6 | #' @param coordnames Names of coorinates (defaults to X and Y) 7 | #' @param boundary Boundary of region to project onto. Defaults to NULL, when the boundary of the mesh will be used. Either of class SpatialPolygons or two columns with the coorinates of the polygon 8 | #' @param intercept Logical: should an intercept be added? Defaults to TRUE 9 | #' 10 | #' @return An INLA stack onto which new data can be projected 11 | #' 12 | #' @export 13 | #' @import INLA 14 | 15 | MakeProjectionGrid <- function(nxy, mesh, data, tag='pred', coordnames = c("X", "Y"), boundary=NULL, intercept=TRUE) { 16 | if("resp"%in%coordnames) stop("resp cannot be a coordinate name") 17 | if("e"%in%coordnames) stop("e cannot be a coordinate name") 18 | if(is.null(boundary)) boundary <- mesh$loc[mesh$segm$int$idx[,2],] 19 | if(class(boundary)=="SpatialPolygons") { 20 | projgrid <- inla.mesh.projector(mesh, xlim=boundary@bbox["x",], ylim=boundary@bbox["y",], dims=nxy) 21 | # get the points on the grid within the boundary 22 | xy.in <- !is.na(over(SpatialPoints(projgrid$lattice$loc, proj4string=boundary@proj4string), boundary)) 23 | } else { 24 | if(ncol(boundary)<2) stop("Boundary should have at least 2 columns") 25 | projgrid <- inla.mesh.projector(mesh, xlim=range(boundary[,1]), ylim=range(boundary[,2]), dims=nxy) 26 | xy.in <- splancs::inout(projgrid$lattice$loc, boundary) 27 | } 28 | 29 | # get the points on the grid within the boundary 30 | # xy.in <- splancs::inout(projgrid$lattice$loc, boundary[,1:2]) 31 | predcoords <- projgrid$lattice$loc[which(xy.in),] 32 | colnames(predcoords) <- coordnames 33 | Apred <- projgrid$proj$A[which(xy.in), ] 34 | 35 | # Extract covariates for points, add intercept and coordinates 36 | NearestCovs=GetNearestCovariate(points=predcoords, covs=data) 37 | if(intercept) NearestCovs$Intercept=1 38 | NearestCovs@data[,colnames(NearestCovs@coords)] <- NearestCovs@coords 39 | 40 | # stack the predicted data 41 | stk <- inla.stack(list(resp=cbind(NA, rep(NA, nrow(NearestCovs))), e=rep(0, nrow(NearestCovs))), 42 | A=list(1,Apred), tag=tag, effects=list(NearestCovs@data, list(i=1:mesh$n))) 43 | pred=list(stk=stk, xy.in=xy.in, predcoords=predcoords) 44 | pred 45 | } 46 | 47 | -------------------------------------------------------------------------------- /tests/testthat/test-FitModel.R: -------------------------------------------------------------------------------- 1 | context("FitModel") 2 | 3 | test_that("FitModel works correctly", { 4 | # skip_on_cran() 5 | load("ebird.RData") 6 | load("parks.RData") 7 | load("covariates.RData") 8 | load("range.RData") 9 | load("region.RData") 10 | 11 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 12 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region, 13 | meshpars=Meshpars, proj = CRS("+proj=longlat +ellps=WGS84")) 14 | 15 | stk.ip <- MakeIntegrationStack(mesh=Mesh$mesh, data=covariates, area=Mesh$w, 16 | tag='ip', InclCoords=TRUE) 17 | stk.ip.dists <- AddDistToRangeToStack(in.stk=stk.ip, coords=c("X", "Y"), 18 | polynoms = range, scale=FALSE) 19 | stk.eBird <- MakePointsStack(presences=ebird, data=covariates, mesh=Mesh$mesh, 20 | polynoms = range, tag='ebird', InclCoords=TRUE) 21 | stk.parks <- MakeBinomStack(observs=parks, data=covariates, mesh=Mesh$mesh, presname='Present', 22 | polynoms = range, tag='parks', InclCoords=TRUE) 23 | 24 | 25 | SolTinModel <- FitModel(stk.eBird, stk.ip.dists, stk.parks, CovNames=NULL, mesh = Mesh$mesh, 26 | predictions = FALSE, waic=TRUE, dic=TRUE) 27 | Summ <- summary(SolTinModel)$fixed 28 | # test formula 29 | formula2 <- formula(SolTin.form <- resp ~ 0 + Forest + NPP + Altitude + int.ebird + DistToPoly1 + 30 | Intercept + X + Y + int.parks) 31 | SolTinModel2 <- FitModel(stk.eBird, stk.ip.dists, stk.parks, formula = formula2, spat.ind="i", 32 | CovNames=NULL, mesh = Mesh$mesh, predictions = FALSE) 33 | Summ2 <- summary(SolTinModel2)$fixed 34 | 35 | # Test priors 36 | SolTinModel3 <- FitModel(stk.eBird, stk.ip.dists, stk.parks, CovNames=NULL, mesh = Mesh$mesh, 37 | predictions = FALSE, waic=TRUE, dic=TRUE, control.fixed = list(mean=0, prec=100)) 38 | Summ3 <- summary(SolTinModel3)$fixed 39 | 40 | Diff <- abs(Summ[grep("int", rownames(Summ)),"mean"]) - abs(Summ3[grep("int", rownames(Summ3)),"mean"]) 41 | expect_is(SolTinModel, "inla") 42 | # check summary 43 | expect_equal(nrow(Summ), 9) 44 | expect_equal(as.vector(Summ[,"mean"]), c(-0.0017, 0, -1e-04, 1.3867, 0.319, -0.3539, 0.0043, 0.0064, -0.294), 45 | tolerance=1e-4) 46 | expect_equal(Summ, Summ2, tolerance=1e-4) 47 | # Test that wAIC and DIC are calculated 48 | expect_equal(SolTinModel$waic$waic, -599.96, tolerance=1e-2) 49 | expect_equal(SolTinModel$dic$dic, -602.78, tolerance=1e-2) 50 | 51 | # Test that priors work and give smaller intercepts 52 | expect_is(SolTinModel3, "inla") 53 | expect_lt(Summ3["int.ebird","mean"], Summ["int.ebird","mean"]) 54 | expect_gt(Summ3["int.parks","mean"], Summ["int.parks","mean"]) 55 | 56 | }) 57 | -------------------------------------------------------------------------------- /R/MakeBinomStack.R: -------------------------------------------------------------------------------- 1 | #' Function to create stack for presence only points 2 | #' 3 | #' @param data SpatialPointsDataFrame of covariates. 4 | #' @param observs SpatialPoints object of presences and trials. 5 | #' @param tag Name for tag for the stack (defaults to "points"). 6 | #' @param intercept Boolean, should an intercept be added? Defaults to TRUE. 7 | #' @param mesh INLA mesh. 8 | #' @param presname Names of presences column in observs. Defaults to "NPres". 9 | #' Note that this column can also be logical. 10 | #' @param trialname Names of column of number of columns in observs. 11 | #' Defaults to "Ntrials", ignored if presences column is logical. 12 | #' @param coordnames Names of coordinates. 13 | #' @param InclCoords Boolean, shoiuld coordinates be included in data (defaults to FALSE). 14 | #' @param polynoms If not NULL, a SpatialPolygons object, with (for example) range maps. 15 | #' @param scale Should the distance be scaled by dividing by the mean of the non-zero distances? 16 | #' Defaults to FALSE, either logical or numeric. Ignored if polynoms is NULL. 17 | #' 18 | #' @return An INLA stack with binomial data: include Ntrials, which is the number of trials 19 | #' 20 | #' @export 21 | #' @import INLA 22 | 23 | MakeBinomStack=function(data, observs, tag="points", intercept=TRUE, mesh, presname="NPres", trialname="Ntrials", 24 | coordnames=NULL, InclCoords=FALSE, polynoms = NULL, scale = FALSE) { 25 | 26 | if(length(presname)>1) stop("more than one name given for presences column") 27 | if(length(trialname)>1) stop("more than one name given for number of trials column") 28 | if(!presname%in%names(observs@data)) stop(paste(presname," not in names of presences data frame", sep="")) 29 | if(!is.logical(observs@data[,presname]) & !trialname%in%names(observs@data)) 30 | stop(paste(trialname," not in names of presences data frame", sep="")) 31 | 32 | if(is.null(coordnames)) coordnames <- colnames(data@coords) 33 | if(!is.null(polynoms)) { 34 | if(class(polynoms) != "SpatialPolygonsDataFrame" & class(polynoms) != "SpatialPolygons") 35 | stop("polynoms should be a spatial polygon") 36 | } 37 | 38 | NearestCovs <- GetNearestCovariate(points=observs, covs=data) 39 | if(InclCoords) { data@data[,coordnames] <- data@coords } 40 | if(intercept) NearestCovs@data[,paste("int",tag,sep=".")] <- 1 # add intercept 41 | if(!is.null(polynoms)) { 42 | NearestCovs <- AddDistToRangeToSpatialPoints(data = NearestCovs, polynoms = polynoms, scale=scale) 43 | } 44 | 45 | # If presences are Boolean, reformat 46 | if(is.logical(observs@data[,presname])) { 47 | observs@data[,presname] <- as.integer(observs@data[,presname]) 48 | observs@data[,trialname] <- rep(1, nrow(observs@data)) 49 | } 50 | # Projector matrix from mesh to data. 51 | projmat <- inla.spde.make.A(mesh, as.matrix(NearestCovs@coords)) # from mesh to point observations 52 | 53 | stk.binom <- inla.stack(data=list(resp=cbind(NA,observs@data[,presname] ), Ntrials=observs@data[,trialname]), A=list(1,projmat), tag=tag, 54 | effects=list(NearestCovs@data, list(i=1:mesh$n))) 55 | 56 | stk.binom 57 | } 58 | -------------------------------------------------------------------------------- /R/FitModel.R: -------------------------------------------------------------------------------- 1 | #' Fit a model with INLA 2 | #' 3 | #' @param ... Data stacks. 4 | #' @param formula If not \code{NULL} (the default), the formula to be used in the model fitting. 5 | #' Does not have to contain the spatial term if \code{spat.ind} is specified. 6 | #' @param CovNames Names of covariates to use. If \code{NULL} will use all in stack effects. 7 | #' @param mesh INLA mesh. 8 | #' @param spat.ind Index for spatial mesh. Defaults to \code{i} (which is used elsewhere n this package). 9 | #' Set to \code{NULL} if no spatial term is wanted. 10 | #' @param predictions Boolean: should predictions (on the linear scale) be made? Defaults to \code{FALSE}. 11 | #' @param tag.pred Name of tag for predictions. Defaults to "pred". 12 | #' @param control.fixed List of arguments to be passed to INLA via control.fixed (e.g. parameters of priors of fixed effects). Default is \code{NULL}. 13 | #' @param waic Should wAIC be calculated? Defaults to \code{FALSE}. 14 | #' @param dic Should DIC be calculated? Defaults to \code{FALSE}. 15 | #' @return If predictions is \code{TRUE}, a list with 16 | #' - model: an object of class INLA, with the results of the analysis in them. 17 | #' . predictions: Posterior means and standard deviationsfor linear predictor for predictions. Note that 18 | #' If predictions is FALSE, just the model. 19 | #' 20 | #' @export 21 | #' @import stats 22 | #' @import INLA 23 | FitModel <- function(..., formula=NULL, CovNames=NULL, mesh, spat.ind = "i", predictions=FALSE, tag.pred="pred", 24 | control.fixed=NULL, waic=FALSE, dic=FALSE) { 25 | 26 | stck <- inla.stack(...) 27 | 28 | if(is.null(CovNames)) { 29 | CovNames <- unlist(stck$effects$names) 30 | CovNames <- CovNames[!CovNames%in%c(spat.ind)] 31 | } else { 32 | if(!is.null(formula)) { 33 | warning("CovNames and formula are both not NULL: CovNames will be ignored") 34 | } 35 | } 36 | 37 | mesh <- inla.spde2.matern(mesh) 38 | 39 | if(!is.null(spat.ind)) { 40 | CovNames <- c(CovNames, paste0("f(", spat.ind, ", model=mesh)")) 41 | } 42 | # I'm sure there's a nicer way of doing this, but ... won't work 43 | if(is.null(control.fixed)) { 44 | control.fixed <- list(mean=0) 45 | } 46 | 47 | if(is.null(formula)) { 48 | Formula <- formula(paste(c("resp ~ 0 ", CovNames), collapse="+")) 49 | } else { 50 | if(is.null(spat.ind)) { 51 | Formula <- formula 52 | } else { 53 | if(any(grepl(paste0('(', spat.ind, ','), formula, fixed=TRUE))) { 54 | warning(paste0(spat.ind, " already in formula, so will be ignored")) 55 | Formula <- formula 56 | } else { 57 | Formula <- update(formula, paste0(" ~ . + f(", spat.ind, ", model=mesh)")) } 58 | } 59 | } 60 | 61 | # Fit model including predictions 62 | mod <- inla(Formula, family=c('poisson','binomial'), 63 | control.family = list(list(link = "log"), list(link = "cloglog")), 64 | data=inla.stack.data(stck), verbose=FALSE, 65 | control.results=list(return.marginals.random=FALSE, 66 | return.marginals.predictor=FALSE), 67 | control.predictor=list(A=inla.stack.A(stck), link=NULL, compute=TRUE), 68 | control.fixed=control.fixed, 69 | Ntrials=inla.stack.data(stck)$Ntrials, E=inla.stack.data(stck)$e, 70 | control.compute=list(waic=waic, dic=dic)) 71 | 72 | if(predictions) { 73 | id <- inla.stack.index(stck,tag.pred)$data 74 | pred <- data.frame(mean=mod$summary.fitted.values$mean[id], 75 | stddev=mod$summary.fitted.values$sd[id]) 76 | res <- list(model=mod, predictions=pred) 77 | } else { 78 | res <- mod 79 | } 80 | res 81 | } 82 | -------------------------------------------------------------------------------- /R/MakeSpatialRegion.R: -------------------------------------------------------------------------------- 1 | #' Function to set up spatial structure for region 2 | #' 3 | #' @param data Data (as data frame, with points having locations, or as a SpatialPointsDataFrame). Can be NULL, if bdry is not NULL. 4 | #' @param coords Names of columns for coordinates (X & Y) in data. Ignored if data is NULL. 5 | #' @param meshpars List of parameters to be sent to inla.mesh.2d(). 6 | #' @param bdry Polygon of boundary for region, of class Polygon. If \code{NULL}, draws a boundary around the points. 7 | #' @param proj Projection to use if data is not a projection. Defaults to utm (hopefully). 8 | #' @return A list with 3 elements: 9 | #' . mesh: mesh (from inla.mesh.2d) 10 | #' . spde: spde object for Matern model (from inla.spde2.matern) 11 | #' . w: weights for each point in mesh 12 | #' 13 | # DLM notes, need to cleanup and include 14 | # @section Mesh parameters: 15 | # The \code{meshpars} argument allows us to set options for mesh creation. Changing these options can have a big impact on the results of the fitted model. \code{cutoff} sets how faithfully the boundary is approximated (setting to 0 gives exactly the boundary supplied). \code{max.edge} is the maximum triangle edge (side) length inside and (optionally) outside the boundary, these are specified in the units of the coordinate system. \code{cutoff} avoids the many triangles being build around locations (this also acts to simplify the boundary), higher values lead to a simpler mesh (which is generated faster). 16 | # 17 | #' @export 18 | #' @import methods 19 | #' @import sp 20 | #' @import INLA 21 | MakeSpatialRegion <- function(data=NULL, coords=c("X","Y"), meshpars, bdry=NULL, proj = CRS("+proj=utm")) { 22 | # data=Data; coords=c("Xorig", "Yorig"); meshpars=list(cutoff=0.5, max.edge=c(1, 3), offset=c(1,1)) 23 | if(is.null(bdry) & is.null(data)) stop("Either data or a boundary has to be supplied") 24 | if(is.null(bdry)) { 25 | if(!class(data)=="SpatialPointsDataFrame") { 26 | dat.spat <- SpatialPointsDataFrame(data[,coords], data=data, proj4string = proj) 27 | } else { 28 | if(!is.projected(data)) data <- spTransform(data, CRSobj = proj) 29 | } 30 | bstart <- min(c(diff(sort(unique(dat.spat@coords[,1]))), diff(sort(dat.spat@coords[,2])))) 31 | poly.tmp <- rgeos::gBuffer(dat.spat, width=bstart, byid=TRUE) 32 | bdry <- rgeos::gBuffer(rgeos::gUnaryUnion(poly.tmp), width=bstart) 33 | bdry <- spTransform(bdry, CRSobj = proj) 34 | # bdry <- gBuffer(gBuffer(gUnaryUnion(poly.tmp), width=bstart), width=0) 35 | } else { 36 | if(class(bdry)!="SpatialPolygons") { 37 | bdry <- SpatialPolygons(Srl=list(Polygons(srl=list(bdry), ID="eek"))) 38 | } else { 39 | if(!is.projected(bdry)) bdry <- spTransform(bdry, CRSobj = proj) 40 | } 41 | } 42 | 43 | bdry <- rgeos::gBuffer(bdry, width=0) 44 | region.bdry <- inla.sp2segment(bdry) 45 | 46 | # Create mesh and spde object 47 | mesh <- inla.mesh.2d(boundary=region.bdry, cutoff=meshpars$cutoff, 48 | max.edge=meshpars$max.edge, offset=meshpars$offset) 49 | # region.mesh <- inla.mesh.2d(boundary=region.bdry, cutoff=0.1, max.edge=c(0.1, 3), offset=c(1,1)) 50 | spde <- inla.spde2.matern(mesh=mesh, alpha=2) # create spde object 51 | # theta <- c(-log(4*pi*s2x*kappa^2), log(kappa)) 52 | 53 | # Get areas for Voronoi tiles around each integration point 54 | dd <- deldir::deldir(mesh$loc[,1], mesh$loc[,2]) #, suppressMsge=TRUE) 55 | tiles <- deldir::tile.list(dd) 56 | # poly.gpc <- as(bdry@coords,'gpc.poly') 57 | poly.gpc <- as(bdry@polygons[[1]]@Polygons[[1]]@coords,'gpc.poly') 58 | w <- sapply(tiles, function(p) rgeos::area.poly(rgeos::intersect(as(cbind(p$x, p$y), 'gpc.poly'), poly.gpc))) 59 | return(list(mesh=mesh, spde=spde, w=w)) 60 | } 61 | -------------------------------------------------------------------------------- /data-raw/FormatSolTinData.R: -------------------------------------------------------------------------------- 1 | # Format Solitary Tinomou data 2 | # Data was given as a single data frame plus (later) a polygon for the range map. 3 | library(devtools) 4 | library(spatstat) 5 | library(splancs) 6 | library(rgbif) 7 | 8 | # GBIF 9 | Names <- name_suggest("tinamus solitorius", rank="species") 10 | SolTin.key <- Names$key[grep("solitarius", Names$canonicalName)] 11 | SolTinGBIF.all <- occ_search(taxonKey = SolTin.key, hasCoordinate = TRUE) #, eventDate = 2010) 12 | SolTinGBIF <- SolTinGBIF.all$data[!grepl("EBIRD", SolTinGBIF.all$data$collectionCode), 13 | c("decimalLatitude", "decimalLongitude", "basisOfRecord", "stateProvince", 14 | "eventDate", "geodeticDatum", "locality", "collectionCode")] 15 | 16 | SolTin_gbif <- data.frame(X = SolTinGBIF$decimalLongitude, Y = SolTinGBIF$decimalLatitude) 17 | SolTin_gbif <-SolTin_gbif[SolTin_gbif$X<0,] 18 | 19 | # eBird (from GBIF. Not a lot of data) 20 | SolTineBird <- SolTinGBIF.all$data[grepl("EBIRD", SolTinGBIF.all$data$collectionCode), 21 | c("decimalLatitude", "decimalLongitude", "basisOfRecord", "stateProvince", 22 | "eventDate", "geodeticDatum", "locality", "collectionCode")] 23 | SolTin_ebird <- data.frame(X = SolTineBird$decimalLongitude, Y = SolTineBird$decimalLatitude) 24 | SolTin_ebird <-SolTin_ebird[SolTin_ebird$X<0,] 25 | 26 | ########### 27 | # load other data 28 | load("data-raw/SolTinamou.RData") 29 | 30 | CovsToUse <- c( "For", "NPP", "Alt") 31 | # Split Data into different data types 32 | 33 | # Range map 34 | range.mask=as.owin(cbind(Data[,c("Xorig","Yorig")],In=Data$range), step=c(0.25, 0.3)) 35 | range.mask$m[is.na(range.mask$m)] <- FALSE 36 | range.poly=simplify.owin(as.polygonal(range.mask), dmin=0.5) 37 | # plot(range.poly) 38 | 39 | SolTin_range <- data.frame(X=range.poly$bdry[[1]]$x, Y=range.poly$bdry[[1]]$y) 40 | 41 | # ebird 42 | # SolTin_ebird <- Data[Data$ebird_pres>0, c("X", "Y")] 43 | # gbif 44 | # SolTin_gbif <- Data[Data$gbif_pres>0, c("X", "Y")] 45 | 46 | # Parks 47 | Data$IsPark=as.logical(apply(Data[,c("ParkPres","ParkAbs")],1,sum)) 48 | parks.mask=as.owin(cbind(Data[,c("Xorig","Yorig")],In=Data$IsPark), step=c(0.25, 0.3)) 49 | parks.mask$m[is.na(parks.mask$m)] <- FALSE 50 | parks.poly=simplify.owin(as.polygonal(parks.mask), dmin=0.5) 51 | 52 | # lapply over parks.poly[[4]] to get mean of covariates in the polygon, plus whether the species was observed in it 53 | Parks.lst=lapply(parks.poly[[4]], function(poly, data) { 54 | IN=inpip(data[,c("Xorig","Yorig")], poly) 55 | c(apply(data[IN,],2,mean), area=poly$area) 56 | #}, data=Data[,c("X","Y", gsub("RangeF", "range",CovsToUse), "ParkPres")]) # use this line if range should be a factor 57 | }, data=Data[,c("Xorig","Yorig", CovsToUse, "ParkPres")]) 58 | 59 | Parks.spat <- sapply(seq_along(parks.poly[[4]]), function(ind, pols) { 60 | pol <- pols[[ind]] 61 | Polygons(list(Polygon(cbind(pol$x,pol$y))), ID=paste0("Park", ind)) 62 | }, pols=parks.poly[[4]]) 63 | Parks.Data <- data.frame(area=unlist(lapply(parks.poly$bdry, function(poly) poly$area)), 64 | Present=unlist(lapply(Parks.lst, function(x) x["ParkPres"]>0))) 65 | rownames(Parks.Data) <- paste0("Park", seq_along(Parks.Data$area)) 66 | 67 | SolTin_parks <- as.data.frame( 68 | sapply(c("Xorig","Yorig", CovsToUse, "ParkPres","area"), function(wh, lst) { 69 | unlist(lapply(lst, function(list, WH) list[[WH]], WH=wh)) 70 | }, lst=Parks.lst, simplify=TRUE)) 71 | SolTin_parks$Present <- SolTin_parks$ParkPres>0 72 | SolTin_parks <- SolTin_parks[,c("Xorig", "Yorig", "area", "Present")] 73 | names(SolTin_parks) <- gsub("orig","", names(SolTin_parks)) 74 | 75 | # Environmenal covariates 76 | SolTin_covariates <- Data[,c("Xorig", "Yorig", "For", "NPP", "Alt")] 77 | names(SolTin_covariates) <- c("X", "Y", "Forest", "NPP", "Altitude") 78 | 79 | # Region polygon 80 | region.mask <- as.owin(cbind(SolTin_covariates[,c("X","Y")], In=rep(TRUE,nrow(SolTin_covariates))), 81 | step=c(0.25, 0.3)) 82 | region.mask$m[is.na(region.mask$m)] <- FALSE 83 | Region.poly <- simplify.owin(as.polygonal(region.mask), dmin=0.5) 84 | SolTin_polygon <- data.frame(X=Region.poly$bdry[[1]]$x[c(1,length(Region.poly$bdry[[1]]$x):1)], 85 | Y=Region.poly$bdry[[1]]$y[c(1,length(Region.poly$bdry[[1]]$y):1)]) 86 | 87 | # SolTin_polygon <- Polygons(list(region=Polygon(coords=PolyPoints)), ID="region") 88 | # region.polygon=SpatialPolygons(list(Pgon), proj4string = Projection) 89 | 90 | 91 | # Write data 92 | use_data(SolTin_ebird, overwrite = TRUE) #, pkg=PointedSDMs) 93 | use_data(SolTin_gbif, overwrite = TRUE) #, pkg=PointedSDMs) 94 | use_data(SolTin_parks, overwrite = TRUE) #, pkg=PointedSDMs) 95 | use_data(SolTin_covariates, overwrite = TRUE) #, pkg=PointedSDMs) 96 | use_data(SolTin_range, overwrite = TRUE) #, pkg=PointedSDMs) 97 | use_data(SolTin_polygon, overwrite = TRUE) #, pkg=PointedSDMs) 98 | 99 | # Save Spatial objects for tests 100 | Projection <- CRS("+proj=longlat +ellps=WGS84") 101 | ebird <- SpatialPoints(SolTin_ebird[,c("X","Y")], proj4string = Projection) 102 | save(ebird, file="tests/testthat/ebird.RData") 103 | gbif <- SpatialPoints(SolTin_gbif[,c("X","Y")], proj4string = Projection) 104 | save(gbif, file="tests/testthat/gbif.RData") 105 | parks <- SpatialPointsDataFrame(SolTin_parks[,c("X","Y")], 106 | data = SolTin_parks[,c("area","Present")], 107 | proj4string = Projection) 108 | save(parks, file="tests/testthat/parks.RData") 109 | parks.polygon <- SpatialPolygons(Srl=Parks.spat, proj4string = Projection) 110 | parks.polygons <- SpatialPolygonsDataFrame(Sr=parks.polygon, data=Parks.Data) 111 | save(parks.polygons, file="tests/testthat/parks_polygons.RData") 112 | 113 | covariates <- SpatialPointsDataFrame(SolTin_covariates[,c("X","Y")], 114 | data=SolTin_covariates[,c("Forest","NPP", "Altitude")], 115 | proj4string = Projection) 116 | save(covariates, file="tests/testthat/covariates.RData") 117 | pgon.range <- Polygons(list(region=Polygon(coords=SolTin_range)), ID="range") 118 | range <- SpatialPolygons(list(pgon.range), proj4string = Projection) 119 | save(range, file="tests/testthat/range.RData") 120 | Pgon <- Polygons(list(region=Polygon(coords=SolTin_polygon)), ID="region") 121 | region <- SpatialPolygons(list(Pgon), proj4string = Projection) 122 | save(region, file="tests/testthat/region.RData") 123 | 124 | 125 | 126 | # Spare code to create test files, before editting them 127 | # sapply(dir("R")[!grepl("MakeSpatialRegion", dir("R"))], function(filename) { 128 | # functionname <- gsub("\\.R", "", filename) 129 | # file.copy("tests/testthat/test-MakeSpatialRegion.R", paste0("tests/testthat/test-", functionname, ".R"), overwrite=TRUE) 130 | # }) 131 | -------------------------------------------------------------------------------- /vignettes/SolitaryTinomou.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "PointedSDMs: the Solitary Timanou" 3 | author: "Bob O'Hara" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Solitary Timanou} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ## Introduction 13 | 14 | This package is written to provide methods to fit species distribution models to data from a variety of sources. Presence-only data (e.g. species recorded provided by citizen scientists, or from museum collections) is often used in these enterprises, but other types of data are collected too. For example, expert range maps are often made (e.g. see any decent bird guide), and there are often more organised surveys which may provide data on species absences, or even (if we are lucky) abundance. The North American [Breeding Bird Survey](https://www.pwrc.usgs.gov/bbs/) is an example of the latter, where the data is freely available. Ideally we should use all of this data to produce a single distribution model, but this means we have to model each type of data in its own way. 15 | 16 | `PointedSDMs` does this by creating a model for the species' presence, which is modelled as an intensity (a higher intensity means the species is more abundant: it takes the view that absence is just a low abundance). This is a continuous surface, so we do not need to worry about the spatial scale (or more accutrately, we only need to worry about how well we are approximating the actual intensity). The observations are modelled as a function of this intensity as well other effects of the observation process. 17 | 18 | The actual model fitting is done using the [INLA package](http://www.r-inla.org/). This is convenient for the model fitting because it is flexible enough to deal with the different data types, and also much faster than MCMC (for example). The downside is that the data formatting and syntax can be tricky, so `PointedSDMs` does as much of this as possible. This vignette demonstrates how to do this, using data for one species, the solitary tinamou (*Tinamus solitarius*). 19 | 20 | ## The Data 21 | 22 | `PointedSDMs` wants data in `SpatialData` formats, but the example data used here is stored as data frame (which is probably the way a lot of data is stored). So we start by showing how to get the data into the right format. We have four sources of data: [eBird](http://ebird.org/content/ebird/), [GBIF](http://www.gbif.org/), a list of presences in national parks, from the parks' species lists, and an expert range map. In addition we have covariate data on a grid, and we will also need to create an extra layer, which will approximate the continuous surface, and onto which we project all of the other data. But first we read in the covariate data ("SolTin_covariates"), which has longitudeand latitude of the centres of pixels and then three covariates: percentage of forest, Net Primary Productivity, and altitude. 23 | 24 | ```{r ReadCovData, fig.width=8, message=FALSE} 25 | 26 | library(PointedSDMs) 27 | library(sp) 28 | library(spatstat) 29 | library(RColorBrewer) 30 | # library(mapview) 31 | data("SolTin_covariates") 32 | Projection <- CRS("+proj=longlat +ellps=WGS84") 33 | ``` 34 | 35 | The projection is standard, and is correct for this data. Next, we have to create a polygon to represent the region we are studying. We could use the maps package to define this, but here the region is defined by the data, so we draw a polygon around that (using functions from the spatstat package), and turn that into a SpatialPolygon (there is actually a data("SolTin_region"), but this show how to do this if you need it for other data sets). 36 | 37 | ```{r MakeRegionPolygon, message=FALSE} 38 | region.mask=as.owin(cbind(SolTin_covariates[,c("X","Y")], In=rep(TRUE,nrow(SolTin_covariates))), 39 | step=c(0.25, 0.3)) 40 | region.mask$m[is.na(region.mask$m)] <- FALSE 41 | Region.poly <- simplify.owin(as.polygonal(region.mask), dmin=0.5) 42 | PolyPoints <- cbind(Region.poly$bdry[[1]]$x[c(1,length(Region.poly$bdry[[1]]$x):1)], 43 | Region.poly$bdry[[1]]$y[c(1,length(Region.poly$bdry[[1]]$y):1)]) 44 | Pgon <- Polygons(list(region=Polygon(coords=PolyPoints)), ID="region") 45 | region.polygon=SpatialPolygons(list(Pgon), proj4string = Projection) 46 | ``` 47 | 48 | Then we out the covariate data into a spatial data frame, and plot them 49 | 50 | ```{r MakeCovariateSpDataFrame, fig.width=8, message=FALSE} 51 | # Put covariates into a spatial data frame 52 | Use <- c("Forest","NPP", "Altitude") # , "ForestQ","NPPQ", "AltitudeQ") 53 | Covariates <- SpatialPointsDataFrame(SolTin_covariates[,c("X","Y")], 54 | data=SolTin_covariates[,Use], proj4string = Projection) 55 | Covariates@data <-data.frame(apply(Covariates@data,2, scale)) # scale the covariates 56 | # spplot(Covariates, layout=c(3,1), col.regions=grey(seq(0,1,length=20)), key.space="right") 57 | spplot(Covariates, layout=c(3,1), col.regions=brewer.pal(6, "Blues")[-1], key.space="right", pretty=TRUE) 58 | 59 | ``` 60 | 61 | The darker colour are the lower values, so (for example) the coast and southwest parts of the range are at lower altitude. Expert opinion is that this is a bird of the lowlands (below 500m) and forests. 62 | 63 | Now we can read in the data other data and convert it into Spatial* objects. Then we can plot it. 64 | 65 | ```{r ReadSpeciesData, message=FALSE, fig.width=6, fig.height=6} 66 | data("SolTin_ebird") 67 | ebird <- SpatialPoints(SolTin_ebird[,c("X","Y")], proj4string = Projection) 68 | data("SolTin_gbif") 69 | gbif <- SpatialPoints(SolTin_gbif[,c("X","Y")], proj4string = Projection) 70 | data("SolTin_parks") 71 | Parks <- SpatialPointsDataFrame(SolTin_parks[,c("X","Y")], 72 | data = SolTin_parks[,c("area","Present")], 73 | proj4string = Projection) 74 | data("SolTin_range") 75 | Pgon.range <- Polygons(list(region=Polygon(coords=SolTin_range)), ID="range") 76 | range.polygon=SpatialPolygons(list(Pgon.range), proj4string = Projection) 77 | 78 | MapCols <- c(brewer.pal(4, "Paired"), grey(c(0.4,0.1))) 79 | # c("blue3", "darkgreen", "pink", "red", "grey70") 80 | names(MapCols) <- c("eBird", "GBIF", "Park, absent", "Park, present", "Region", "Expert Range") 81 | 82 | par(mar=rep(0,4)) 83 | plot(region.polygon, col=MapCols["Region"]) 84 | plot(range.polygon, col=MapCols["Expert Range"], border=NA, add=TRUE) 85 | points(ebird, cex=0.5, pch=19, col=MapCols["eBird"]) 86 | points(gbif, cex=0.5, pch=19, col=MapCols["GBIF"]) 87 | points(Parks, cex=0.7, pch=19, col=MapCols[c("Park, absent", "Park, present")][1+Parks@data$Present]) 88 | 89 | legend(region.polygon@bbox["x","min"]+0.01*diff(region.polygon@bbox["x",]), 90 | region.polygon@bbox["y","min"]+0.95*diff(region.polygon@bbox["y",]), 91 | legend = names(MapCols), fill = MapCols, cex=0.8) 92 | 93 | ``` 94 | 95 | The expert range map does not include eBird and GBIF data from the north-west of the region, and outside of that is too wide. The other po0ints are generally consistent with each other, except that hte species is not listed in several parks in the west where the species is otherwise recorded. 96 | 97 | ## Data Preparation 98 | 99 | We need to do some preparation before fitting the model. The model works by approximating the continuous space by a tesselation of triangles, so we have to create that tesselation. This means working out where to place the vertices of the triangles: this creates a mesh. The more vertices, the better the approximation (but the longer the calculations take). So, we can use different mesh parameters ("Meshpars") to change this. We can plot the mesh to see if it's OK: it is also better if the triangles aren't too far away from being equilateral. 100 | 101 | ```{r MakeMesh, message=FALSE, warning=FALSE, fig.width=5, fig.height=5} 102 | 103 | Meshpars <- list(cutoff=0.8, max.edge=c(1, 3), offset=c(1,1)) 104 | Mesh <- MakeSpatialRegion(data=NULL, bdry=region.polygon, meshpars=Meshpars, 105 | proj = Projection) 106 | stk.ip <- MakeIntegrationStack(mesh=Mesh$mesh, data=Covariates, area=Mesh$w, 107 | tag='ip', InclCoords=TRUE) 108 | stk.ip.dists <- AddDistToRangeToStack(in.stk=stk.ip, coords=c("X", "Y"), 109 | polynoms = range.polygon, scale=FALSE) 110 | plot(Mesh$mesh) 111 | ``` 112 | 113 | The blue line is the region: within that we would usually want more points than there are here (the cost of doing this is that the computations take longer). The points outside the region are needed for the modelling, but will be ignored in any results. 114 | 115 | Next we can create some data that we want to predict onto, in order to draw a map of the predicted presence. The resolution of the map is controlled by Nxy (the width and height in pixels). We could, of course, use different data if we wanted to predict a future distribution, of course. Again, this grid is coarser than we would usually want, to speed up the computation. 116 | 117 | ```{r MakePred, message=TRUE} 118 | 119 | # Create data for projections 120 | Nxy.scale <- 0.5 # use this to change the resolution of the predictions 121 | Boundary <- Mesh$mesh$loc[Mesh$mesh$segm$int$idx[,2],] # get the boundary of the region 122 | Nxy <- round(c(diff(range(Boundary[,1])), diff(range(Boundary[,2])))/Nxy.scale) 123 | stk.pred <- MakeProjectionGrid(nxy=Nxy, mesh=Mesh$mesh, data=Covariates, 124 | tag='pred', boundary=Boundary) 125 | stk.pred$stk <- AddDistToRangeToStack(in.stk=stk.pred$stk, coords=c("X", "Y"), 126 | polynoms = range.polygon, scale=FALSE) 127 | ``` 128 | 129 | Now we can format the presence-only data (i.e. the eBird and GBIF data), and the parks data. This is easy with Make*Stack functions. The tags are important if we want to extract different parts of the model, e.g. the predictions. 130 | 131 | ```{r MakeDataStacks, message=FALSE} 132 | stk.eBird <- MakePointsStack(presences=ebird, data=Covariates, mesh=Mesh$mesh, 133 | polynoms = range.polygon, tag='ebird', 134 | InclCoords=TRUE) 135 | stk.gbif <- MakePointsStack(presences=gbif, data=Covariates, mesh=Mesh$mesh, 136 | polynoms = range.polygon, tag='gbif', 137 | InclCoords=TRUE) 138 | stk.parks <- MakeBinomStack(observs=Parks, data=Covariates, mesh=Mesh$mesh, 139 | presname='Present', polynoms = range.polygon, 140 | tag='parks', InclCoords=TRUE) 141 | ``` 142 | 143 | Now we've done all that, we can fit the model. We pass all of the data to the function as stacks, along with the mesh. 144 | 145 | ```{r FitModel, message=FALSE} 146 | SolTinModel <- FitModel(stk.eBird, stk.gbif, stk.ip.dists, stk.parks, 147 | stk.pred$stk, CovNames=NULL, mesh = Mesh$mesh, 148 | predictions = TRUE) 149 | summary(SolTinModel$model)$fixed 150 | ``` 151 | 152 | The summary suggests that the covariates are not good explanatory variables. Unfortunately adding quadratic terms does not help either. We can, though, plot the predictions: 153 | 154 | ```{r PlotModel, message=FALSE, fig.width=6, fig.height=6} 155 | 156 | Pred <- SpatialPixelsDataFrame(points=stk.pred$predcoords, data=SolTinModel$predictions, proj4string=Projection) 157 | Pred@data$precision <- Pred@data$stddev^-2 158 | 159 | ncolours <- 200 160 | greencols.fn <- colorRampPalette(brewer.pal(9, 'Greens')) 161 | greencols <- greencols.fn(ncolours) 162 | bluecols.fn <- colorRampPalette(brewer.pal(9, 'Blues')) 163 | bluecols <- bluecols.fn(ncolours) 164 | 165 | map.mean <- mapview(Pred, zcol = c("mean"), legend = TRUE, # alpha=0.2, 166 | col.regions=greencols) 167 | map.stddev <- mapview(Pred, zcol = c("stddev"), legend = TRUE, alpha=0.3, 168 | col.regions=bluecols) 169 | sync(map.mean, map.stddev) 170 | 171 | 172 | ``` 173 | 174 | This suggests that there is a pattern, with tinamou tending to be in the central/eastern region. There is more uncertainty around the edges, so the posterior mean tends to appraoch the overall mean, hence the apparent higher values there. The model is informed more by the spatial surface rather than the covariates, though. So, let's see what happens if we remove the spatial part of the model. 175 | 176 | ```{r FitModelNoSpat, message=FALSE} 177 | SolTinModelNoSpat <- FitModel(stk.eBird, stk.gbif, stk.ip.dists, stk.parks, stk.pred$stk, 178 | CovNames=NULL, mesh = Mesh$mesh, predictions = TRUE, spat.ind = NULL) 179 | summary(SolTinModelNoSpat$model)$fixed 180 | ``` 181 | 182 | The environmental covariates still don't seem to do anything, and although the map has variation, it is more variable that the map above, which at least shows clusters. 183 | 184 | ```{r PlotModelNoSpat, message=FALSE, fig.width=6, fig.height=6} 185 | PredNoSpat <- SpatialPixelsDataFrame(points=stk.pred$predcoords, 186 | data=SolTinModelNoSpat$predictions, proj4string=Projection) 187 | # plot(PredNoSpat, attr="mean", col=grey(seq(0,1,length=100))) 188 | map.nospat.mean <- mapview(PredNoSpat, zcol = c("mean"), legend = TRUE, # alpha=0.2, 189 | col.regions=greencols) 190 | map.nospat.stddev <- mapview(PredNoSpat, zcol = c("stddev"), legend = TRUE, alpha=0.3, 191 | col.regions=bluecols) 192 | sync(map.nospat.mean, map.nospat.stddev) 193 | 194 | ``` 195 | 196 | All of this is a bit disappointing - one would hope an example species would show some response to the environment. The next step is to look at interactions. We only look at Forest and Altitude, as these are where there is predicted to be an effect on the distbution. But the results still give no evidence for the effects going in any direction. 197 | 198 | ```{r TryQuadraticSurface, message=FALSE} 199 | Quad.form <- resp ~ 0 + (Forest + Altitude)^2 + I(Forest^2) + I(Altitude^2) + int.ebird + DistToPoly1 + 200 | int.gbif + Intercept + X + Y + int.parks + f(i, model = mesh) 201 | SolTinModel.quad <- FitModel(stk.eBird, stk.gbif, stk.ip.dists, stk.parks, stk.pred$stk, 202 | formula=Quad.form, spat.ind = NULL, 203 | CovNames=NULL, mesh = Mesh$mesh, predictions = TRUE) 204 | summary(SolTinModel.quad$model)$fixed 205 | ``` 206 | 207 | -------------------------------------------------------------------------------- /README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

PointedSDMs

30 |

This is an R package to fit SDMs in R using a point process formulation. It uses INLA to do the fitting, so a lot of the functions are written to re-format Spatial data so tha INLA can use it.

31 |

Installation

32 |

At the moment this package is not public, so you will either have a zip file, which you can use with install.packages(), or you will have access to hte GitHub repository, so

33 |

R devtools::install_github("oharar/PointedSDMs")

34 |

should work.

35 |

Usage

36 |

Check out the vignette:

37 |

R vignette("SolitaryTinomou")

38 | 39 | 40 | 41 | --------------------------------------------------------------------------------