Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Hanna authored and Richard Hanna committed Jul 19, 2022
0 parents commit 3ae357b
Show file tree
Hide file tree
Showing 28 changed files with 1,678 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
^renv$
^renv\.lock$
^.*\.Rproj$
^\.Rproj\.user$
^LICENSE\.md$
^README\.Rmd$
1 change: 1 addition & 0 deletions .Rprofile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source("renv/activate.R")
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.Rproj.user
.Rhistory
.RData
.Ruserdata
20 changes: 20 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Package: REDCapTidieR
Type: Package
Title: Extract REDCap Databases into Tidy Tibbles
Version: 0.0.0.9000
Author: c(
person("Richard", "Hanna", , "[email protected]", role = c("aut", "cre")),
person("Stephan", "Kadauke", , "[email protected]", role = "aut")
)
Maintainer: The package maintainer <[email protected]>
Description: This package is designed to help convert REDCap exports into tidy tables for easy handling of REDCap repeat instruments and event arms.
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Imports:
checkmate,
dplyr,
purrr,
REDCapR,
stringr
RoxygenNote: 7.2.0
2 changes: 2 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
YEAR: 2022
COPYRIGHT HOLDER: REDCapTidieR authors
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# MIT License

Copyright (c) 2022 REDCapTidieR authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
10 changes: 10 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Generated by roxygen2: do not edit by hand

export(read_redcap_tidy)
import(REDCapR)
import(checkmate)
import(dplyr)
import(purrr)
import(stringr)
import(tibble)
import(tidyr)
107 changes: 107 additions & 0 deletions R/clean_redcap.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#' Extract non-Longitudinal REDCap Databases into Tidy Tibbles
#'
#' @param db_data The REDCap database output defined by \code{REDCapR::reedcap_read_oneshot()$data}
#' @param db_metadata The REDCap metadata output defined by \code{REDCapR::redcap_metadata_read()$data}
#'
#' @import dplyr purrr REDCapR checkmate

clean_redcap <- function(
db_data,
db_metadata
){

# Apply checkmate checks ---
assert_data_frame(db_data)
assert_data_frame(db_metadata)

repeated_forms <- db_data %>%
filter(!is.na(redcap_repeat_instrument)) %>%
pull(redcap_repeat_instrument) %>%
unique()

repeated_forms_tibble <- tibble(
names = repeated_forms,
data = map(
repeated_forms,
~ extract_repeat_table(.x, db_data, db_metadata)
),
structure = "repeating"
)

nonrepeated_forms <- db_metadata %>%
pull(form_name) %>%
unique() %>%
setdiff(repeated_forms)

nonrepeated_forms_tibble <- tibble(
names = nonrepeated_forms,
data = map(
nonrepeated_forms,
~ extract_nonrepeat_table(.x, db_data, db_metadata)
),
structure = "nonrepeating"
)

clean_redcap_output <- rbind(repeated_forms_tibble, nonrepeated_forms_tibble)

clean_redcap_output
}

#' Extract Non-Repeat Tables from non-Longitudinal REDCap Databases
#'
#' @param form_name The \code{form_name} described in the named column from the REDCap metadata.
#' @param db_data The REDCap database output defined by \code{REDCapR::reedcap_read_oneshot()$data}
#' @param db_metadata The REDCap metadata output defined by \code{REDCapR::redcap_metadata_read()$data}
#'
#' @import dplyr REDCapR

extract_nonrepeat_table <- function(
form_name,
db_data,
db_metadata
){
my_record_id <- names(db_data)[1]
my_form <- form_name

my_fields <- db_metadata %>%
filter(form_name == my_form) %>%
pull(field_name)

if (my_fields[1] != my_record_id) {
my_fields <- c(my_record_id, my_fields)
}

db_data %>%
filter(is.na(redcap_repeat_instance)) %>%
select(all_of(my_fields))
}

#' Extract Repeat Tables from non-Longitudinal REDCap Databases
#'
#' @param form_name The \code{form_name} described in the named column from the REDCap metadata.
#' @param db_data The non-longitudinal REDCap database output defined by \code{REDCapR::redcap_read_oneshot()$data}
#' @param db_metadata The non-longitudinal REDCap metadata output defined by \code{REDCapR::redcap_metadata_read()$data}
#'
#' @import dplyr REDCapR

extract_repeat_table <- function(
form_name,
db_data,
db_metadata
){
my_record_id <- names(db_data)[1]
my_form <- form_name

my_fields <- db_metadata %>%
filter(form_name == my_form) %>%
pull(field_name)

if (my_fields[1] != my_record_id) {
my_fields <- c(my_record_id, my_fields)
}

db_data %>%
filter(!is.na(redcap_repeat_instance)) %>%
select(all_of(my_fields), redcap_repeat_instance) %>%
relocate(redcap_repeat_instance, .after = all_of(my_record_id))
}
162 changes: 162 additions & 0 deletions R/clean_redcap_long.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#' Extract Longitudinal REDCap Databases into Tidy Tibbles
#'
#' @param db_data_long The longitudinal REDCap database output defined by \code{REDCapR::redcap_read_oneshot()$data}
#' @param db_metadata_long The longitudinal REDCap metadata output defined by \code{REDCapR::redcap_metadata_read()$data}
#' @param linked_arms Output of \code{link_arms}, linking forms to REDCap events/arms
#'
#' @import dplyr purrr REDCapR checkmate

clean_redcap_long <- function(
db_data_long,
db_metadata_long,
linked_arms
){

# Apply checkmate checks
assert_data_frame(db_data_long)
assert_data_frame(db_metadata_long)

## Repeating Forms Logic ----
repeated_forms <- db_data_long %>%
filter(!is.na(redcap_repeat_instrument)) %>%
pull(redcap_repeat_instrument) %>%
unique()

repeated_forms_tibble <- tibble(
redcap_form_names = repeated_forms,
redcap_data = map(
redcap_form_names,
~ extract_repeat_table_long(.x, db_data_long, db_metadata_long, linked_arms)
),
structure = "repeating"
)

## Nonrepeating Forms Logic ----
nonrepeated_forms <- db_metadata_long %>%
pull(form_name) %>%
unique() %>%
setdiff(repeated_forms)

nonrepeated_forms_tibble <- tibble(
redcap_form_names = nonrepeated_forms,
redcap_data = map(
redcap_form_names,
~ extract_nonrepeat_table_long(.x, db_data_long, db_metadata_long, linked_arms)
),
structure = "nonrepeating"
)

clean_redcap_output <- rbind(repeated_forms_tibble, nonrepeated_forms_tibble)

clean_redcap_output
}

#' Extract Non-Repeat Tables from Longitudinal REDCap Databases
#'
#' @param form_name The \code{form_name} described in the named column from the REDCap metadata.
#' @param db_data The REDCap database output defined by \code{REDCapR::reedcap_read_oneshot()$data}
#' @param db_metadata The REDCap metadata output defined by \code{REDCapR::redcap_metadata_read()$data}
#' @param linked_arms Output of \code{link_arms}, linking forms to REDCap events/arms
#'
#' @import dplyr REDCapR stringr

extract_nonrepeat_table_long <- function(
form_name,
db_data_long,
db_metadata_long,
linked_arms
){
my_record_id <- names(db_data_long)[1]
my_form <- form_name

my_fields <- db_metadata_long %>%
filter(form_name == my_form) %>%
pull(field_name)

if (my_fields[1] != my_record_id) {
my_fields <- c(my_record_id, my_fields)
}

# Setup data for loop redcap_arm linking
db_data_long <- db_data_long %>%
add_partial_keys() %>%
filter(is.na(redcap_repeat_instance))

# Use link_arms() output to check if my_form appears in each event_name
# If it does not, filter out all rows containing that event_name
for (i in 1:length(names(linked_arms))) {
if (my_form %in% unlist(linked_arms[[i]]) == FALSE) {
db_data_long <- db_data_long %>%
filter(redcap_event_name != names(linked_arms[i]))
}
db_data_long
}

# Final aesthetic cleanup
out <- db_data_long %>%
select(all_of(my_fields), redcap_event, redcap_arm) %>%
relocate(c(redcap_event, redcap_arm), .after = record_id)

# Check arms
if(any(names(linked_arms) %>% str_detect("arm_2"))){
out <- out %>%
select(-redcap_arm)
}

out
}

#' Extract Repeat Tables from Longitudinal REDCap Databases
#'
#' @param form_name The \code{form_name} described in the named column from the REDCap metadata.
#' @param db_data The REDCap database output defined by \code{REDCapR::reedcap_read_oneshot()$data}
#' @param db_metadata The REDCap metadata output defined by \code{REDCapR::redcap_metadata_read()$data}
#' @param linked_arms Output of \code{link_arms}, linking forms to REDCap events/arms
#'
#' @import dplyr REDCapR stringr

extract_repeat_table_long <- function(
form_name,
db_data_long,
db_metadata_long,
linked_arms
){
my_record_id <- names(db_data_long)[1]
my_form <- form_name

my_fields <- db_metadata_long %>%
filter(form_name == my_form) %>%
pull(field_name)

if (my_fields[1] != my_record_id) {
my_fields <- c(my_record_id, my_fields)
}

# Setup data for loop redcap_arm linking
db_data_long <- db_data_long %>%
add_partial_keys() %>%
filter(!is.na(redcap_repeat_instance))

# Use link_arms() output to check if my_form appears in each event_name
# If it does not, filter out all rows containing that event_name
for (i in 1:length(names(linked_arms))) {
if (my_form %in% unlist(linked_arms[[i]]) == FALSE) {
db_data_long <- db_data_long %>%
filter(redcap_event_name != names(linked_arms[i]))
}
db_data_long
}

# Final aesthetic cleanup
out <- db_data_long %>%
select(all_of(my_fields), redcap_repeat_instance, redcap_event, redcap_arm) %>%
relocate(c(redcap_repeat_instance, redcap_event, redcap_arm), .after = record_id)

# Check arms
if(any(names(linked_arms) %>% str_detect("arm_2"))){
out <- out %>%
select(-redcap_arm)
}

out
}
45 changes: 45 additions & 0 deletions R/read_redcap_tidy.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#' Extract REDCap Databases to Tidy Tibbles
#'
#' Automatically detect REDCap database structure for the following elements:
#' \itemize{
#' \item{Repeat Instruments}
#' \item{Longitudinal Events}
#' \item{Longitudinal Arms}
#' }
#'
#' @import REDCapR
#'
#' @param redcap_uri The URI (uniform resource identifier) of the REDCap project. Required.
#' @param token The user-specific string that serves as the password for a project. Required.
#'
#' @export

read_redcap_tidy <- function(redcap_uri,
token){

# Load Datasets ----
db_data <- redcap_read_oneshot(redcap_uri = redcap_uri,
token = token)$data

db_metadata <- redcap_metadata_read(redcap_uri = redcap_uri,
token = token)$data

# Check if database supplied is longitudinal to determine appropriate function to use
is_longitudinal <- if("redcap_event_name" %in% names(db_data)){TRUE}else{FALSE}

if (is_longitudinal) {
linked_arms <- link_arms(db_data_long = db_data,
db_metadata_long = db_metadata,
redcap_uri = redcap_uri,
token = token)

out <- clean_redcap_long(db_data_long = db_data,
db_metadata_long = db_metadata,
linked_arms = linked_arms)
} else {
out <- clean_redcap(db_data = db_data,
db_metadata = db_metadata)
}

out
}
Loading

0 comments on commit 3ae357b

Please sign in to comment.