-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Mikkel Roald-Arbøl
committed
Sep 15, 2024
1 parent
43320c9
commit 0d56e80
Showing
61 changed files
with
20,621 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,83 @@ | ||
#' Calculate summary statistics | ||
#' | ||
#' @description | ||
#' `r lifecycle::badge('experimental')` | ||
#' | ||
#' Calculate summary statistics for tracks | ||
#' | ||
#' @param data A kinematics data frame | ||
#' @param threshold_velocity Choose which observations to use based on the velocity. A number, "auto" or "none". Can take a number (e.g. estimated from histograms) or "auto". "auto" fits a density function to the velocities and tries to identify a local minimum between the first and second local maxima, and uses that as the threshold. "none" keeps all observations. | ||
#' | ||
#' @param measures Measures of central tendency and dispersion. Options are `median_mad` (default) and `mean_sd`. See description for more information. | ||
#' @param straightness Which method to calculate path straightness. Choose between "A" (default), "B", "C"... or a combination (e.g. "c("A","B")"). See description for details about the different calculations. | ||
#' @return An data frame data frame with kinematics calculated | ||
#' @export | ||
#' @import dplyr | ||
#' @import circular | ||
#' @importFrom collapse fmean fmedian fsd | ||
#' @importFrom rlang := | ||
#' @importFrom rlang .data | ||
#' | ||
calculate_statistics <- function( | ||
data, | ||
threshold_velocity | ||
measures = "median_mad", | ||
straightness = c("A", "B", "C", "D") | ||
) { | ||
# Make some tests to ensure that `calculate_kinematics` has been run first | ||
|
||
# Make sure to remove observations with almost no movement (figure out a robust method for this) | ||
validate_statistics() | ||
|
||
# Calculate translational and rotational separately (maybe?) and gather at the end | ||
data <- data |> | ||
dplyr::summarise() | ||
|
||
# dplyr::mutate(distance = sqrt(.data$dx^2 + .data$dy^2), | ||
# v_translation = .data$distance * sampling_rate, | ||
# direction = atan2(.data$dx, .data$dy), | ||
# direction = if_else(.data$dy == 0 | .data$dy == 0, NA, direction), | ||
# direction = if_else(.data$direction < 0, .data$direction + 2*pi, .data$direction), # Keep direction between 0 and 2*pi | ||
# direction = zoo::na.locf(.data$direction, na.rm = FALSE), | ||
# rotation = direction - lag(direction), | ||
# # rotation = dplyr::if_else(abs(.data$dx) > 1 & abs(.data$dy) > 1, | ||
# # abs(dplyr::lag(.data$direction) - .data$direction), | ||
# # 0), | ||
# # rotation = dplyr::if_else(.data$rotation > pi, 2*pi - .data$rotation, .data$rotation), | ||
# v_rotation = .data$rotation * sampling_rate, | ||
# ) | ||
totals <- data |> | ||
dplyr::summarise(across(c(.data$distance, .data$rotation), ~ collapse::fsum(abs(.x)), .names = "total_{.col}"), | ||
across(c(.data$x, .data$y), ~ dplyr::last(.x, na_rm = TRUE), .names = "last_{.col}"), | ||
.by = .data$uid) | ||
|
||
totals <- totals |> | ||
calculate_straightness(straightness) | ||
# dplyr::mutate("straightness_{{ A }} = calculate_straightness(.data$last_x, .data$last_y, .data$total_distance, method = straightness)) | ||
|
||
|
||
if (measures == "median_mad"){ | ||
data <- data |> | ||
dplyr::summarise(across(c(.data$direction), ~ collapse::fmean(circular::circular(.x, modulo = "2pi")), .names = "median_{.col}"), | ||
across(c(.data$direction), ~ calculate_circular_mad(circular::circular(.x, modulo = "2pi")), .names = "mad_{.col}"), | ||
across(c(.data$v_translation, .data$a_translation, .data$v_rotation, .data$a_rotation), ~ collapse::fmedian(abs(.x)), .names = "median_{.col}"), | ||
across(c(.data$v_translation, .data$a_translation, .data$v_rotation, .data$a_rotation), ~ stats::mad(abs(.x), na.rm = TRUE), .names = "mad_{.col}"), | ||
.by = .data$uid | ||
) |> | ||
left_join(totals) |> | ||
select(-c(last_x, last_y)) |> | ||
suppressMessages() | ||
|
||
} else if (measures == "mean_sd"){ | ||
data <- data |> | ||
dplyr::summarise(across(c(.data$direction), ~ collapse::fmean(circular::circular(.x)), .names = "mean_{.col}"), | ||
across(c(.data$direction), ~ circular::sd(circular::circular(.x)), .names = "sd_{.col}"), | ||
across(c(.data$v_translation, .data$a_translation, .data$v_rotation, .data$a_rotation), ~ collapse::fmean(abs(.x)), .names = "mean_{.col}"), | ||
across(c(.data$v_translation, .data$a_translation, .data$v_rotation, .data$a_rotation), ~ collapse::fsd(abs(.x)), .names = "sd_{.col}"), | ||
.by = .data$uid | ||
) |> | ||
left_join(totals) |> | ||
select(-c(last_x, last_y)) |> | ||
suppressMessages() | ||
} | ||
|
||
return(data) | ||
} | ||
|
||
#' Calculate circular Median Absolute Deviation (MAD) | ||
#' @param angles Vector of angles | ||
#' @importFrom circular circular | ||
#' @importFrom collapse fmedian | ||
#' @keywords internal | ||
calculate_circular_mad <- function(angles) { | ||
ensure_circular(angles) | ||
# Convert angles to circular object | ||
angles_circular <- circular::circular(angles, units = "radians") | ||
|
||
# Calculate circular median | ||
circular_median <- collapse::fmedian(angles_circular) | ||
|
||
# Compute absolute deviations from the circular median | ||
abs_dev <- abs(angles_circular - circular_median) | ||
|
||
# Calculate and return the median absolute deviation | ||
collapse::fmedian(abs_dev) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#' Calculate straightness measures | ||
#' | ||
#' @param data Data frame | ||
#' @param straightness hich method to calculate path straightness. Choose between "A" (default), "B", "C"... or a combination (e.g. "c("A","B")"). See description for details about the different calculations. | ||
#' | ||
#' @keywords internal | ||
#' @export | ||
calculate_straightness <- function(data, straightness = c("A", "B", "C", "D")){ | ||
# Make validator to ensure that x,y,total_translation and total_rotation is present | ||
|
||
data <- data |> | ||
dplyr::mutate(straightness_A = calculate_straightness_A( | ||
.data$last_x, | ||
.data$last_y, | ||
.data$total_distance), | ||
straightness_B = calculate_straightness_B( | ||
.data$last_x, | ||
.data$last_y, | ||
.data$total_distance), | ||
straightness_C = calculate_straightness_C( | ||
.data$total_distance, | ||
.data$total_rotation), | ||
straightness_D = calculate_straightness_D( | ||
.data$total_distance, | ||
.data$total_rotation) | ||
) | ||
|
||
# Only select the methods chosen by the user | ||
possible_straightness <- c("A", "B", "C", "D") | ||
possible_straightness_columns <- paste("straightness", possible_straightness, sep = "_") | ||
straightness_columns <- paste("straightness", straightness, sep = "_") | ||
columns_not_selected <- possible_straightness_columns[which(!possible_straightness_columns %in% straightness_columns)] | ||
data <- data |> | ||
dplyr::select(!all_of(columns_not_selected)) | ||
|
||
return(data) | ||
} | ||
|
||
#' @keywords internal | ||
calculate_straightness_A <- function(x, y, distance){ | ||
calculate_distance(x, y) / distance | ||
} | ||
|
||
#' @keywords internal | ||
calculate_straightness_B <- function(x, y, distance){ | ||
distance / calculate_distance(x, y) | ||
} | ||
|
||
#' @keywords internal | ||
calculate_straightness_C <- function(distance, rotation){ | ||
distance / as.numeric(rotation) | ||
} | ||
|
||
#' @keywords internal | ||
calculate_straightness_D <- function(distance, rotation){ | ||
as.numeric(rotation) / distance | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#' Clean kinematics | ||
#' | ||
#' @description | ||
#' `r lifecycle::badge('experimental')` | ||
#' | ||
#' @param data | ||
#' | ||
#' @return a clean kinematics data frame | ||
#' @export | ||
clean_kinematics <- function(data){ | ||
# Place validators here | ||
|
||
# Proceed to make the cleaning | ||
data <- data |> | ||
dplyr::filter(.data$direction != atan2(1,0) & .data$direction != atan2(0,1)) |> | ||
dplyr::filter(.data$v_translation > 0) | ||
return(data) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.