Skip to content

Commit

Permalink
Merge pull request #92 from habitus-eu/issue90_integrate_hbGPS
Browse files Browse the repository at this point in the history
Issue90 integrate hb gps
  • Loading branch information
vincentvanhees authored Sep 15, 2023
2 parents 06ca603 + 7f6c83f commit 0fe66d3
Show file tree
Hide file tree
Showing 30 changed files with 993 additions and 496 deletions.
8 changes: 4 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: HabitusGUI
Title: R Shiny App for Processing Behavioural Data
Description: Shiny app to ease processing behavioural data with research software such as GGIR, activityCounts, PALMSpy,and palmsplusr.
Version: 0.1.9
Date: 2022-09-08
Version: 0.2.0
Date: 2022-09-30
Authors@R:
c(person(given = "Vincent",
family = "van Hees",
Expand All @@ -13,8 +13,8 @@ Authors@R:
License: Apache License version 2.0 | file LICENSE
Imports: shiny, shinyFiles, GGIR, bslib, methods, jsonlite, DT,
dplyr, magrittr, shinyjs, sf, readr, tidyr, stringr, callr, palmsplusr,
data.table, rlang, purrr, geosphere
Remotes: vincentvanhees/palmsplusr
data.table, rlang, purrr, geosphere, hbGPS
Remotes: vincentvanhees/palmsplusr, habitus-eu/hbGPS
LazyData: true
Suggests: testthat, covr, rmarkdown
Depends: stats, utils, R (>= 3.5.0)
Expand Down
5 changes: 3 additions & 2 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
export(Counts2csv)
export(GGIRshiny)
export(PALMSpyshiny)
export(checkFile)
export(checkConfigFile)
export(check_and_clean_palms_data)
export(check_params)
export(cleanPath)
export(create_test_GGIRconfig)
export(create_test_files)
export(hbGPS_shiny)
export(hbt_build_days)
export(hbt_build_multimodal)
export(hbt_build_palmsplus)
Expand All @@ -24,6 +25,7 @@ export(update_params)
exportClasses(toolio)
import(GGIR)
import(dplyr)
import(hbGPS)
import(palmsplusr)
import(sf)
import(shiny)
Expand All @@ -39,7 +41,6 @@ importFrom(methods,new)
importFrom(methods,setClass)
importFrom(purrr,reduce)
importFrom(readr,read_csv)
importFrom(readr,write_csv)
importFrom(rlang,UQ)
importFrom(rlang,parse_expr)
importFrom(stats,aggregate)
Expand Down
4 changes: 2 additions & 2 deletions R/GGIRshiny.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#'
#' @param rawaccdir Path to input directory
#' @param outputdir Path to output directory
#' @param configfile Configfile path
#' @param sleepdiary Path to sleep diary
#' @param configfile Configfile path
#' @param do.Counts Boolean to indicate whether BrondCounts should be derived
#' @return no object is returned, only a new file is created in the output directory
#' @import GGIR
Expand Down Expand Up @@ -40,7 +40,7 @@ GGIRshiny = function(rawaccdir, outputdir, sleepdiary = c(), configfile = c(),
if (.Platform$OS.type == "windows") {
logFile = paste0(outputdir, "/GGIR.log")
fileConn = file(logFile)
writeLines(c("Hello, this Shiny app is primarily designed for Linux.",
writeLines(c("Hello, this Shiny app is primarily designed for Unix.",
"In Windows OS live progress of the analysis can be followed in the RStudio console.",
"In Unix-like systems the progress would be shown here inside this window in the Shiny app."), fileConn)
close(fileConn)
Expand Down
50 changes: 50 additions & 0 deletions R/checkConfigFile.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#' Function to check that the config files have the expected format
#'
#' @param file data path to config file
#' @param tool either PALMSpy, GGIR, or palmsplusr for now.
#'
#' @return message with the result of the check (either ok or the description of a problem)
#' @export
checkConfigFile = function(file=c(), tool=c()) {
# intialize check object, ok by default, it would be overwritten if
# any problem is identified in the config file.
check = "ok"

# General check on file existence and extension
if (!file.exists(file)) {
# stop("No config file found at ", path)
check = "No config file found at "
} else {
path_unlist = unlist(strsplit(x = file, split = ".", fixed = TRUE))
path_ext = tolower(path_unlist[length(path_unlist)])
if (tool %in% c("GGIR", "hbGPS", "palmsplusr") & path_ext != "csv") {
check = "The GGIR config file uploaded is not a csv file"
} else if (tool == "PALMSpy" & path_ext != "json") {
check = "The GGIR config file uploaded is not a json file"
}
}

# Specific file content check
if (check == "ok") {
if (tool == "PALMSpy") {
# TO BE DEVELOPED
} else if (tool == "GGIR" || tool == "hbGPS") {
# read config file if it exists and it is a csv file
params = read.csv(file = file)
# sanity check 2: colnames of config file ----
if (ncol(params) == 3 && tool != "palmsplusr") {
check_colnames = all.equal(colnames(params), c("argument", "value", "context"))
} else if (ncol(params) == 5 && tool == "palmsplusr") {
check_colnames = all.equal(colnames(params), c("context", "name", "formula", "domain_field", "after_conversion"))
} else {
check_colnames = FALSE
}
if (check_colnames == FALSE) {
# this automatically also checks that csv is separated by commas, as
# it would generate just one column (e.g., "argument;value;context") otherwise
check = paste0("The csv file uploaded is not a ", tool, " config file")
}
}
}
return(check)
}
69 changes: 0 additions & 69 deletions R/checkFile.R

This file was deleted.

5 changes: 3 additions & 2 deletions R/check_and_clean_palms_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
#'
#' @param palms_to_clean palms_to_clean
#' @param country_name country_name
#' @param outputdir outputdir
#' @return palms_to_clean_lower object
#' @import dplyr
#' @export
check_and_clean_palms_data <- function(palms_to_clean, country_name){
check_and_clean_palms_data <- function(palms_to_clean, country_name, outputdir = NULL){
dif = datetime = identifier = tripnumber = triptype = tt1 = tt4 = NULL
miss_end = miss_start = multi_start = multi_end = error = NULL
# Create error list -------------------------------------------------------
Expand Down Expand Up @@ -40,7 +41,7 @@ check_and_clean_palms_data <- function(palms_to_clean, country_name){

# Saving the new 'clean' dataset - %>% ---------------------------------------
# write_csv(palms, str_replace(link_to_csv, pattern = '.csv', '_cleaned.csv'), na = "")
write_csv(error_list, paste(country_name,"error_list.csv", sep = "_"))
data.table::fwrite(error_list, paste(outputdir, country_name,"error_list.csv", sep = "_"))

return(palms_to_clean_lower)
}
Expand Down
14 changes: 13 additions & 1 deletion R/check_params.R
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,19 @@ check_params = function(params = c(), tool = c()) {
}
}
}

# Check parameters which value should be timeformat
seti = which(params$class == "timeformat")
if (length(seti) > 0) {
for (i in seti) {
stmp = unlist(strsplit(params$value[i], "%"))
stmp = stmp[which(stmp != "")]
if (length(stmp) != 6) {
blocked_params$name[cnt] = rowNames[i]
blocked_params$error[cnt] = "is not a valid R time format specification."
cnt = cnt + 1
}
}
}
# Create messages
if (cnt <= N) {
blocked_params = blocked_params[-c(cnt:N),]
Expand Down
62 changes: 62 additions & 0 deletions R/hbGPS_shiny.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#' hbGPS_shiny
#'
#' @param ggiroutdir GGIR time series output directory
#' @param gpsdir Path to GPS directory
#' @param outputdir Path to output directory
#' @param dataset_name Name of dataset
#' @param configfile Path to configuration file
#' @return no object is returned, only a new file is created in the output directory
#' @import hbGPS
#' @export

hbGPS_shiny = function(ggiroutdir = NULL, gpsdir = NULL, outputdir = NULL,
dataset_name = "", configfile = c()) {
# create R script with the code to run the data analysis via a command line call
# in this way turning off or restarting the app will not kill the data analysis
fileConn <- file(paste0(outputdir, "/hbgps_cmdline.R"))
writeLines(c("#!/usr/bin/env Rscript",
"args = commandArgs(trailingOnly = TRUE)",
"if (length(args) < 4) {",
"stop(\"At least four arguments are expected\", call. = FALSE)",
"}",
"hbGPS::hbGPS(gps_file = args[1], ",
"GGIRpath = args[2],",
"outputDir = args[3],",
"configFile = args[4])"
),
fileConn)
close(fileConn)
if (.Platform$OS.type == "windows") {
logFile = paste0(outputdir, "/hbGPS.log")
fileConn = file(logFile)
writeLines(c("Hello, this Shiny app is primarily designed for Unix.",
"In Windows OS live progress of the analysis can be followed in the RStudio console.",
"In Unix-like systems the progress would be shown here inside this window in the Shiny app."), fileConn)
close(fileConn)

basecommand = paste0(outputdir, "/hbgps_cmdline.R ",
gpsdir, " ",
ggiroutdir, " ",
outputdir, " ",
configfile)
system2(command = "Rscript", args = basecommand,
stdout = "",
stderr = "", wait = TRUE)
write.table(x = paste0(""),
file = paste0(outputdir, "/hbGPS.log"))

fileConn = file(logFile)
writeLines(c(""), fileConn)
close(fileConn)

} else {
basecommand = paste0("cd ", outputdir, " ; nohup Rscript hbgps_cmdline.R ",
gpsdir, " ",
ggiroutdir, " ",
outputdir, " ",
configfile, " > ", outputdir, "/hbGPS.log 2>&1 &")
system2(command = "cd", args = gsub(pattern = "cd ", replacement = "", x = basecommand),
stdout = "", stderr = "", wait = TRUE)
}

}
5 changes: 3 additions & 2 deletions R/hbt_build_days.R
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ hbt_build_days <- function(data = NULL, verbose = TRUE,
mutate_if(is.logical, as.integer)

fields <- palmsplus_fields %>% filter(domain_field == TRUE) %>% pull(name)
data <- data %>%

data <- data %>%
st_set_geometry(NULL) %>%
dplyr::select(identifier, datetime, domain_names, all_of(fields)) %>%
dplyr::select(identifier, datetime, any_of(domain_names), all_of(fields)) %>%
mutate(duration = 1) %>%
mutate_at(vars(-identifier,-datetime), ~ . * palms_epoch(data) / 60) %>%
group_by(identifier, date = as.Date(datetime)) %>%
Expand Down
37 changes: 23 additions & 14 deletions R/identify_tools.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,36 @@
# S4 class needs to be defined outside function
setClass(Class = "toolio", slots = list(input = "character", output = "character", usecases = "character"))

identify_tools = function(datatypes = c("AccRaw", "ACount", "GPS", "GIS", "PALMSpy_out"),
identify_tools = function(datatypes = c("AccRaw", "ACount", "GPS", "GIS",
"PALMSpy_out", "GGIR_out", "hbGPS_out"),
goals = c("PA", "QC", "Trips", "Environment"),
available_tools = c("GGIR", "PALMSpy", "palmsplusr", "Counts")) {
available_tools = c("GGIR", "PALMSpy", "palmsplusr", "CountConverter", "hbGPS")) {
iotools = list(GGIR = new("toolio",
input = "AccRaw",
output = c("GGIR_out", "ACount"),
usecases = c("PA", "QC", "Trips", "Environment")),
PALMSpy = new("toolio",
input = c("ACount","GPS"),
input = c("ACount", "GPS"),
output = c("PALMSpy_out"),
usecases = c("Trips", "QC", "Environment")),
palmsplusr = new("toolio",
input = c("PALMSpy_out", "GIS"),
output = c("palmsplusr_out"),
usecases = c("Environment", "QC")),
Counts = new("toolio",
input = "AccRaw",
output = c("Counts_out"),
usecases = c("PA", "Trips", "QC", "Environment")))
palmsplusr = new("toolio", # palmsplusr based on PALMSpy output
input = c("PALMSpy_out", "GIS"),
output = c("palmsplusr_out"),
usecases = c("Environment", "QC")),
palmsplusr = new("toolio", # palmsplusr based on hbGPS output
input = c("hbGPS_out", "GIS"),
output = c("palmsplusr_out"),
usecases = c("Environment", "QC")),
CountConverter = new("toolio",
input = "AccRaw",
output = c("Counts_out"),
usecases = c("PA", "Trips", "QC", "Environment")),
hbGPS = new("toolio",
input = c("GGIR_out","GPS"),
output = c("hbGPS_out"),
usecases = c("Trips", "QC", "Environment")))
iotools = iotools[which(names(iotools) %in% available_tools)] # only look at available tools
allgoals = tools_needed = outputs = c()
tools_needed = outputs = c()
# loop over tools and select the ones that generate the output users needs and is able to generate
for (j in 1:length(available_tools)) { # assumption is that pipeline is never longer then number of tools
for (i in 1:length(iotools)) {
Expand All @@ -46,10 +55,10 @@ identify_tools = function(datatypes = c("AccRaw", "ACount", "GPS", "GIS", "PALMS
if ("AccRaw" %in% datatypes == FALSE & "GGIR" %in% tools_needed) {
tools_needed = tools_needed[-which(tools_needed == "GGIR")]
}
if ("Counts" %in% tools_needed) {
if ("CountConverter" %in% tools_needed) {
if ("ACount" %in% datatypes == TRUE | # No need to estimate counts if they already exist
("AccRaw" %in% datatypes == TRUE & "GPS" %in% datatypes == FALSE)) { # No need to estimate counts if there is no GPS data
tools_needed = tools_needed[-which(tools_needed == "Counts")]
tools_needed = tools_needed[-which(tools_needed == "CountConverter")]
}
}
invisible(list(tools_needed = tools_needed, iotools = iotools[which(names(iotools) %in% tools_needed)]))
Expand Down
Loading

0 comments on commit 0fe66d3

Please sign in to comment.