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/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') diff --git a/R/direction_to_centroid.R b/R/direction_to_centroid.R new file mode 100644 index 00000000..2b45d9d9 --- /dev/null +++ b/R/direction_to_centroid.R @@ -0,0 +1,132 @@ +#' Direction to group centroid +#' +#' \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 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 +#' \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. +#' +#' @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 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. +#' +#' @export +#' @family Distance functions +#' @seealso [centroid_group], [group_pts] +#' @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")) +#' +#' # 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')) +direction_to_centroid <- function( + DT = NULL, + coords = NULL) { + + # 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) + 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(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { + stop('coords must be numeric') + } + + 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 DT, did you run centroid_group?' + )) + } + + 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) + } + + DT[, direction_centroid := fifelse( + .SD[[xcol]] == .SD[[centroid_xcol]] & + .SD[[ycol]] == .SD[[centroid_ycol]], + units::as_units(NaN, 'rad'), + units::as_units( + atan2(.SD[[centroid_ycol]] - .SD[[ycol]], + (.SD[[centroid_xcol]] - .SD[[xcol]])), + 'rad' + ) + )] + DT[direction_centroid < units::as_units(0, 'rad'), + direction_centroid := direction_centroid + units::as_units(2 * pi, 'rad')] + + return(DT[]) +} diff --git a/R/distance_to_centroid.R b/R/distance_to_centroid.R new file mode 100644 index 00000000..b79fa93e --- /dev/null +++ b/R/distance_to_centroid.R @@ -0,0 +1,167 @@ +#' Distance to group centroid +#' +#' \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 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 +#' \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}}. +#' +#' @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}} +#' +#' @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. +#' +#' @export +#' @family Distance functions +#' @seealso [centroid_group], [group_pts] +#' @references +#' See examples of using distance 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")) +#' +#' # 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 +#' ) +distance_to_centroid <- function( + DT = NULL, + coords = NULL, + group = 'group', + return_rank = FALSE, + ties.method = NULL) { + + # 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) + 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(!(DT[, vapply(.SD, is.numeric, TRUE), .SDcols = c(coords)]))) { + stop('coords must be numeric') + } + + 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 DT, did you run centroid_group?' + )) + } + + 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) + } + + DT[, distance_centroid := + sqrt((.SD[[xcol]] - .SD[[centroid_xcol]])^2 + + (.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?') + } + + 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(distance_centroid, ties.method = ties.method), + by = c(group)] + } + return(DT[]) +} diff --git a/man/direction_to_centroid.Rd b/man/direction_to_centroid.Rd new file mode 100644 index 00000000..e90c05eb --- /dev/null +++ b/man/direction_to_centroid.Rd @@ -0,0 +1,80 @@ +% 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. 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. +} +\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 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 +\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..3b8bcf97 --- /dev/null +++ b/man/distance_to_centroid.Rd @@ -0,0 +1,107 @@ +% 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 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 +\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} diff --git a/tests/testthat/test-direction-to-centroid.R b/tests/testthat/test-direction-to-centroid.R new file mode 100644 index 00000000..3fa35878 --- /dev/null +++ b/tests/testthat/test-direction-to-centroid.R @@ -0,0 +1,89 @@ +# Test direction_to_centroid +context('test direction_to_centroid') + +library(spatsoc) +library(units) + +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) + +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') + copy_DT <- copy(clean_DT) + setnames(copy_DT, 'centroid_X', 'potato_X') + expect_error(direction_to_centroid(copy_DT, coords = coords), + 'did you run centroid_group') +}) + +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') + 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', { + copy_DT <- copy(clean_DT)[, direction_centroid := 1] + expect_message( + direction_to_centroid(copy_DT, coords = coords), + 'direction_centroid column will be overwritten' + ) +}) + +test_that('no rows are added to the result DT', { + copy_DT <- copy(clean_DT) + + expect_equal(nrow(copy_DT), + nrow(direction_to_centroid(copy_DT, coords = coords))) +}) + +test_that('one column added to the result DT', { + copy_DT <- copy(clean_DT) + + expect_equal(ncol(copy_DT) + 1, + ncol(direction_to_centroid(DT, coords = coords))) +}) + +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', { + expect_s3_class(direction_to_centroid(DT, coords = coords), 'data.table') +}) + diff --git a/tests/testthat/test-distance-to-centroid.R b/tests/testthat/test-distance-to-centroid.R new file mode 100644 index 00000000..847a73a6 --- /dev/null +++ b/tests/testthat/test-distance-to-centroid.R @@ -0,0 +1,99 @@ +# 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) + +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') + expect_error(distance_to_centroid(DT, coords = coords, group = group, + return_rank = NULL), + 'return_rank') +}) + +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') + copy_DT <- copy(DT) + setnames(copy_DT, 'centroid_X', 'potato_X') + expect_error(distance_to_centroid(copy_DT, coords = coords), + 'did you run centroid_group?') +}) + +test_that('coords are correctly provided or error detected', { + expect_error(distance_to_centroid(DT, coords = c('X', NULL)), + 'coords requires a vector') + 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', { + copyDT <- copy(clean_DT)[, distance_centroid := 1] + expect_message( + distance_to_centroid(copyDT, coords = coords), + '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') +}) + +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') +})