Skip to content

Commit 0762009

Browse files
authored
Merge pull request #52 from ropensci/fix/rm-sp-build-polys
Fix/rm sp build polys
2 parents dfec811 + 40ac530 commit 0762009

File tree

11 files changed

+480
-233
lines changed

11 files changed

+480
-233
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
export(build_lines)
44
export(build_lines_sp)
55
export(build_polys)
6+
export(build_polys_sp)
67
export(dyad_id)
78
export(edge_dist)
89
export(edge_nn)

R/build_polys.R

Lines changed: 75 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,77 @@
11
#' Build Polygons
22
#'
3-
#' \code{build_polys} creates a \code{SpatialPolygons} object from a
4-
#' \code{data.table}. The function accepts a \code{data.table} with
5-
#' relocation data, individual identifiers, a \code{projection},
6-
#' \code{hrType} and \code{hrParams}. The relocation data is transformed
7-
#' into \code{SpatialPolygons} for each individual and optionally, each
8-
#' \code{splitBy}. Relocation data should be in two columns representing
9-
#' the X and Y coordinates.
10-
#'
11-
#' The \code{DT} must be a \code{data.table}. If your data is a
12-
#' \code{data.frame}, you can convert it by reference using
13-
#' \code{\link[data.table:setDT]{data.table::setDT}}.
14-
#'
15-
#' The \code{id}, \code{coords} (and optional \code{splitBy}) arguments
16-
#' expect the names of respective columns in \code{DT} which correspond
3+
#' `build_polys` generates a simple feature collection with POLYGONs from a
4+
#' `data.table`. The function accepts a `data.table` with
5+
#' relocation data, individual identifiers, a projection,
6+
#' home range type and parameters. The relocation
7+
#' data is transformed into POLYGONs using either [adehabitatHR::mcp] or
8+
#' [adehabitatHR::kernelUD] for each individual and, optionally,
9+
#' combination of columns listed in `splitBy`. Relocation data should be in two
10+
#' columns representing the X and Y coordinates.
11+
#'
12+
#' [group_polys] uses `build_polys` for grouping overlapping
13+
#' polygons created from relocations.
14+
#'
15+
#' ## R-spatial evolution
16+
#'
17+
#' Please note, spatsoc has followed updates from R spatial, GDAL and PROJ for
18+
#' handling projections, see more below and details at
19+
#' \url{https://r-spatial.org/r/2020/03/17/wkt.html}.
20+
#'
21+
#' In addition, `build_polys` previously used [sp::SpatialPoints] but has been
22+
#' updated to use [sf::st_as_sf] according to the R-spatial evolution, see more
23+
#' at \url{https://r-spatial.org/r/2022/04/12/evolution.html}. A deprecated
24+
#' version of this function using [sp::SpatialPoints] is retained as
25+
#' [build_polys_sp] temporarily but users are urged to transition as soon as
26+
#' possible.
27+
#'
28+
#' ## Notes on arguments
29+
#'
30+
#' The `DT` must be a `data.table`. If your data is a `data.frame`, you can
31+
#' convert it by reference using [data.table::setDT].
32+
#'
33+
#' The `id`, `coords` (and optional `splitBy`) arguments
34+
#' expect the names of respective columns in `DT` which correspond
1735
#' to the individual identifier, X and Y coordinates, and additional
1836
#' grouping columns.
1937
#'
20-
#' The \code{projection} argument expects a character string defining
21-
#' the EPSG code. For example, for UTM zone 36N (EPSG 32736), the projection
22-
#' argument is "EPSG:32736". See \url{https://spatialreference.org}
23-
#' for a list of EPSG codes. Please note, R spatial has followed updates
24-
#' to GDAL and PROJ for handling projections, see more at
25-
#' \url{https://r-spatial.org/r/2020/03/17/wkt.html}. It is likely
26-
#' that \code{build_polys} will return "Warning in proj4string(xy) :
27-
#' CRS object has comment, which is lost in output" due to these changes.
28-
#'
29-
#' The \code{hrType} must be either one of "kernel" or "mcp". The
30-
#' \code{hrParams} must be a named list of arguments matching those
31-
#' of \code{adehabitatHR::kernelUD} and \code{adehabitatHR::getverticeshr}
32-
#' or \code{adehabitatHR::mcp}.
33-
#'
34-
#' The \code{splitBy} argument offers further control building
35-
#' \code{SpatialPolygons}. If in your \code{DT}, you have multiple
38+
#' The `projection` argument expects a character string or numeric
39+
#' defining the coordinate reference system to be passed to [sf::st_crs].
40+
#' For example, for UTM zone 36S (EPSG 32736), the projection
41+
#' argument is `projection = "EPSG:32736"` or `projection = 32736`.
42+
#' See \url{https://spatialreference.org}
43+
#' for a list of EPSG codes.
44+
#'
45+
#' The `hrType` must be either one of "kernel" or "mcp". The
46+
#' `hrParams` must be a named list of arguments matching those
47+
#' of [adehabitatHR::kernelUD] and [adehabitatHR::getverticeshr]
48+
#' or [adehabitatHR::mcp].
49+
#'
50+
#' The `splitBy` argument offers further control building
51+
#' POLYGONs. If in your `DT`, you have multiple
3652
#' temporal groups (e.g.: years) for example, you can provide the
37-
#' name of the column which identifies them and build \code{SpatialPolygons}
53+
#' name of the column which identifies them and build POLYGONs
3854
#' for each individual in each year.
3955
#'
40-
#' \code{group_polys} uses \code{build_polys} for grouping overlapping
41-
#' polygons created from relocations.
4256
#'
43-
#' @return \code{build_polys} returns a \code{SpatialPolygons} object
44-
#' with a polyon for each individual (and optionally \code{splitBy}
45-
#' combination).
57+
#' @return `build_polys` returns a simple feature collection with POLYGONs
58+
#' for each individual (and optionally `splitBy` combination).
4659
#'
47-
#' An error is returned when \code{hrParams} do not match the arguments
48-
#' of the \code{hrType} \code{adehabitatHR} function.
60+
#' An error is returned when `hrParams` do not match the arguments
61+
#' of the respective `hrType` `adehabitatHR` function.
4962
#'
5063
#'
5164
#' @inheritParams group_polys
5265
#' @param spPts alternatively, provide solely a SpatialPointsDataFrame with one
53-
#' column representing the ID of each point.
66+
#' column representing the ID of each point, as specified by [adehabitatHR::mcp]
67+
#' or [adehabitatHR::kernelUD]
5468
#' @param projection numeric or character defining the coordinate reference
55-
#' system to be passed to [sf::st_crs()]. For example, either
69+
#' system to be passed to [sf::st_crs]. For example, either
5670
#' `projection = "EPSG:32736"` or `projection = 32736`.
5771
#' @export
5872
#'
5973
#' @family Build functions
60-
#' @seealso \code{\link{group_polys}}
74+
#' @seealso [group_polys]
6175
#'
6276
#' @examples
6377
#' # Load data.table
@@ -70,7 +84,7 @@
7084
#' DT[, datetime := as.POSIXct(datetime, tz = 'UTC')]
7185
#'
7286
#' # EPSG code for example data
73-
#' utm <- 'EPSG:32736'
87+
#' utm <- 32736
7488
#'
7589
#' # Build polygons for each individual using kernelUD and getverticeshr
7690
#' build_polys(DT, projection = utm, hrType = 'kernel',
@@ -79,18 +93,9 @@
7993
#'
8094
#' # Build polygons for each individual by year
8195
#' DT[, yr := year(datetime)]
82-
#' build_polys(DT, projection = utm, hrType = 'mcp', hrParams = list(percent = 95),
96+
#' build_polys(DT, projection = utm, hrType = 'mcp',
97+
#' hrParams = list(percent = 95),
8398
#' id = 'ID', coords = c('X', 'Y'), splitBy = 'yr')
84-
#'
85-
#' # Build polygons from SpatialPointsDataFrame
86-
#' library(sp)
87-
#' pts <- SpatialPointsDataFrame(coords = DT[, .(X, Y)],
88-
#' proj4string = CRS(utm),
89-
#' data = DT[, .(ID)]
90-
#' )
91-
#'
92-
#' build_polys(spPts = pts, hrType = 'mcp', hrParams = list(percent = 95))
93-
#'
9499
build_polys <- function(DT = NULL,
95100
projection = NULL,
96101
hrType = NULL,
@@ -153,7 +158,7 @@ build_polys <- function(DT = NULL,
153158
FUN = function(x) {
154159
is.numeric(x) | is.character(x) | is.integer(x)
155160
}
156-
), .SDcols = splitBy]))) {
161+
), .SDcols = c(splitBy)]))) {
157162
stop(
158163
strwrap(
159164
prefix = " ",
@@ -176,12 +181,15 @@ build_polys <- function(DT = NULL,
176181
}
177182

178183
if (is.null(spPts)) {
179-
spPts <- sp::SpatialPointsDataFrame(
180-
DT[, .SD, .SDcols = eval.parent(coords, n = 1)],
181-
proj4string = sp::CRS(projection),
182-
data = DT[, .(ID = do.call(paste,
183-
c(.SD, sep = '-'))),
184-
.SDcols = splitBy])
184+
DT[, ade_id := do.call(function(...) paste(..., sep = '-'), .SD),
185+
.SDcols = c(splitBy)]
186+
spPts <- sf::as_Spatial(
187+
sf::st_as_sf(
188+
DT[, .SD, .SDcols = c(coords, 'ade_id')],
189+
coords = coords,
190+
crs = sf::st_crs(projection)),
191+
IDs = DT$ade_id
192+
)
185193
}
186194

187195
hrParams$xy <- spPts
@@ -192,7 +200,7 @@ build_polys <- function(DT = NULL,
192200
if (!('unout' %in% names(hrParams))) {
193201
hrParams$unout <- 'm2'
194202
}
195-
return(do.call(adehabitatHR::mcp, hrParams))
203+
out <- do.call(adehabitatHR::mcp, hrParams)
196204
} else {
197205
stop(
198206
strwrap(
@@ -213,10 +221,10 @@ build_polys <- function(DT = NULL,
213221
}
214222
kern <- do.call(adehabitatHR::kernelUD,
215223
hrParams[intersect(names(hrParams), names(kernelParam))])
216-
return(do.call(adehabitatHR::getverticeshr,
224+
out <- do.call(adehabitatHR::getverticeshr,
217225
c(x = list(kern),
218226
hrParams[intersect(names(hrParams),
219-
names(verticesParam))])))
227+
names(verticesParam))]))
220228
} else {
221229
stop(
222230
strwrap(
@@ -228,7 +236,11 @@ build_polys <- function(DT = NULL,
228236
)
229237
)
230238
}
239+
} else {
240+
stop('hrType not one of "kernel" or "mcp"')
231241
}
242+
243+
return(sf::st_as_sf(out))
232244
}
233245

234246

R/build_polys_sp.R

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#' Build Polygons (deprecated version of function with retired spatial packages)
2+
#'
3+
#' @inheritParams build_polys
4+
#' @export
5+
#'
6+
#' @family Build functions
7+
#' @seealso \code{\link{group_polys}}
8+
build_polys_sp <- function(DT = NULL,
9+
projection = NULL,
10+
hrType = NULL,
11+
hrParams = NULL,
12+
id = NULL,
13+
coords = NULL,
14+
splitBy = NULL,
15+
spPts = NULL) {
16+
.Deprecated(msg = 'build_polys has been updated to use modern spatial R packages, removing dependencies on rgdal, rgeos, maptools in favor of sf. This version will be preserved until September 2023 for testing and user transition.')
17+
18+
# due to NSE notes in R CMD check
19+
. <- NULL
20+
21+
if (is.null(DT) && is.null(spPts)) {
22+
stop('input DT or spPts required')
23+
}
24+
25+
if (!is.null(DT) && !is.null(spPts)) {
26+
stop('cannot provide both DT and spPts')
27+
}
28+
29+
if (!is.null(DT) && is.null(spPts)) {
30+
if (is.null(coords)) {
31+
stop('coords must be provided')
32+
}
33+
34+
if (is.null(id)) {
35+
stop('id must be provided')
36+
}
37+
38+
if (is.null(projection)) {
39+
stop('projection must be provided')
40+
}
41+
42+
if (length(coords) != 2) {
43+
stop('coords requires a vector of column names for coordinates X and Y')
44+
}
45+
46+
if (is.null(splitBy)) {
47+
splitBy <- id
48+
} else {
49+
splitBy <- c(id, splitBy)
50+
}
51+
52+
if (any(!(c(splitBy, coords) %in% colnames(DT)))) {
53+
stop(paste0(
54+
as.character(paste(setdiff(
55+
c(id, coords), colnames(DT)
56+
),
57+
collapse = ', ')),
58+
' field(s) provided are not present in input DT'
59+
))
60+
}
61+
62+
if (any(!(DT[, vapply(.SD, is.numeric, TRUE),
63+
.SDcols = coords]))) {
64+
stop('coords must be numeric')
65+
}
66+
67+
if (any(!(DT[, lapply(
68+
.SD,
69+
FUN = function(x) {
70+
is.numeric(x) | is.character(x) | is.integer(x)
71+
}
72+
), .SDcols = splitBy]))) {
73+
stop(
74+
strwrap(
75+
prefix = " ",
76+
initial = "",
77+
x = 'id (and splitBy when provided)
78+
must be character, numeric or integer type'
79+
)
80+
)
81+
}
82+
83+
}
84+
85+
86+
if (is.null(hrType)) {
87+
stop('hrType must be provided')
88+
}
89+
90+
if (is.null(hrParams)) {
91+
message('hrParams is not provided, using defaults')
92+
}
93+
94+
if (is.null(spPts)) {
95+
spPts <- sp::SpatialPointsDataFrame(
96+
DT[, .SD, .SDcols = eval.parent(coords, n = 1)],
97+
proj4string = sp::CRS(projection),
98+
data = DT[, .(ID = do.call(paste,
99+
c(.SD, sep = '-'))),
100+
.SDcols = splitBy])
101+
}
102+
103+
hrParams$xy <- spPts
104+
105+
if (hrType == 'mcp') {
106+
functionParams <- formals(adehabitatHR::mcp)
107+
if (all(names(hrParams) %in% names(functionParams))) {
108+
if (!('unout' %in% names(hrParams))) {
109+
hrParams$unout <- 'm2'
110+
}
111+
return(do.call(adehabitatHR::mcp, hrParams))
112+
} else {
113+
stop(
114+
strwrap(
115+
prefix = " ",
116+
initial = "",
117+
x = 'hrParams provided do not match function parameters,
118+
see ?adehabitatHR::mcp'
119+
)
120+
)
121+
}
122+
} else if (hrType == 'kernel') {
123+
kernelParam <- formals(adehabitatHR::kernelUD)
124+
verticesParam <- formals(adehabitatHR::getverticeshr.estUD)
125+
126+
if (all(names(hrParams) %in% c(names(kernelParam), names(verticesParam)))) {
127+
if (!('unout' %in% names(hrParams))) {
128+
hrParams$unout <- 'm2'
129+
}
130+
kern <- do.call(adehabitatHR::kernelUD,
131+
hrParams[intersect(names(hrParams), names(kernelParam))])
132+
return(do.call(adehabitatHR::getverticeshr,
133+
c(x = list(kern),
134+
hrParams[intersect(names(hrParams),
135+
names(verticesParam))])))
136+
} else {
137+
stop(
138+
strwrap(
139+
prefix = " ",
140+
initial = "",
141+
x = 'hrParams provided do not match
142+
function parameters, see ?adehabitatHR::kernelUD
143+
and ?adehabitatHR::getverticeshr'
144+
)
145+
)
146+
}
147+
}
148+
}
149+
150+

R/group_lines.R

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
#' argument is "EPSG:32736". See \url{https://spatialreference.org}
2525
#' for a list of EPSG codes. Please note, R spatial has followed updates
2626
#' to GDAL and PROJ for handling projections, see more at
27-
#' \url{https://r-spatial.org/r/2020/03/17/wkt.html}. It is likely
28-
#' that \code{build_polys} will return "Warning in proj4string(xy) :
29-
#' CRS object has comment, which is lost in output" due to these changes.
27+
#' \url{https://r-spatial.org/r/2020/03/17/wkt.html}.
3028
#'
3129
#' The \code{sortBy} is used to order the input \code{data.table} when creating
3230
#' \code{SpatialLines}. It must a \code{POSIXct} to ensure the rows are sorted

R/group_polys.R

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222
#' 'EPSG:32736'. See \url{https://spatialreference.org} for a list of EPSG
2323
#' codes. Please note, R spatial has followed updates to GDAL and PROJ for
2424
#' handling projections, see more at
25-
#' \url{https://r-spatial.org/r/2020/03/17/wkt.html}. It is likely
26-
#' that \code{build_polys} will return "Warning in proj4string(xy) :
27-
#' CRS object has comment, which is lost in output" due to these changes.
25+
#' \url{https://r-spatial.org/r/2020/03/17/wkt.html}.
2826
#'
2927
#' The \code{hrType} must be either one of "kernel" or "mcp". The
3028
#' \code{hrParams} must be a named list of arguments matching those of

0 commit comments

Comments
 (0)