From f9fe32321467cf3a5c7f2809bb9c51f9f4a2eb72 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 19 Jul 2024 12:07:08 -0300 Subject: [PATCH 01/60] fst distance to group centroid --- R/distance_to_group_centroid.R | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 R/distance_to_group_centroid.R diff --git a/R/distance_to_group_centroid.R b/R/distance_to_group_centroid.R new file mode 100644 index 00000000..5bd10395 --- /dev/null +++ b/R/distance_to_group_centroid.R @@ -0,0 +1,34 @@ +#' Calculate distance to group centroid +#' +#' @param DT expects group_mean columns generated with group_centroid +#' @param coords character vector of column names for x, y +distance_to_group_centroid <- function(DT, coords, group = 'group', + return_rank = FALSE) { + pre <- 'group_mean_' + + stopifnot(length(coords) == 2) + + xcol <- first(coords) + ycol <- last(coords) + group_xcol <- paste0(pre, xcol) + group_ycol <- paste0(pre, ycol) + + stopifnot(xcol %in% colnames(DT)) + stopifnot(ycol %in% colnames(DT)) + stopifnot(group_xcol %in% colnames(DT)) + stopifnot(group_ycol %in% colnames(DT)) + stopifnot(group %in% colnames(DT)) + + + DT[, dist_group_centroid := + sqrt((.SD[[xcol]] - .SD[[group_xcol]])^2 + + (.SD[[ycol]] - .SD[[group_ycol]])^2)] + + if (return_rank) { + DT[, N_by_group := .N, by = c(group)] + DT[, rank_dist_group_centroid := + data.table::frank(dist_group_centroid), + by = c(group)] + } + return(DT[]) +} From 89536d18ed2724ee6b6dc1b046bf2a5bd45968b0 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 19 Jul 2024 12:07:12 -0300 Subject: [PATCH 02/60] fst bearing to group centroid --- R/bearing_to_group_centroid.R | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 R/bearing_to_group_centroid.R diff --git a/R/bearing_to_group_centroid.R b/R/bearing_to_group_centroid.R new file mode 100644 index 00000000..f9a35b25 --- /dev/null +++ b/R/bearing_to_group_centroid.R @@ -0,0 +1,28 @@ +#' Calculate absolute bearing to group centroid +#' +#' @param DT expects group_mean columns generated with group_centroid +#' @param coords character vector of column names for x, y +bearing_to_group_centroid <- function(DT, coords = NULL) { + pre <- 'group_mean_' + + stopifnot(length(coords) == 2) + + xcol <- first(coords) + ycol <- last(coords) + group_xcol <- paste0(pre, xcol) + group_ycol <- paste0(pre, ycol) + + stopifnot(xcol %in% colnames(DT)) + stopifnot(ycol %in% colnames(DT)) + stopifnot(group_xcol %in% colnames(DT)) + stopifnot(group_ycol %in% colnames(DT)) + + DT[, bearing_centroid := fifelse( + .SD[[xcol]] == .SD[[group_xcol]] & + .SD[[ycol]] == .SD[[group_ycol]], + NaN, + atan2(.SD[[group_ycol]] - .SD[[ycol]], + (.SD[[group_xcol]] - .SD[[xcol]])) + )] + return(DT[]) +} From ce3597f7b3ba1420765469998da2598fe748b6d7 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 14:18:58 -0300 Subject: [PATCH 03/60] rename functions --- R/{bearing_to_group_centroid.R => direction_to_centroid.R} | 2 +- R/{distance_to_group_centroid.R => distance_to_centroid.R} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename R/{bearing_to_group_centroid.R => direction_to_centroid.R} (92%) rename R/{distance_to_group_centroid.R => distance_to_centroid.R} (93%) diff --git a/R/bearing_to_group_centroid.R b/R/direction_to_centroid.R similarity index 92% rename from R/bearing_to_group_centroid.R rename to R/direction_to_centroid.R index f9a35b25..5d9b995d 100644 --- a/R/bearing_to_group_centroid.R +++ b/R/direction_to_centroid.R @@ -2,7 +2,7 @@ #' #' @param DT expects group_mean columns generated with group_centroid #' @param coords character vector of column names for x, y -bearing_to_group_centroid <- function(DT, coords = NULL) { +direction_to_centroid <- function(DT, coords = NULL) { pre <- 'group_mean_' stopifnot(length(coords) == 2) diff --git a/R/distance_to_group_centroid.R b/R/distance_to_centroid.R similarity index 93% rename from R/distance_to_group_centroid.R rename to R/distance_to_centroid.R index 5bd10395..af8fcd52 100644 --- a/R/distance_to_group_centroid.R +++ b/R/distance_to_centroid.R @@ -2,7 +2,7 @@ #' #' @param DT expects group_mean columns generated with group_centroid #' @param coords character vector of column names for x, y -distance_to_group_centroid <- function(DT, coords, group = 'group', +distance_to_centroid <- function(DT, coords, group = 'group', return_rank = FALSE) { pre <- 'group_mean_' From 802fa77bf33eb6231ad2beae11e05903a0e007c9 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:31:14 -0300 Subject: [PATCH 04/60] title --- R/distance_to_centroid.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index af8fcd52..6ccee1ad 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -1,4 +1,4 @@ -#' Calculate distance to group centroid +#' Distance to group centroid #' #' @param DT expects group_mean columns generated with group_centroid #' @param coords character vector of column names for x, y From d725badd891703a32a4208ad1e7df966d1c6bdea Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:16 -0300 Subject: [PATCH 05/60] description, details --- R/distance_to_centroid.R | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 6ccee1ad..238f4de9 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -1,10 +1,26 @@ #' Distance to group centroid #' -#' @param DT expects group_mean columns generated with group_centroid -#' @param coords character vector of column names for x, y -distance_to_centroid <- function(DT, coords, group = 'group', - return_rank = FALSE) { - pre <- 'group_mean_' +#' \code{distance_to_centroid} calculates the distance of each relocation to the +#' centroid of the spatiotemporal group identified by \code{group_pts}. The +#' function accepts a \code{data.table} with relocation data appended with a +#' \code{group} column from \code{group_pts} and centroid columns from +#' \code{centroid_group}. Relocation data should be in two columns representing +#' the X and Y coordinates. +#' +#' The \code{DT} must be a \code{data.table}. If your data is a +#' \code{data.frame}, you can convert it by reference using +#' \code{\link[data.table:setDT]{data.table::setDT}} or by reassigning using +#' \code{\link[data.table:data.table]{data.table::data.table}}. +#' +#' This function expects a \code{group} column present generated with the +#' \code{group_pts} function and centroid coordinate columns generated with the +#' \code{centroid_group} function. The \code{coords} and \code{group} arguments +#' expect the names of columns in \code{DT} which correspond to the X and Y +#' coordinates and group columns. The \code{return_rank} argument controls if +#' the rank of each individual's distance to the group centroid is also +#' returned. The \code{ties.method} argument is passed to +#' \code{data.table::frank}, see details at +#' \code{\link[data.table:frank]{?data.table::frank}}. stopifnot(length(coords) == 2) From 826784e3d1bbe8b438367662683415da3464f3c5 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:19 -0300 Subject: [PATCH 06/60] params --- R/distance_to_centroid.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 238f4de9..08df1e1e 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -21,6 +21,14 @@ #' returned. The \code{ties.method} argument is passed to #' \code{data.table::frank}, see details at #' \code{\link[data.table:frank]{?data.table::frank}}. +#' +#' @inheritParams group_pts +#' @param group group column name, generated by \code{group_pts}, default +#' 'group' +#' @param return_rank boolean if rank distance should also be returned, default +#' FALSE +#' @param ties.method see \code{\link[data.table:frank]{?data.table::frank}} +#' stopifnot(length(coords) == 2) From 38a34b8869d961c8efd625419462dc9e6551f95f Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:22 -0300 Subject: [PATCH 07/60] return --- R/distance_to_centroid.R | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 08df1e1e..6255fc26 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -29,6 +29,15 @@ #' FALSE #' @param ties.method see \code{\link[data.table:frank]{?data.table::frank}} #' +#' @return \code{distance_to_centroid} returns the input \code{DT} appended with +#' a \code{distance_centroid} column indicating the distance to group centroid +#' and, optionally, a \code{rank_distance_centroid} column indicating the +#' within group rank distance to group centroid (if \code{return_rank = +#' TRUE}). +#' +#' A message is returned when \code{distance_centroid} and optional +#' \code{rank_distance_centroid} columns already exist in the input \code{DT}, +#' because they will be overwritten. stopifnot(length(coords) == 2) From f4074871973a796c587582c8443da7ddbf93feb9 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:30 -0300 Subject: [PATCH 08/60] export, family, seealso, references --- R/distance_to_centroid.R | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 6255fc26..512e1960 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -38,6 +38,15 @@ #' A message is returned when \code{distance_centroid} and optional #' \code{rank_distance_centroid} columns already exist in the input \code{DT}, #' because they will be overwritten. +#' +#' @export +#' @family Distance functions +#' @seealso [centroid_group], [group_pts] +#' @references +#' See examples of using distance to group centroid: +#' * +#' * +#' * stopifnot(length(coords) == 2) From c7fdb00ea9af197338de7311b4992fbbf5068afa Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:34 -0300 Subject: [PATCH 09/60] example --- R/distance_to_centroid.R | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 512e1960..2ba950bf 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -47,6 +47,33 @@ #' * #' * #' * +#' +#' @examples +#' # Load data.table +#' library(data.table) +#' \dontshow{data.table::setDTthreads(1)} +#' +#' # Read example data +#' DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc")) +#' +#' # Select only individuals A, B, C for this example +#' DT <- DT[ID %in% c('A', 'B', 'C')] +#' +#' # Cast the character column to POSIXct +#' DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] +#' +#' # Temporal grouping +#' group_times(DT, datetime = 'datetime', threshold = '20 minutes') +#' +#' # Spatial grouping with timegroup +#' group_pts(DT, threshold = 5, id = 'ID', +#' coords = c('X', 'Y'), timegroup = 'timegroup') +#' +#' # Calculate group centroid +#' centroid_group(DT, coords = c('X', 'Y'), group = 'group', na.rm = TRUE) +#' +#' # Calculate distance to group centroid +#' distance_to_centroid(DT, coords = c('X', 'Y'), group = 'group', return_rank = TRUE) stopifnot(length(coords) == 2) From 28e8f7bd5e5a94bb0903f91a05112924d524a09a Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:36 -0300 Subject: [PATCH 10/60] args --- R/distance_to_centroid.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 2ba950bf..f8a280ab 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -74,6 +74,12 @@ #' #' # Calculate distance to group centroid #' distance_to_centroid(DT, coords = c('X', 'Y'), group = 'group', return_rank = TRUE) +distance_to_centroid <- function( + DT = NULL, + coords = NULL, + group = 'group', + return_rank = FALSE, + ties.method = NULL) { stopifnot(length(coords) == 2) From b00d64d27189cf8c19523766877ee7498c5067a7 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:38 -0300 Subject: [PATCH 11/60] nse --- R/distance_to_centroid.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index f8a280ab..5fd33f03 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -81,7 +81,8 @@ distance_to_centroid <- function( return_rank = FALSE, ties.method = NULL) { - stopifnot(length(coords) == 2) + # Due to NSE notes in R CMD check + distance_centroid <- rank_distance_centroid <- NULL xcol <- first(coords) ycol <- last(coords) From bcf4925db67b6eb56e229e8d7be1219caeda7a02 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:36:46 -0300 Subject: [PATCH 12/60] checks --- R/distance_to_centroid.R | 55 ++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 5fd33f03..a0c50ea8 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -84,19 +84,58 @@ distance_to_centroid <- function( # Due to NSE notes in R CMD check distance_centroid <- rank_distance_centroid <- NULL + if (is.null(DT)) { + stop('input DT required') + } + + if (length(coords) != 2) { + stop('coords requires a vector of column names for coordinates X and Y') + } + + if (is.null(return_rank)) { + stop('return_rank required') + } + xcol <- first(coords) ycol <- last(coords) - group_xcol <- paste0(pre, xcol) - group_ycol <- paste0(pre, ycol) + pre <- 'centroid_' + centroid_xcol <- paste0(pre, xcol) + centroid_ycol <- paste0(pre, ycol) + centroid_coords <- c(centroid_xcol, centroid_ycol) - stopifnot(xcol %in% colnames(DT)) - stopifnot(ycol %in% colnames(DT)) - stopifnot(group_xcol %in% colnames(DT)) - stopifnot(group_ycol %in% colnames(DT)) - stopifnot(group %in% colnames(DT)) + if (any(!(coords %in% colnames(DT)))) { + stop(paste0( + as.character(paste(setdiff( + coords, + colnames(DT) + ), collapse = ', ')), + ' field(s) provided are not present in input DT' + )) + } + if (any(!(centroid_coords %in% colnames(DT) + ))) { + stop(paste0( + as.character(paste(setdiff( + centroid_coords, + colnames(DT) + ), collapse = ', ')), + ' field(s) provided are not present in input DT, did you run centroid_group?' + )) + } + + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { + stop('coords must be numeric') + } - DT[, dist_group_centroid := + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { + stop('centroid coords must be numeric') + } + + if ('distance_centroid' %in% colnames(DT)) { + message('distance_centroid column will be overwritten by this function') + data.table::set(DT, j = 'distance_centroid', value = NULL) + } sqrt((.SD[[xcol]] - .SD[[group_xcol]])^2 + (.SD[[ycol]] - .SD[[group_ycol]])^2)] From 9d9cec95cee4ac528c963b15a31e4fa5695d9b4a Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:37:01 -0300 Subject: [PATCH 13/60] calc dist, rank --- R/distance_to_centroid.R | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index a0c50ea8..b8eb26e2 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -136,13 +136,23 @@ distance_to_centroid <- function( message('distance_centroid column will be overwritten by this function') data.table::set(DT, j = 'distance_centroid', value = NULL) } + + DT[, distance_centroid := sqrt((.SD[[xcol]] - .SD[[group_xcol]])^2 + (.SD[[ycol]] - .SD[[group_ycol]])^2)] if (return_rank) { - DT[, N_by_group := .N, by = c(group)] - DT[, rank_dist_group_centroid := - data.table::frank(dist_group_centroid), + if (!group %in% colnames(DT)) { + stop('group column not present in input DT, did you run group_pts?') + } + + if ('rank_distance_centroid' %in% colnames(DT)) { + message('rank_distance_centroid column will be overwritten by this function') + data.table::set(DT, j = 'rank_distance_centroid', value = NULL) + } + + DT[, rank_distance_centroid := + data.table::frank(dist_group_centroid, ties.method = ties.method), by = c(group)] } return(DT[]) From f8ff58953ca470a179f2c6aeaaad50ef46f0c3fc Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:39:54 -0300 Subject: [PATCH 14/60] title --- R/direction_to_centroid.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 5d9b995d..18da95ff 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -1,4 +1,4 @@ -#' Calculate absolute bearing to group centroid +#' Direction to group centroid #' #' @param DT expects group_mean columns generated with group_centroid #' @param coords character vector of column names for x, y From aa65fbceabda2e5cc771cee141d59ad539ebdd23 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:39:58 -0300 Subject: [PATCH 15/60] description --- R/direction_to_centroid.R | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 18da95ff..e01c325d 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -1,9 +1,22 @@ #' Direction to group centroid #' -#' @param DT expects group_mean columns generated with group_centroid -#' @param coords character vector of column names for x, y -direction_to_centroid <- function(DT, coords = NULL) { - pre <- 'group_mean_' +#' \code{direction_to_centroid} calculates the direction of each relocation to +#' the centroid of the spatiotemporal group identified by \code{group_pts}. The +#' function accepts a \code{data.table} with relocation data appended with a +#' \code{group} column from \code{group_pts} and centroid columns from +#' \code{centroid_group}. Relocation data should be in two columns representing +#' the X and Y coordinates. +#' +#' The \code{DT} must be a \code{data.table}. If your data is a +#' \code{data.frame}, you can convert it by reference using +#' \code{\link[data.table:setDT]{data.table::setDT}} or by reassigning using +#' \code{\link[data.table:data.table]{data.table::data.table}}. +#' +#' This function expects a \code{group} column present generated with the +#' \code{group_pts} function and centroid coordinate columns generated with the +#' \code{centroid_group} function. The \code{coords} and \code{group} arguments +#' expect the names of columns in \code{DT} which correspond to the X and Y +#' coordinates and group columns. stopifnot(length(coords) == 2) From 5b288c313f32c5c76d92342b4f40b691a50920ed Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:40:01 -0300 Subject: [PATCH 16/60] params --- R/direction_to_centroid.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index e01c325d..fd8fc802 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -17,6 +17,8 @@ #' \code{centroid_group} function. The \code{coords} and \code{group} arguments #' expect the names of columns in \code{DT} which correspond to the X and Y #' coordinates and group columns. +#' +#' @inheritParams group_pts stopifnot(length(coords) == 2) From 4d51239a7d5cef468de69359295ae215b7fbcd6a Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:40:03 -0300 Subject: [PATCH 17/60] returnb --- R/direction_to_centroid.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index fd8fc802..92935eb9 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -19,6 +19,13 @@ #' coordinates and group columns. #' #' @inheritParams group_pts +#' +#' @return \code{direction_to_centroid} returns the input \code{DT} appended +#' with a \code{direction_centroid} column indicating the direction to group +#' centroid. +#' +#' A message is returned when \code{direction_centroid} column already exist +#' in the input \code{DT}, because they will be overwritten. stopifnot(length(coords) == 2) From 230fe18b50147ab4c0c0f8313897ea9f4f921081 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:46:50 -0300 Subject: [PATCH 18/60] reference --- R/direction_to_centroid.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 92935eb9..b430ac31 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -26,6 +26,13 @@ #' #' A message is returned when \code{direction_centroid} column already exist #' in the input \code{DT}, because they will be overwritten. +#' +#' @export +#' @family Distance functions +#' @seealso [centroid_group], [group_pts] +#' @references +#' See example of using direction to group centroid: +#' * stopifnot(length(coords) == 2) From 5da229f51dbc78bc8d9b19980fdf59200f08a881 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:46:55 -0300 Subject: [PATCH 19/60] example --- R/direction_to_centroid.R | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index b430ac31..4dbbbe7e 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -33,6 +33,33 @@ #' @references #' See example of using direction to group centroid: #' * +#' +#' @examples +#' # Load data.table +#' library(data.table) +#' \dontshow{data.table::setDTthreads(1)} +#' +#' # Read example data +#' DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc")) +#' +#' # Select only individuals A, B, C for this example +#' DT <- DT[ID %in% c('A', 'B', 'C')] +#' +#' # Cast the character column to POSIXct +#' DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] +#' +#' # Temporal grouping +#' group_times(DT, datetime = 'datetime', threshold = '20 minutes') +#' +#' # Spatial grouping with timegroup +#' group_pts(DT, threshold = 5, id = 'ID', +#' coords = c('X', 'Y'), timegroup = 'timegroup') +#' +#' # Calculate group centroid +#' centroid_group(DT, coords = c('X', 'Y'), group = 'group', na.rm = TRUE) +#' +#' # Calculate direction to group centroid +#' direction_to_centroid(DT, coords = c('X', 'Y')) stopifnot(length(coords) == 2) From d6a45bec64af5c0313543796f5a16d46f4ddeb9a Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:46:56 -0300 Subject: [PATCH 20/60] args --- R/direction_to_centroid.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 4dbbbe7e..606136f9 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -60,6 +60,9 @@ #' #' # Calculate direction to group centroid #' direction_to_centroid(DT, coords = c('X', 'Y')) +direction_to_centroid <- function( + DT = NULL, + coords = NULL) { stopifnot(length(coords) == 2) From 27d944cf8a0dc0d3fa6e032fa1de0ac11f992d0e Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:47:05 -0300 Subject: [PATCH 21/60] check --- R/direction_to_centroid.R | 54 +++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 606136f9..c0d1e768 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -64,19 +64,57 @@ direction_to_centroid <- function( DT = NULL, coords = NULL) { - stopifnot(length(coords) == 2) + # Due to NSE notes in R CMD check + direction_centroid <- NULL + + if (is.null(DT)) { + stop('input DT required') + } + + if (length(coords) != 2) { + stop('coords requires a vector of column names for coordinates X and Y') + } xcol <- first(coords) ycol <- last(coords) - group_xcol <- paste0(pre, xcol) - group_ycol <- paste0(pre, ycol) + pre <- 'centroid_' + centroid_xcol <- paste0(pre, xcol) + centroid_ycol <- paste0(pre, ycol) + centroid_coords <- c(centroid_xcol, centroid_ycol) + + if (any(!(coords %in% colnames(DT)))) { + stop(paste0( + as.character(paste(setdiff( + coords, + colnames(DT) + ), collapse = ', ')), + ' field(s) provided are not present in input DT' + )) + } + + if (any(!(centroid_coords %in% colnames(DT) + ))) { + stop(paste0( + as.character(paste(setdiff( + centroid_coords, + colnames(DT) + ), collapse = ', ')), + ' field(s) provided are not present in input DT, did you run centroid_group?' + )) + } + + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { + stop('coords must be numeric') + } - stopifnot(xcol %in% colnames(DT)) - stopifnot(ycol %in% colnames(DT)) - stopifnot(group_xcol %in% colnames(DT)) - stopifnot(group_ycol %in% colnames(DT)) + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { + stop('centroid coords must be numeric') + } - DT[, bearing_centroid := fifelse( + if ('direction_centroid' %in% colnames(DT)) { + message('direction_centroid column will be overwritten by this function') + data.table::set(DT, j = 'direction_centroid', value = NULL) + } .SD[[xcol]] == .SD[[group_xcol]] & .SD[[ycol]] == .SD[[group_ycol]], NaN, From ccd85cf31808a88bd6b36a9b4cc4c8036a140c4c Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 15:47:07 -0300 Subject: [PATCH 22/60] cal --- R/direction_to_centroid.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index c0d1e768..fb90a86d 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -115,11 +115,14 @@ direction_to_centroid <- function( message('direction_centroid column will be overwritten by this function') data.table::set(DT, j = 'direction_centroid', value = NULL) } + + DT[, direction_centroid := fifelse( .SD[[xcol]] == .SD[[group_xcol]] & .SD[[ycol]] == .SD[[group_ycol]], NaN, atan2(.SD[[group_ycol]] - .SD[[ycol]], (.SD[[group_xcol]] - .SD[[xcol]])) )] + return(DT[]) } From 938ee8fb5ff0591b3626d0bd09e618214681ceac Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:02:49 -0300 Subject: [PATCH 23/60] fix rm sub ids --- R/direction_to_centroid.R | 3 --- R/distance_to_centroid.R | 3 --- 2 files changed, 6 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index fb90a86d..74daf57c 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -42,9 +42,6 @@ #' # Read example data #' DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc")) #' -#' # Select only individuals A, B, C for this example -#' DT <- DT[ID %in% c('A', 'B', 'C')] -#' #' # Cast the character column to POSIXct #' DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] #' diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index b8eb26e2..3a4de958 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -56,9 +56,6 @@ #' # Read example data #' DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc")) #' -#' # Select only individuals A, B, C for this example -#' DT <- DT[ID %in% c('A', 'B', 'C')] -#' #' # Cast the character column to POSIXct #' DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] #' From d0a700d7d6d05ea309dd83953c92c13c193d32a7 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:03:06 -0300 Subject: [PATCH 24/60] fst test-distance-to-centroid --- tests/testthat/test-distance-to-centroid.R | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/testthat/test-distance-to-centroid.R diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R new file mode 100644 index 00000000..427fb3fa --- /dev/null +++ b/tests/testthat/test-distance-to-centroid.R @@ -0,0 +1,2 @@ +# Test distance_to_centroid +context('test distance_to_centroid') From 1e54b264d5c9ffde70abad969726bf2eae1b04b7 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:06 -0300 Subject: [PATCH 25/60] reorg checks --- R/distance_to_centroid.R | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 3a4de958..afa41fe6 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -110,6 +110,14 @@ distance_to_centroid <- function( )) } + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { + stop('coords must be numeric') + } + + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { + stop('centroid coords must be numeric') + } + if (any(!(centroid_coords %in% colnames(DT) ))) { stop(paste0( @@ -121,13 +129,6 @@ distance_to_centroid <- function( )) } - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { - stop('coords must be numeric') - } - - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { - stop('centroid coords must be numeric') - } if ('distance_centroid' %in% colnames(DT)) { message('distance_centroid column will be overwritten by this function') From e90fcdb4eef257b30a6f7ee37dc2ae2b605b97a8 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:12 -0300 Subject: [PATCH 26/60] fix centroid_ col --- R/distance_to_centroid.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index afa41fe6..8cc1d57b 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -129,15 +129,14 @@ distance_to_centroid <- function( )) } - if ('distance_centroid' %in% colnames(DT)) { message('distance_centroid column will be overwritten by this function') data.table::set(DT, j = 'distance_centroid', value = NULL) } DT[, distance_centroid := - sqrt((.SD[[xcol]] - .SD[[group_xcol]])^2 + - (.SD[[ycol]] - .SD[[group_ycol]])^2)] + sqrt((.SD[[xcol]] - .SD[[centroid_xcol]])^2 + + (.SD[[ycol]] - .SD[[centroid_ycol]])^2)] if (return_rank) { if (!group %in% colnames(DT)) { From 49ab63c0d979045a89d662f3696677c05e1d1870 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:20 -0300 Subject: [PATCH 27/60] check if group is null if rank true --- R/distance_to_centroid.R | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 8cc1d57b..ed7608a6 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -139,6 +139,10 @@ distance_to_centroid <- function( (.SD[[ycol]] - .SD[[centroid_ycol]])^2)] if (return_rank) { + if (is.null(group)) { + stop('group column name required') + } + if (!group %in% colnames(DT)) { stop('group column not present in input DT, did you run group_pts?') } From 805a2dcf2a664d7b57da39749c9ca1f482590d8a Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:34 -0300 Subject: [PATCH 28/60] setup --- tests/testthat/test-distance-to-centroid.R | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 427fb3fa..97e1d7e7 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -1,2 +1,21 @@ # Test distance_to_centroid context('test distance_to_centroid') + +library(spatsoc) + +DT <- fread('../testdata/DT.csv') +id <- 'ID' +datetime <- 'datetime' +timethreshold <- '20 minutes' +threshold <- 50 +coords <- c('X', 'Y') +timegroup <- 'timegroup' +group <- 'group' + +DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] +group_times(DT, datetime = datetime, timethreshold) +group_pts(DT, threshold = threshold, id = id, + coords = coords, timegroup = timegroup) +centroid_group(DT, coords = coords, group = group, na.rm = TRUE) + +clean_DT <- copy(DT) From 2be4d811e503aa4e35ffa60babfa008a66ada3da Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:41 -0300 Subject: [PATCH 29/60] required --- tests/testthat/test-distance-to-centroid.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 97e1d7e7..1d62522b 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -19,3 +19,15 @@ group_pts(DT, threshold = threshold, id = id, centroid_group(DT, coords = coords, group = group, na.rm = TRUE) clean_DT <- copy(DT) + +test_that('DT is required', { + expect_error(distance_to_centroid(DT = NULL)) +}) + +test_that('arguments required, otherwise error detected', { + expect_error(distance_to_centroid(DT, coords = NULL), + 'coords req') + expect_error(distance_to_centroid(DT, coords = coords, group = NULL, + return_rank = TRUE), + 'group column name required') +}) From b09eb284927796618675a5224adfe740311ad8d1 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:46 -0300 Subject: [PATCH 30/60] exist --- tests/testthat/test-distance-to-centroid.R | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 1d62522b..2b863c30 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -31,3 +31,19 @@ test_that('arguments required, otherwise error detected', { return_rank = TRUE), 'group column name required') }) + +test_that('column names must exist in DT', { + expect_error(distance_to_centroid(DT, coords = rep('potato', 2)), + 'potato field') + expect_error(distance_to_centroid(DT, coords = coords, group = 'potato', + return_rank = TRUE), + 'group column') +}) + +test_that('coords are correctly provided or error detected', { + expect_error(distance_to_centroid(DT, coords = c('X', NULL)), + 'coords requires a vector') + expect_error(distance_to_centroid(DT, coords = c('X', 'ID')), + 'coords must be numeric') +}) + From b2a4b9f6a465fd76b3767c8ff750d891c43fda46 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:19:59 -0300 Subject: [PATCH 31/60] message if already present --- tests/testthat/test-distance-to-centroid.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 2b863c30..22ec7c25 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -47,3 +47,10 @@ test_that('coords are correctly provided or error detected', { 'coords must be numeric') }) +test_that('distance_centroid column succesfully detected', { + copyDT <- copy(clean_DT)[, distance_centroid := 1] + expect_message( + distance_to_centroid(copyDT, coords = coords), + 'distance_centroid column will be overwritten' + ) +}) From 235a041cd728062d6cb626ade5c8a103824e8b80 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:20:07 -0300 Subject: [PATCH 32/60] results dims, types --- tests/testthat/test-distance-to-centroid.R | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 22ec7c25..da01c1dc 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -54,3 +54,27 @@ test_that('distance_centroid column succesfully detected', { 'distance_centroid column will be overwritten' ) }) + +test_that('no rows are added to the result DT', { + copyDT <- copy(clean_DT) + + expect_equal(nrow(copyDT), + nrow(distance_to_centroid(copyDT, coords = coords))) +}) + +test_that('one column added to the result DT', { + copyDT <- copy(clean_DT) + + expect_equal(ncol(copyDT) + 1, + ncol(distance_to_centroid(DT, coords = coords))) +}) + +test_that('column added to the result DT is a double', { + expect_type(distance_to_centroid(DT, coords = coords)$distance_centroid, + 'double') +}) + +test_that('returns a data.table', { + expect_s3_class(distance_to_centroid(DT, coords = coords), 'data.table') +}) + From 7485649ebea253a8db7d5e1ffe8fbc0bc7aa6085 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:15 -0300 Subject: [PATCH 33/60] reorg checks --- R/direction_to_centroid.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 74daf57c..31f6e864 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -89,6 +89,14 @@ direction_to_centroid <- function( )) } + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { + stop('coords must be numeric') + } + + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { + stop('centroid coords must be numeric') + } + if (any(!(centroid_coords %in% colnames(DT) ))) { stop(paste0( @@ -100,14 +108,6 @@ direction_to_centroid <- function( )) } - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { - stop('coords must be numeric') - } - - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { - stop('centroid coords must be numeric') - } - if ('direction_centroid' %in% colnames(DT)) { message('direction_centroid column will be overwritten by this function') data.table::set(DT, j = 'direction_centroid', value = NULL) From 4ed13b490325185cecfac6b70a0e091facedf3f5 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:20 -0300 Subject: [PATCH 34/60] fix centroid cols --- R/direction_to_centroid.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 31f6e864..e1d7c129 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -114,11 +114,11 @@ direction_to_centroid <- function( } DT[, direction_centroid := fifelse( - .SD[[xcol]] == .SD[[group_xcol]] & - .SD[[ycol]] == .SD[[group_ycol]], + .SD[[xcol]] == .SD[[centroid_xcol]] & + .SD[[ycol]] == .SD[[centroid_ycol]], NaN, - atan2(.SD[[group_ycol]] - .SD[[ycol]], - (.SD[[group_xcol]] - .SD[[xcol]])) + atan2(.SD[[centroid_ycol]] - .SD[[ycol]], + (.SD[[centroid_xcol]] - .SD[[xcol]])) )] return(DT[]) From 0780edd3003de7b5f7463eeecb212ff19a091fc2 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:29 -0300 Subject: [PATCH 35/60] fst test direction to centroid --- tests/testthat/test-direction-to-centroid.R | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/testthat/test-direction-to-centroid.R diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R new file mode 100644 index 00000000..4f50c8c1 --- /dev/null +++ b/tests/testthat/test-direction-to-centroid.R @@ -0,0 +1,2 @@ +# Test direction_to_centroid +context('test direction_to_centroid') From 0d22e14a71dfc1a5546289ae5cba190aeb7d45e2 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:32 -0300 Subject: [PATCH 36/60] setup --- tests/testthat/test-direction-to-centroid.R | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 4f50c8c1..2ca01d99 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -1,2 +1,21 @@ # Test direction_to_centroid context('test direction_to_centroid') + +library(spatsoc) + +DT <- fread('../testdata/DT.csv') +id <- 'ID' +datetime <- 'datetime' +timethreshold <- '20 minutes' +threshold <- 50 +coords <- c('X', 'Y') +timegroup <- 'timegroup' +group <- 'group' + +DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] +group_times(DT, datetime = datetime, timethreshold) +group_pts(DT, threshold = threshold, id = id, + coords = coords, timegroup = timegroup) +centroid_group(DT, coords = coords, group = group, na.rm = TRUE) + +clean_DT <- copy(DT) From 4153cd9ec4516c3262602f97b7440c5a7a9ba17e Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:39 -0300 Subject: [PATCH 37/60] required --- tests/testthat/test-direction-to-centroid.R | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 2ca01d99..19b07f6f 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -19,3 +19,24 @@ group_pts(DT, threshold = threshold, id = id, centroid_group(DT, coords = coords, group = group, na.rm = TRUE) clean_DT <- copy(DT) + +test_that('DT is required', { + expect_error(direction_to_centroid(DT = NULL)) +}) + +test_that('arguments required, otherwise error detected', { + expect_error(direction_to_centroid(DT, coords = NULL), + 'coords req') +}) + +test_that('column names must exist in DT', { + expect_error(direction_to_centroid(DT, coords = rep('potato', 2)), + 'potato field') +}) + +test_that('coords are correctly provided or error detected', { + expect_error(direction_to_centroid(DT, coords = c('X', NULL)), + 'coords requires a vector') + expect_error(direction_to_centroid(DT, coords = c('X', 'ID')), + 'coords must be numeric') +}) From 6bbf631031791e5cf3dca013a737071ebf1d9eec Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:43 -0300 Subject: [PATCH 38/60] message --- tests/testthat/test-direction-to-centroid.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 19b07f6f..11bae89d 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -40,3 +40,11 @@ test_that('coords are correctly provided or error detected', { expect_error(direction_to_centroid(DT, coords = c('X', 'ID')), 'coords must be numeric') }) + +test_that('direction_centroid column succesfully detected', { + copyDT <- copy(clean_DT)[, direction_centroid := 1] + expect_message( + direction_to_centroid(copyDT, coords = coords), + 'direction_centroid column will be overwritten' + ) +}) From 501f3ccd5ab3afd957e2be1209e803ac6ba1622c Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 16:22:47 -0300 Subject: [PATCH 39/60] returns --- tests/testthat/test-direction-to-centroid.R | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 11bae89d..e8aa1d5b 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -48,3 +48,27 @@ test_that('direction_centroid column succesfully detected', { 'direction_centroid column will be overwritten' ) }) + +test_that('no rows are added to the result DT', { + copyDT <- copy(clean_DT) + + expect_equal(nrow(copyDT), + nrow(direction_to_centroid(copyDT, coords = coords))) +}) + +test_that('one column added to the result DT', { + copyDT <- copy(clean_DT) + + expect_equal(ncol(copyDT) + 1, + ncol(direction_to_centroid(DT, coords = coords))) +}) + +test_that('column added to the result DT is a double', { + expect_type(direction_to_centroid(DT, coords = coords)$direction_centroid, + 'double') +}) + +test_that('returns a data.table', { + expect_s3_class(direction_to_centroid(DT, coords = coords), 'data.table') +}) + From 376eef457dd5b8aa1a077daf6bcdf8ec01d7c2da Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 17:00:54 -0300 Subject: [PATCH 40/60] set units --- R/direction_to_centroid.R | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index e1d7c129..8edd2d7d 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -116,9 +116,12 @@ direction_to_centroid <- function( DT[, direction_centroid := fifelse( .SD[[xcol]] == .SD[[centroid_xcol]] & .SD[[ycol]] == .SD[[centroid_ycol]], - NaN, - atan2(.SD[[centroid_ycol]] - .SD[[ycol]], - (.SD[[centroid_xcol]] - .SD[[xcol]])) + units::as_units(NaN, 'rad'), + units::as_units( + atan2(.SD[[centroid_ycol]] - .SD[[ycol]], + (.SD[[centroid_xcol]] - .SD[[xcol]])), + 'rad' + ) )] return(DT[]) From e637ab7daa5b5d4a90d5d9faffe531936e74db01 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 17:15:12 -0300 Subject: [PATCH 41/60] test units --- tests/testthat/test-direction-to-centroid.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index e8aa1d5b..1d7e1419 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -2,6 +2,7 @@ context('test direction_to_centroid') library(spatsoc) +library(units) DT <- fread('../testdata/DT.csv') id <- 'ID' @@ -63,9 +64,13 @@ test_that('one column added to the result DT', { ncol(direction_to_centroid(DT, coords = coords))) }) -test_that('column added to the result DT is a double', { +test_that('column added to the result DT is a double with units rad', { expect_type(direction_to_centroid(DT, coords = coords)$direction_centroid, 'double') + expect_equal( + units( + direction_to_centroid(DT, coords = coords)$direction_centroid)$numerator, + 'rad') }) test_that('returns a data.table', { From 84fefa23e1564b22eca6e5e87891c584ea09cdf1 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 17:40:37 -0300 Subject: [PATCH 42/60] clarify radians --- R/direction_to_centroid.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 8edd2d7d..3385ca21 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -22,7 +22,7 @@ #' #' @return \code{direction_to_centroid} returns the input \code{DT} appended #' with a \code{direction_centroid} column indicating the direction to group -#' centroid. +#' centroid in radians. #' #' A message is returned when \code{direction_centroid} column already exist #' in the input \code{DT}, because they will be overwritten. From b332c0648dce2cf2a22aad7fe01fde312d0f39eb Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Fri, 4 Oct 2024 17:40:43 -0300 Subject: [PATCH 43/60] man --- NAMESPACE | 2 + man/direction_to_centroid.Rd | 79 +++++++++++++++++++++++++++ man/distance_to_centroid.Rd | 102 +++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 man/direction_to_centroid.Rd create mode 100644 man/distance_to_centroid.Rd diff --git a/NAMESPACE b/NAMESPACE index cc3f44e7..ba4c7247 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,6 +6,8 @@ export(centroid_dyad) export(centroid_fusion) export(centroid_group) export(direction_step) +export(direction_to_centroid) +export(distance_to_centroid) export(dyad_id) export(edge_dist) export(edge_nn) diff --git a/man/direction_to_centroid.Rd b/man/direction_to_centroid.Rd new file mode 100644 index 00000000..d28dca68 --- /dev/null +++ b/man/direction_to_centroid.Rd @@ -0,0 +1,79 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/direction_to_centroid.R +\name{direction_to_centroid} +\alias{direction_to_centroid} +\title{Direction to group centroid} +\usage{ +direction_to_centroid(DT = NULL, coords = NULL) +} +\arguments{ +\item{DT}{input data.table} + +\item{coords}{Character vector of X coordinate and Y coordinate column names. +Note: the order is assumed X followed by Y column names.} +} +\value{ +\code{direction_to_centroid} returns the input \code{DT} appended +with a \code{direction_centroid} column indicating the direction to group +centroid in radians. + +A message is returned when \code{direction_centroid} column already exist +in the input \code{DT}, because they will be overwritten. +} +\description{ +\code{direction_to_centroid} calculates the direction of each relocation to +the centroid of the spatiotemporal group identified by \code{group_pts}. The +function accepts a \code{data.table} with relocation data appended with a +\code{group} column from \code{group_pts} and centroid columns from +\code{centroid_group}. Relocation data should be in two columns representing +the X and Y coordinates. +} +\details{ +The \code{DT} must be a \code{data.table}. If your data is a +\code{data.frame}, you can convert it by reference using +\code{\link[data.table:setDT]{data.table::setDT}} or by reassigning using +\code{\link[data.table:data.table]{data.table::data.table}}. + +This function expects a \code{group} column present generated with the +\code{group_pts} function and centroid coordinate columns generated with the +\code{centroid_group} function. The \code{coords} and \code{group} arguments +expect the names of columns in \code{DT} which correspond to the X and Y +coordinates and group columns. +} +\examples{ +# Load data.table +library(data.table) +\dontshow{data.table::setDTthreads(1)} + +# Read example data +DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc")) + +# Cast the character column to POSIXct +DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] + +# Temporal grouping +group_times(DT, datetime = 'datetime', threshold = '20 minutes') + +# Spatial grouping with timegroup +group_pts(DT, threshold = 5, id = 'ID', + coords = c('X', 'Y'), timegroup = 'timegroup') + +# Calculate group centroid +centroid_group(DT, coords = c('X', 'Y'), group = 'group', na.rm = TRUE) + +# Calculate direction to group centroid +direction_to_centroid(DT, coords = c('X', 'Y')) +} +\references{ +See example of using direction to group centroid: +\itemize{ +\item \url{https://doi.org/10.1016/j.cub.2017.08.004} +} +} +\seealso{ +\link{centroid_group}, \link{group_pts} + +Other Distance functions: +\code{\link{distance_to_centroid}()} +} +\concept{Distance functions} diff --git a/man/distance_to_centroid.Rd b/man/distance_to_centroid.Rd new file mode 100644 index 00000000..fa7a43fe --- /dev/null +++ b/man/distance_to_centroid.Rd @@ -0,0 +1,102 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/distance_to_centroid.R +\name{distance_to_centroid} +\alias{distance_to_centroid} +\title{Distance to group centroid} +\usage{ +distance_to_centroid( + DT = NULL, + coords = NULL, + group = "group", + return_rank = FALSE, + ties.method = NULL +) +} +\arguments{ +\item{DT}{input data.table} + +\item{coords}{Character vector of X coordinate and Y coordinate column names. +Note: the order is assumed X followed by Y column names.} + +\item{group}{group column name, generated by \code{group_pts}, default +'group'} + +\item{return_rank}{boolean if rank distance should also be returned, default +FALSE} + +\item{ties.method}{see \code{\link[data.table:frank]{?data.table::frank}}} +} +\value{ +\code{distance_to_centroid} returns the input \code{DT} appended with +a \code{distance_centroid} column indicating the distance to group centroid +and, optionally, a \code{rank_distance_centroid} column indicating the +within group rank distance to group centroid (if \code{return_rank = + TRUE}). + +A message is returned when \code{distance_centroid} and optional +\code{rank_distance_centroid} columns already exist in the input \code{DT}, +because they will be overwritten. +} +\description{ +\code{distance_to_centroid} calculates the distance of each relocation to the +centroid of the spatiotemporal group identified by \code{group_pts}. The +function accepts a \code{data.table} with relocation data appended with a +\code{group} column from \code{group_pts} and centroid columns from +\code{centroid_group}. Relocation data should be in two columns representing +the X and Y coordinates. +} +\details{ +The \code{DT} must be a \code{data.table}. If your data is a +\code{data.frame}, you can convert it by reference using +\code{\link[data.table:setDT]{data.table::setDT}} or by reassigning using +\code{\link[data.table:data.table]{data.table::data.table}}. + +This function expects a \code{group} column present generated with the +\code{group_pts} function and centroid coordinate columns generated with the +\code{centroid_group} function. The \code{coords} and \code{group} arguments +expect the names of columns in \code{DT} which correspond to the X and Y +coordinates and group columns. The \code{return_rank} argument controls if +the rank of each individual's distance to the group centroid is also +returned. The \code{ties.method} argument is passed to +\code{data.table::frank}, see details at +\code{\link[data.table:frank]{?data.table::frank}}. +} +\examples{ +# Load data.table +library(data.table) +\dontshow{data.table::setDTthreads(1)} + +# Read example data +DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc")) + +# Cast the character column to POSIXct +DT[, datetime := as.POSIXct(datetime, tz = 'UTC')] + +# Temporal grouping +group_times(DT, datetime = 'datetime', threshold = '20 minutes') + +# Spatial grouping with timegroup +group_pts(DT, threshold = 5, id = 'ID', + coords = c('X', 'Y'), timegroup = 'timegroup') + +# Calculate group centroid +centroid_group(DT, coords = c('X', 'Y'), group = 'group', na.rm = TRUE) + +# Calculate distance to group centroid +distance_to_centroid(DT, coords = c('X', 'Y'), group = 'group', return_rank = TRUE) +} +\references{ +See examples of using distance to group centroid: +\itemize{ +\item \url{https://doi.org/10.1016/j.anbehav.2021.08.004} +\item \url{https://doi.org/10.1111/eth.12336} +\item \url{https://doi.org/10.1007/s13364-018-0400-2} +} +} +\seealso{ +\link{centroid_group}, \link{group_pts} + +Other Distance functions: +\code{\link{direction_to_centroid}()} +} +\concept{Distance functions} From ac8edd51469cf128c6c8ba676099111039e120a9 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 09:35:26 -0300 Subject: [PATCH 44/60] fix quote rad --- R/direction_step.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/direction_step.R b/R/direction_step.R index 6aaee57b..ab2f6785 100644 --- a/R/direction_step.R +++ b/R/direction_step.R @@ -123,7 +123,7 @@ direction_step <- function( lwgeom::st_geod_azimuth( sf::st_as_sf(.SD, coords = coords, crs = projection)) ), - units::set_units(NA, rad), + units::set_units(NA, 'rad'), by = c(id, splitBy)] } else if (!sf::st_is_longlat(projection)) { DT[, direction := c( @@ -132,7 +132,7 @@ direction_step <- function( sf::st_as_sf(.SD, coords = coords, crs = projection), crs = 4326) ), - units::set_units(NA, rad)), + units::set_units(NA, 'rad')), by = c(id, splitBy)] } else { stop('projection not recognized, please see sf::st_crs') From 12a7b5b3dfed6b3c056dfb2edd3bf147504cefb3 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 09:35:30 -0300 Subject: [PATCH 45/60] fix colname --- R/distance_to_centroid.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index ed7608a6..8e88a5ee 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -153,7 +153,7 @@ distance_to_centroid <- function( } DT[, rank_distance_centroid := - data.table::frank(dist_group_centroid, ties.method = ties.method), + data.table::frank(distance_centroid, ties.method = ties.method), by = c(group)] } return(DT[]) From 2c3dd37d5db477323f30fe5df5520b08fd2bccc2 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 10:03:10 -0300 Subject: [PATCH 46/60] set limits between 0 and 2 pi --- R/direction_to_centroid.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 3385ca21..093a756e 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -123,6 +123,8 @@ direction_to_centroid <- function( 'rad' ) )] + DT[direction_centroid < units::as_units(0, 'rad'), + direction_centroid := direction_centroid + units::as_units(2 * pi, 'rad')] return(DT[]) } From 8aecfd1622e327b8382c35d4dbb81573d40130a9 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 10:52:18 -0300 Subject: [PATCH 47/60] clarify range --- R/direction_to_centroid.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 093a756e..4a920216 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -22,7 +22,8 @@ #' #' @return \code{direction_to_centroid} returns the input \code{DT} appended #' with a \code{direction_centroid} column indicating the direction to group -#' centroid in radians. +#' centroid in radians. The direction is measured in radians in the range +#' of 0 to 2 * pi from the positive x-axis. #' #' A message is returned when \code{direction_centroid} column already exist #' in the input \code{DT}, because they will be overwritten. From 0a622acd467bb466bdb90de4ec44f4395331c854 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 10:58:45 -0300 Subject: [PATCH 48/60] fix long lines --- R/direction_to_centroid.R | 5 +++-- R/distance_to_centroid.R | 13 ++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 4a920216..818b4e3a 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -94,7 +94,8 @@ direction_to_centroid <- function( stop('coords must be numeric') } - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), + .SDcols = c(centroid_coords)]))) { stop('centroid coords must be numeric') } @@ -105,7 +106,7 @@ direction_to_centroid <- function( centroid_coords, colnames(DT) ), collapse = ', ')), - ' field(s) provided are not present in input DT, did you run centroid_group?' + ' field(s) provided are not present in DT, did you run centroid_group?' )) } diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 8e88a5ee..70b436e6 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -70,7 +70,12 @@ #' centroid_group(DT, coords = c('X', 'Y'), group = 'group', na.rm = TRUE) #' #' # Calculate distance to group centroid -#' distance_to_centroid(DT, coords = c('X', 'Y'), group = 'group', return_rank = TRUE) +#' distance_to_centroid( +#' DT, +#' coords = c('X', 'Y'), +#' group = 'group', +#' return_rank = TRUE +#' ) distance_to_centroid <- function( DT = NULL, coords = NULL, @@ -125,7 +130,7 @@ distance_to_centroid <- function( centroid_coords, colnames(DT) ), collapse = ', ')), - ' field(s) provided are not present in input DT, did you run centroid_group?' + ' field(s) provided are not present in DT, did you run centroid_group?' )) } @@ -148,7 +153,9 @@ distance_to_centroid <- function( } if ('rank_distance_centroid' %in% colnames(DT)) { - message('rank_distance_centroid column will be overwritten by this function') + message( + 'rank_distance_centroid column will be overwritten by this function' + ) data.table::set(DT, j = 'rank_distance_centroid', value = NULL) } From 800d019999b70b04ddef335e84440a6b9e71e88e Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 10:59:57 -0300 Subject: [PATCH 49/60] test centroid check --- tests/testthat/test-direction-to-centroid.R | 4 ++++ tests/testthat/test-distance-to-centroid.R | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 1d7e1419..3ef4e9b5 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -33,6 +33,10 @@ test_that('arguments required, otherwise error detected', { test_that('column names must exist in DT', { expect_error(direction_to_centroid(DT, coords = rep('potato', 2)), 'potato field') + copy_DT <- copy(DT) + setnames(copy_DT, 'centroid_X', 'potato_X') + expect_error(direction_to_centroid(copy_DT, coords = coords), + 'centroid_') }) test_that('coords are correctly provided or error detected', { diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index da01c1dc..afdf6fa3 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -38,6 +38,10 @@ test_that('column names must exist in DT', { expect_error(distance_to_centroid(DT, coords = coords, group = 'potato', return_rank = TRUE), 'group column') + copy_DT <- copy(DT) + setnames(copy_DT, 'centroid_X', 'potato_X') + expect_error(distance_to_centroid(copy_DT, coords = coords), + 'centroid_') }) test_that('coords are correctly provided or error detected', { From 668600c63399904e6d2edeb99d3d2f1febee49af Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:00:03 -0300 Subject: [PATCH 50/60] test coord numeric --- tests/testthat/test-direction-to-centroid.R | 3 +++ tests/testthat/test-distance-to-centroid.R | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 3ef4e9b5..77f43e86 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -44,6 +44,9 @@ test_that('coords are correctly provided or error detected', { 'coords requires a vector') expect_error(direction_to_centroid(DT, coords = c('X', 'ID')), 'coords must be numeric') + copy_DT <- copy(DT)[, X := as.character(X)] + expect_error(direction_to_centroid(copy_DT, coords = coords), + 'coords must be numeric') }) test_that('direction_centroid column succesfully detected', { diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index afdf6fa3..92590bb3 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -47,7 +47,8 @@ test_that('column names must exist in DT', { test_that('coords are correctly provided or error detected', { expect_error(distance_to_centroid(DT, coords = c('X', NULL)), 'coords requires a vector') - expect_error(distance_to_centroid(DT, coords = c('X', 'ID')), + copy_DT <- copy(DT)[, X := as.character(X)] + expect_error(distance_to_centroid(copy_DT, coords = coords), 'coords must be numeric') }) From ce89dd0f3dc8d49c6fc492bb0956790af20dbe79 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:18:35 -0300 Subject: [PATCH 51/60] clarify planar --- R/direction_to_centroid.R | 4 ++-- R/distance_to_centroid.R | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index 818b4e3a..f4cf760b 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -4,8 +4,8 @@ #' the centroid of the spatiotemporal group identified by \code{group_pts}. The #' function accepts a \code{data.table} with relocation data appended with a #' \code{group} column from \code{group_pts} and centroid columns from -#' \code{centroid_group}. Relocation data should be in two columns representing -#' the X and Y coordinates. +#' \code{centroid_group}. Relocation data should be in planar coordinates +#' provided in two columns representing the X and Y coordinates. #' #' The \code{DT} must be a \code{data.table}. If your data is a #' \code{data.frame}, you can convert it by reference using diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 70b436e6..3ae654bc 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -4,8 +4,8 @@ #' centroid of the spatiotemporal group identified by \code{group_pts}. The #' function accepts a \code{data.table} with relocation data appended with a #' \code{group} column from \code{group_pts} and centroid columns from -#' \code{centroid_group}. Relocation data should be in two columns representing -#' the X and Y coordinates. +#' \code{centroid_group}. Relocation data should be in planar coordinates +#' provided in two columns representing the X and Y coordinates. #' #' The \code{DT} must be a \code{data.table}. If your data is a #' \code{data.frame}, you can convert it by reference using From 72f90c49e765df62fc2590001c0840e99a7cb45b Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:18:42 -0300 Subject: [PATCH 52/60] reorg checks --- R/direction_to_centroid.R | 10 +++++----- R/distance_to_centroid.R | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R index f4cf760b..2b45d9d9 100644 --- a/R/direction_to_centroid.R +++ b/R/direction_to_centroid.R @@ -94,11 +94,6 @@ direction_to_centroid <- function( stop('coords must be numeric') } - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), - .SDcols = c(centroid_coords)]))) { - stop('centroid coords must be numeric') - } - if (any(!(centroid_coords %in% colnames(DT) ))) { stop(paste0( @@ -110,6 +105,11 @@ direction_to_centroid <- function( )) } + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), + .SDcols = c(centroid_coords)]))) { + stop('centroid coords must be numeric') + } + if ('direction_centroid' %in% colnames(DT)) { message('direction_centroid column will be overwritten by this function') data.table::set(DT, j = 'direction_centroid', value = NULL) diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R index 3ae654bc..b79fa93e 100644 --- a/R/distance_to_centroid.R +++ b/R/distance_to_centroid.R @@ -119,10 +119,6 @@ distance_to_centroid <- function( stop('coords must be numeric') } - if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { - stop('centroid coords must be numeric') - } - if (any(!(centroid_coords %in% colnames(DT) ))) { stop(paste0( @@ -134,6 +130,10 @@ distance_to_centroid <- function( )) } + if (any(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(centroid_coords)]))) { + stop('centroid coords must be numeric') + } + if ('distance_centroid' %in% colnames(DT)) { message('distance_centroid column will be overwritten by this function') data.table::set(DT, j = 'distance_centroid', value = NULL) From 168faab09c96852b356cfd70bfcee847386a9ea1 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:01 -0300 Subject: [PATCH 53/60] test fix expected error --- tests/testthat/test-direction-to-centroid.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 77f43e86..28b0637d 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -33,10 +33,10 @@ test_that('arguments required, otherwise error detected', { test_that('column names must exist in DT', { expect_error(direction_to_centroid(DT, coords = rep('potato', 2)), 'potato field') - copy_DT <- copy(DT) + copy_DT <- copy(clean_DT) setnames(copy_DT, 'centroid_X', 'potato_X') expect_error(direction_to_centroid(copy_DT, coords = coords), - 'centroid_') + 'did you run centroid_group') }) test_that('coords are correctly provided or error detected', { From 1fc0848a22fd41a0b6c85a1dff08cb4766c973a1 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:11 -0300 Subject: [PATCH 54/60] test numeric centroid coords --- tests/testthat/test-direction-to-centroid.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index 28b0637d..d1095baf 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -44,9 +44,12 @@ test_that('coords are correctly provided or error detected', { 'coords requires a vector') expect_error(direction_to_centroid(DT, coords = c('X', 'ID')), 'coords must be numeric') - copy_DT <- copy(DT)[, X := as.character(X)] + copy_DT <- copy(clean_DT)[, X := as.character(X)] expect_error(direction_to_centroid(copy_DT, coords = coords), 'coords must be numeric') + copy_DT <- copy(clean_DT)[, centroid_X := as.character(centroid_X)] + expect_error(direction_to_centroid(copy_DT, coords = coords), + 'centroid coords must be numeric') }) test_that('direction_centroid column succesfully detected', { From 2b09fb14de63a3fa54e8c07b0181335a5b5e51f8 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:21 -0300 Subject: [PATCH 55/60] tidy --- tests/testthat/test-direction-to-centroid.R | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R index d1095baf..3fa35878 100644 --- a/tests/testthat/test-direction-to-centroid.R +++ b/tests/testthat/test-direction-to-centroid.R @@ -53,24 +53,24 @@ test_that('coords are correctly provided or error detected', { }) test_that('direction_centroid column succesfully detected', { - copyDT <- copy(clean_DT)[, direction_centroid := 1] + copy_DT <- copy(clean_DT)[, direction_centroid := 1] expect_message( - direction_to_centroid(copyDT, coords = coords), + direction_to_centroid(copy_DT, coords = coords), 'direction_centroid column will be overwritten' ) }) test_that('no rows are added to the result DT', { - copyDT <- copy(clean_DT) + copy_DT <- copy(clean_DT) - expect_equal(nrow(copyDT), - nrow(direction_to_centroid(copyDT, coords = coords))) + expect_equal(nrow(copy_DT), + nrow(direction_to_centroid(copy_DT, coords = coords))) }) test_that('one column added to the result DT', { - copyDT <- copy(clean_DT) + copy_DT <- copy(clean_DT) - expect_equal(ncol(copyDT) + 1, + expect_equal(ncol(copy_DT) + 1, ncol(direction_to_centroid(DT, coords = coords))) }) From bd9acda84729091c2620632f07d65d3ef7913f6e Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:28 -0300 Subject: [PATCH 56/60] test return rank required --- tests/testthat/test-distance-to-centroid.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 92590bb3..9780c616 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -30,6 +30,9 @@ test_that('arguments required, otherwise error detected', { expect_error(distance_to_centroid(DT, coords = coords, group = NULL, return_rank = TRUE), 'group column name required') + expect_error(distance_to_centroid(DT, coords = coords, group = group, + return_rank = NULL), + 'return_rank') }) test_that('column names must exist in DT', { From 00dd872a59fd84c6de359a5af95aaaa31ee93a5d Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:31 -0300 Subject: [PATCH 57/60] fix msg --- tests/testthat/test-distance-to-centroid.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 9780c616..57475c24 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -44,7 +44,7 @@ test_that('column names must exist in DT', { copy_DT <- copy(DT) setnames(copy_DT, 'centroid_X', 'potato_X') expect_error(distance_to_centroid(copy_DT, coords = coords), - 'centroid_') + 'did you run centroid_group?') }) test_that('coords are correctly provided or error detected', { From 1994a27c6e4ac55b7cd1f3ce61858253d2af93a7 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:38 -0300 Subject: [PATCH 58/60] test centroid coords numeric --- tests/testthat/test-distance-to-centroid.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 57475c24..792d05e2 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -53,6 +53,9 @@ test_that('coords are correctly provided or error detected', { copy_DT <- copy(DT)[, X := as.character(X)] expect_error(distance_to_centroid(copy_DT, coords = coords), 'coords must be numeric') + copy_DT <- copy(DT)[, centroid_X := as.character(centroid_X)] + expect_error(direction_to_centroid(copy_DT, coords = coords), + 'centroid coords must be numeric') }) test_that('distance_centroid column succesfully detected', { From 1276ec68d9bcfe41d7e72b8fee81a2ffcc215aed Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:19:46 -0300 Subject: [PATCH 59/60] test msg overwrite return rank --- tests/testthat/test-distance-to-centroid.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R index 792d05e2..847a73a6 100644 --- a/tests/testthat/test-distance-to-centroid.R +++ b/tests/testthat/test-distance-to-centroid.R @@ -89,3 +89,11 @@ test_that('returns a data.table', { expect_s3_class(distance_to_centroid(DT, coords = coords), 'data.table') }) +test_that('message if overwritting rank_distance_centroid', { + copy_DT <- copy(clean_DT) + copy_DT[, rank_distance_centroid := 'potato'] + + expect_message(distance_to_centroid(copy_DT, coords = coords, group = group, + return_rank = TRUE), + 'rank_distance_centroid') +}) From 57362652b8262c0b4923c2e1fbe687f2a8bbcd73 Mon Sep 17 00:00:00 2001 From: "Alec L. Robitaille" Date: Mon, 7 Oct 2024 11:20:20 -0300 Subject: [PATCH 60/60] man --- man/direction_to_centroid.Rd | 7 ++++--- man/distance_to_centroid.Rd | 11 ++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/man/direction_to_centroid.Rd b/man/direction_to_centroid.Rd index d28dca68..e90c05eb 100644 --- a/man/direction_to_centroid.Rd +++ b/man/direction_to_centroid.Rd @@ -15,7 +15,8 @@ Note: the order is assumed X followed by Y column names.} \value{ \code{direction_to_centroid} returns the input \code{DT} appended with a \code{direction_centroid} column indicating the direction to group -centroid in radians. +centroid in radians. The direction is measured in radians in the range +of 0 to 2 * pi from the positive x-axis. A message is returned when \code{direction_centroid} column already exist in the input \code{DT}, because they will be overwritten. @@ -25,8 +26,8 @@ in the input \code{DT}, because they will be overwritten. the centroid of the spatiotemporal group identified by \code{group_pts}. The function accepts a \code{data.table} with relocation data appended with a \code{group} column from \code{group_pts} and centroid columns from -\code{centroid_group}. Relocation data should be in two columns representing -the X and Y coordinates. +\code{centroid_group}. Relocation data should be in planar coordinates +provided in two columns representing the X and Y coordinates. } \details{ The \code{DT} must be a \code{data.table}. If your data is a diff --git a/man/distance_to_centroid.Rd b/man/distance_to_centroid.Rd index fa7a43fe..3b8bcf97 100644 --- a/man/distance_to_centroid.Rd +++ b/man/distance_to_centroid.Rd @@ -42,8 +42,8 @@ because they will be overwritten. centroid of the spatiotemporal group identified by \code{group_pts}. The function accepts a \code{data.table} with relocation data appended with a \code{group} column from \code{group_pts} and centroid columns from -\code{centroid_group}. Relocation data should be in two columns representing -the X and Y coordinates. +\code{centroid_group}. Relocation data should be in planar coordinates +provided in two columns representing the X and Y coordinates. } \details{ The \code{DT} must be a \code{data.table}. If your data is a @@ -83,7 +83,12 @@ group_pts(DT, threshold = 5, id = 'ID', centroid_group(DT, coords = c('X', 'Y'), group = 'group', na.rm = TRUE) # Calculate distance to group centroid -distance_to_centroid(DT, coords = c('X', 'Y'), group = 'group', return_rank = TRUE) +distance_to_centroid( + DT, + coords = c('X', 'Y'), + group = 'group', + return_rank = TRUE +) } \references{ See examples of using distance to group centroid: