Introduction

library(REDCapCAST)

This vignette covers the included functions and basic functionality.

A dataset and a meta data file are provided with the package for demonstration of the functions.

Splitting the dataset

redcapcast_data |> gt::gt()
record_id redcap_event_name redcap_repeat_instrument redcap_repeat_instance cpr inclusion dob age age_integer sex cohabitation hypertension diabetes region baseline_data_start_complete mrs_assessed mrs_date mrs_score mrs_complete event_date event_type new_event_complete
1 inclusion NA NA 1203401OB4 2023-03-13 1940-03-12 83.00239 83 female Yes No Yes East Incomplete Yes 2023-03-13 1 Incomplete NA NA NA
2 inclusion NA NA 0102342303 2023-03-01 1934-02-01 89.07780 89 male Yes No No South Incomplete Yes 2023-03-07 1 Incomplete NA NA NA
2 follow1 NA NA NA NA NA NA NA NA NA NA NA NA NA Yes 2023-03-09 3 Incomplete NA NA NA
2 follow1 New Event (?) 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-03-13 TIA Incomplete
3 inclusion NA NA 2301569823 2022-03-08 1956-01-23 66.12319 66 male No Yes Yes North Incomplete NA NA NA Incomplete NA NA NA
3 follow1 NA NA NA NA NA NA NA NA NA NA NA NA NA Yes 2022-08-16 2 Incomplete NA NA NA
3 follow2 NA NA NA NA NA NA NA NA NA NA NA NA NA Yes 2023-03-13 1 Incomplete NA NA NA
3 follow1 New Event (?) 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2022-11-08 AIS Incomplete
3 follow1 New Event (?) 2 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2022-12-14 ICH Incomplete
3 follow2 New Event (?) 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-02-06 ICH Incomplete
3 follow2 New Event (?) 2 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-03-13 TIA Incomplete
3 follow2 New Event (?) 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-02-28 AIS Incomplete
4 inclusion NA NA 0204051342 2023-03-14 1905-04-02 117.94903 117 female NA NA NA NA Incomplete NA NA NA Incomplete NA NA NA
4 follow2 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA Incomplete NA NA NA
4 follow2 New Event (?) 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-01-02 AIS Complete
4 follow2 New Event (?) 2 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-02-06 ICH Incomplete
4 follow2 New Event (?) 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 2023-03-05 Unknown Complete
5 inclusion NA NA 0201976043 2023-03-23 1897-01-02 126.21751 126 male No Yes Yes East Complete NA NA NA Incomplete NA NA NA
redcapcast_meta |> gt::gt()
field_name form_name section_header field_type field_label select_choices_or_calculations field_note text_validation_type_or_show_slider_number text_validation_min text_validation_max identifier branching_logic required_field custom_alignment question_number matrix_group_name matrix_ranking field_annotation
record_id baseline_data_start NA text ID NA NA NA NA NA NA NA NA NA NA NA NA NA
cpr baseline_data_start NA text CPR (Danish civil registration number) NA ddmmyyxxxx NA NA NA y NA y NA NA NA NA NA
inclusion baseline_data_start NA text Inclusion date NA NA date_ymd NA NA NA NA NA NA NA NA NA NA
dob baseline_data_start NA text Date of birth (From CPR) NA NA date_ymd NA NA NA NA NA NA NA NA NA @CALCTEXT(if([cpr]!="", concat(if(mid([cpr], 7, 1)>=0 and mid([cpr], 7, 1)<=3,19, if(mid([cpr], 5, 2)>=0 and mid([cpr], 5, 2)<=36 and mid([cpr], 7, 1)>=4 and mid([cpr], 7, 1)<=4,20, if(mid([cpr], 5, 2)>=37 and mid([cpr], 5, 2)<=99 and mid([cpr], 7, 1)>=4 and mid([cpr], 7, 1)<=4,19, if(mid([cpr], 5, 2)>=0 and mid([cpr], 5, 2)<=57 and mid([cpr], 7, 1)>=5 and mid([cpr], 7, 1)<=5,20, if(mid([cpr], 5, 2)>=58 and mid([cpr], 5, 2)<=99 and mid([cpr], 7, 1)>=5 and mid([cpr], 7, 1)<=5,18, if(mid([cpr], 5, 2)>=0 and mid([cpr], 5, 2)<=57 and mid([cpr], 7, 1)>=6 and mid([cpr], 7, 1)<=6,20, if(mid([cpr], 5, 2)>=58 and mid([cpr], 5, 2)<=99 and mid([cpr], 7, 1)>=6 and mid([cpr], 7, 1)<=6,18, if(mid([cpr], 5, 2)>=0 and mid([cpr], 5, 2)<=57 and mid([cpr], 7, 1)>=7 and mid([cpr], 7, 1)<=7,20, if(mid([cpr], 5, 2)>=58 and mid([cpr], 5, 2)<=99 and mid([cpr], 7, 1)>=7 and mid([cpr], 7, 1)<=7,18, if(mid([cpr], 5, 2)>=0 and mid([cpr], 5, 2)<=57 and mid([cpr], 7, 1)>=8 and mid([cpr], 7, 1)<=8,20, if(mid([cpr], 5, 2)>=58 and mid([cpr], 5, 2)<=99 and mid([cpr], 7, 1)>=8 and mid([cpr], 7, 1)<=8,18, if(mid([cpr], 5, 2)>=0 and mid([cpr], 5, 2)<=36 and mid([cpr], 7, 1)>=9 and mid([cpr], 7, 1)<=9,20, if(mid([cpr], 5, 2)>=37 and mid([cpr], 5, 2)<=99 and mid([cpr], 7, 1)>=9 and mid([cpr], 7, 1)<=9,19,17))))))))))))), mid([cpr], 5, 2), "-",mid([cpr],3, 2), "-", left([cpr], 2) ), ""))
age baseline_data_start NA calc Age Note: Apparently, the build in datediff() function does not handle counting whole years. This results in wrongly counting age higher around the date of birth. if([cpr]!="" and [inclusion]!="", datediff([dob], [inclusion], 'y'), "") NA NA NA NA NA NA NA NA NA NA NA NA
age_integer baseline_data_start NA calc Age integer Note: as opposed to the build in datediff() this handles counting years as integers very well. Calculate decimal years in statistical programming software. In R you can use with(ds, stRoke::age_calc(dob, inclusion)). if([cpr]!="", left([inclusion], 4)-left([dob], 4) - if(mid([dob], 6, 2) < mid([inclusion], 6, 2) or (mid([dob], 6, 2) = mid([inclusion], 6, 2) and mid([dob], 9, 2) <= mid([inclusion], 9, 2)), 0, 1),"") NA NA NA NA NA NA NA NA NA NA NA NA
sex baseline_data_start NA text Legal sex NA NA NA NA NA NA NA NA NA NA NA NA @CALCTEXT(if([cpr]!="",if((right([cpr],1)=1 or right([cpr],1)=3 or right([cpr],1)=5 or right([cpr],1)=7 or right([cpr],1)=9),"male","female"),""))
cohabitation baseline_data_start History and social radio Cohabitation 1, Yes | 2, No NA NA NA NA NA NA NA NA NA NA NA NA
hypertension baseline_data_start NA radio Hypertension 1, Yes | 2, No NA NA NA NA NA NA NA NA NA NA NA NA
diabetes baseline_data_start NA radio Diabetes 1, Yes | 2, No NA NA NA NA NA NA NA NA NA NA NA NA
region baseline_data_start Area dropdown Region 1, North | 2, East | 3, South | 4, West NA autocomplete NA NA NA NA NA NA NA NA NA NA
mrs_assessed mrs NA radio Assesed 1, Yes | 2, No NA NA NA NA NA NA NA NA NA NA NA NA
mrs_date mrs NA text Assessment date NA NA date_dmy NA NA NA NA NA NA NA NA NA NA
mrs_score mrs NA radio mRS score 0, 0 | 1, 1 | 2, 2 | 3, 3 | 4, 4 | 5, 5 NA NA NA NA NA NA NA NA NA NA NA NA
event_date new_event NA text Date of event NA NA date_dmy NA NA NA NA NA NA NA NA NA NA
event_type new_event NA radio Neurovascular event 1, TIA | 2, AIS | 3, ICH | 4, SAH | 99, Unknown NA NA NA NA NA NA NA NA NA NA NA NA
list <-
  REDCap_split(records = redcapcast_data,
                           metadata = redcapcast_meta,
                           forms = "repeating")
str(list)
#> List of 2
#>  $          :'data.frame':   9 obs. of  17 variables:
#>   ..$ record_id                   : num [1:9] 1 2 2 3 3 3 4 4 5
#>   ..$ redcap_event_name           : chr [1:9] "inclusion" "inclusion" "follow1" "inclusion" ...
#>   ..$ cpr                         : chr [1:9] "1203401OB4" "0102342303" NA "2301569823" ...
#>   ..$ inclusion                   : Date[1:9], format: "2023-03-13" "2023-03-01" ...
#>   ..$ dob                         : Date[1:9], format: "1940-03-12" "1934-02-01" ...
#>   ..$ age                         : num [1:9] 83 89.1 NA 66.1 NA ...
#>   ..$ age_integer                 : num [1:9] 83 89 NA 66 NA NA 117 NA 126
#>   ..$ sex                         : chr [1:9] "female" "male" NA "male" ...
#>   ..$ cohabitation                : chr [1:9] "Yes" "Yes" NA "No" ...
#>   ..$ hypertension                : chr [1:9] "No" "No" NA "Yes" ...
#>   ..$ diabetes                    : chr [1:9] "Yes" "No" NA "Yes" ...
#>   ..$ region                      : chr [1:9] "East" "South" NA "North" ...
#>   ..$ baseline_data_start_complete: chr [1:9] "Incomplete" "Incomplete" NA "Incomplete" ...
#>   ..$ mrs_assessed                : chr [1:9] "Yes" "Yes" "Yes" NA ...
#>   ..$ mrs_date                    : Date[1:9], format: "2023-03-13" "2023-03-07" ...
#>   ..$ mrs_score                   : num [1:9] 1 1 3 NA 2 1 NA NA NA
#>   ..$ mrs_complete                : chr [1:9] "Incomplete" "Incomplete" "Incomplete" "Incomplete" ...
#>  $ new_event:'data.frame':   9 obs. of  7 variables:
#>   ..$ record_id               : num [1:9] 2 3 3 3 3 3 4 4 4
#>   ..$ redcap_event_name       : chr [1:9] "follow1" "follow1" "follow1" "follow2" ...
#>   ..$ redcap_repeat_instrument: chr [1:9] "new_event" "new_event" "new_event" "new_event" ...
#>   ..$ redcap_repeat_instance  : num [1:9] 1 1 2 1 2 3 1 2 3
#>   ..$ event_date              : Date[1:9], format: "2023-03-13" "2022-11-08" ...
#>   ..$ event_type              : chr [1:9] "TIA" "AIS" "ICH" "ICH" ...
#>   ..$ new_event_complete      : chr [1:9] "Incomplete" "Incomplete" "Incomplete" "Incomplete" ...
list <-
  REDCap_split(records = redcapcast_data,
                           metadata = redcapcast_meta,
                           forms = "all")
str(list)
#> List of 3
#>  $ baseline_data_start:'data.frame': 9 obs. of  13 variables:
#>   ..$ record_id                   : num [1:9] 1 2 2 3 3 3 4 4 5
#>   ..$ redcap_event_name           : chr [1:9] "inclusion" "inclusion" "follow1" "inclusion" ...
#>   ..$ cpr                         : chr [1:9] "1203401OB4" "0102342303" NA "2301569823" ...
#>   ..$ inclusion                   : Date[1:9], format: "2023-03-13" "2023-03-01" ...
#>   ..$ dob                         : Date[1:9], format: "1940-03-12" "1934-02-01" ...
#>   ..$ age                         : num [1:9] 83 89.1 NA 66.1 NA ...
#>   ..$ age_integer                 : num [1:9] 83 89 NA 66 NA NA 117 NA 126
#>   ..$ sex                         : chr [1:9] "female" "male" NA "male" ...
#>   ..$ cohabitation                : chr [1:9] "Yes" "Yes" NA "No" ...
#>   ..$ hypertension                : chr [1:9] "No" "No" NA "Yes" ...
#>   ..$ diabetes                    : chr [1:9] "Yes" "No" NA "Yes" ...
#>   ..$ region                      : chr [1:9] "East" "South" NA "North" ...
#>   ..$ baseline_data_start_complete: chr [1:9] "Incomplete" "Incomplete" NA "Incomplete" ...
#>  $ mrs                :'data.frame': 9 obs. of  6 variables:
#>   ..$ record_id        : num [1:9] 1 2 2 3 3 3 4 4 5
#>   ..$ redcap_event_name: chr [1:9] "inclusion" "inclusion" "follow1" "inclusion" ...
#>   ..$ mrs_assessed     : chr [1:9] "Yes" "Yes" "Yes" NA ...
#>   ..$ mrs_date         : Date[1:9], format: "2023-03-13" "2023-03-07" ...
#>   ..$ mrs_score        : num [1:9] 1 1 3 NA 2 1 NA NA NA
#>   ..$ mrs_complete     : chr [1:9] "Incomplete" "Incomplete" "Incomplete" "Incomplete" ...
#>  $ new_event          :'data.frame': 9 obs. of  7 variables:
#>   ..$ record_id               : num [1:9] 2 3 3 3 3 3 4 4 4
#>   ..$ redcap_event_name       : chr [1:9] "follow1" "follow1" "follow1" "follow2" ...
#>   ..$ redcap_repeat_instrument: chr [1:9] "new_event" "new_event" "new_event" "new_event" ...
#>   ..$ redcap_repeat_instance  : num [1:9] 1 1 2 1 2 3 1 2 3
#>   ..$ event_date              : Date[1:9], format: "2023-03-13" "2022-11-08" ...
#>   ..$ event_type              : chr [1:9] "TIA" "AIS" "ICH" "ICH" ...
#>   ..$ new_event_complete      : chr [1:9] "Incomplete" "Incomplete" "Incomplete" "Incomplete" ...

Reading data from REDCap

This function wraps all the above demonstrated function to get the dataset, the metadata, apply the REDCap_splitfunction and then a bit of cleaning. It just cuts outs all the steps for an easier approach.

The function works very similar to the REDCapR::redcap_read() in allowing to specify fields, events and forms for export instead of exporting the whole database and filtering afterwards. I believe this is a better and safer, focused approach.

# read_redcap_tables(uri = "YOUR URI", token = "YOUR TOKEN")

Pivotting to wider format

# redcap_wider(ds)