Advanced REDCapR Operations

2019-09-22

This vignette covers the the less-typical uses of REDCapR to interact with REDCap through its API.

Next Steps

Set project-wide values.

There is some information that is specific to a REDCap project, as opposed to an individual operation. This includes the (1) uri of the server, and the (2) token for the user’s project. This is hosted on a machine used in REDCapR’s public test suite, so you can run this example from any computer. Unless tests are running.

library(REDCapR) #Load the package into the current R session.
uri                   <- "https://bbmc.ouhsc.edu/redcap/api/"
token_simple          <- "9A81268476645C4E5F03428B8AC3AA7B"
token_longitudinal    <- "0434F0E9CF53ED0587847AB6E51DE762"

Converting from tall/long to wide

Disclaimer: Occasionally we’re asked for a longitudinal dataset to be converted from a “long/tall format” (where typically each row is one observation for a participant) to a “wide format” (where each row is on participant). Usually we advise against it. Besides all the database benefits of a long structure, a wide structure restricts your options with the stat routine. No modern longitudinal analysis procedures (e.g., growth curve models or multilevel/hierarchical models) accept wide. You’re pretty much stuck with repeated measures anova, which is very inflexible for real-world medical-ish analyses. It requires a patient to have a measurement at every time point; otherwise the anova excludes the patient entirely.

However we like going wide to produce visual tables for publications, and here’s one way to do it in R. First retrieve the dataset from REDCap.

library(magrittr);
suppressPackageStartupMessages(requireNamespace("dplyr"))
suppressPackageStartupMessages(requireNamespace("tidyr"))
events_to_retain  <- c("dose_1_arm_1", "visit_1_arm_1", "dose_2_arm_1", "visit_2_arm_1")

ds_long <- REDCapR::redcap_read_oneshot(redcap_uri=uri, token=token_longitudinal)$data
#> 18 records and 125 columns were read from REDCap in 0.5 seconds.  The http status code was 200.
ds_long %>%
  dplyr::select(study_id, redcap_event_name, pmq1, pmq2, pmq3, pmq4)
#>    study_id        redcap_event_name pmq1 pmq2 pmq3 pmq4
#> 1       100         enrollment_arm_1   NA   NA   NA   NA
#> 2       100             dose_1_arm_1    2    2    1    1
#> 3       100            visit_1_arm_1    1    0    0    0
#> 4       100             dose_2_arm_1    3    1    0    0
#> 5       100            visit_2_arm_1    0    1    0    0
#> 6       100        final_visit_arm_1   NA   NA   NA   NA
#> 7       220         enrollment_arm_1   NA   NA   NA   NA
#> 8       220             dose_1_arm_1    0    1    0    2
#> 9       220            visit_1_arm_1    0    3    1    0
#> 10      220             dose_2_arm_1    1    2    0    1
#> 11      220            visit_2_arm_1    3    4    1    0
#> 12      220        final_visit_arm_1   NA   NA   NA   NA
#> 13      304         enrollment_arm_2   NA   NA   NA   NA
#> 14      304 deadline_to_opt_ou_arm_2   NA   NA   NA   NA
#> 15      304         first_dose_arm_2    0    1    0    0
#> 16      304        first_visit_arm_2    2    0    0    0
#> 17      304        final_visit_arm_2   NA   NA   NA   NA
#> 18      304 deadline_to_return_arm_2   NA   NA   NA   NA

When widening only one variable (e.g., pmq1), the code’s pretty simple:

ds_wide <-
  ds_long %>%
  dplyr::select(study_id, redcap_event_name, pmq1) %>%
  dplyr::filter(redcap_event_name %in% events_to_retain) %>%
  tidyr::spread(key=redcap_event_name, value=pmq1)
ds_wide
#>   study_id dose_1_arm_1 dose_2_arm_1 visit_1_arm_1 visit_2_arm_1
#> 1      100            2            3             1             0
#> 2      220            0            1             0             3

When widening more than one variable (e.g., pmq1 - pmq4), it’s usually easiest to go even longer/taller (e.g., ds_eav) before reversing direction and going wide:

pattern <- "^(\\w+?)_arm_(\\d)$"

ds_eav <- ds_long %>%
  dplyr::select(study_id, redcap_event_name, pmq1, pmq2, pmq3, pmq4) %>%
  dplyr::mutate(
    event      = sub(pattern, "\\1", redcap_event_name),
    arm        = as.integer(sub(pattern, "\\2", redcap_event_name))
  ) %>%
  dplyr::select(study_id, event, arm, pmq1, pmq2, pmq3, pmq4) %>%
  tidyr::gather(key=key, value=value, pmq1, pmq2, pmq3, pmq4) %>%
  dplyr::filter(!(event %in% c(
    "enrollment", "final_visit", "deadline_to_return", "deadline_to_opt_ou")
  )) %>%
  dplyr::mutate( # Simulate correcting for mismatched names across arms:
    event = dplyr::recode(event, "first_dose"="dose_1", "first_visit"="visit_1"),
    key = paste0(event, "_", key)
  ) %>%
  dplyr::select(-event)

# Show the first 10 rows of the EAV table.
ds_eav %>%
  head(10)
#>    study_id arm          key value
#> 1       100   1  dose_1_pmq1     2
#> 2       100   1 visit_1_pmq1     1
#> 3       100   1  dose_2_pmq1     3
#> 4       100   1 visit_2_pmq1     0
#> 5       220   1  dose_1_pmq1     0
#> 6       220   1 visit_1_pmq1     0
#> 7       220   1  dose_2_pmq1     1
#> 8       220   1 visit_2_pmq1     3
#> 9       304   2  dose_1_pmq1     0
#> 10      304   2 visit_1_pmq1     2
# Spread the EAV to wide.
ds_wide <-
  ds_eav %>%
  tidyr::spread(key=key, value=value)
ds_wide
#>   study_id arm dose_1_pmq1 dose_1_pmq2 dose_1_pmq3 dose_1_pmq4 dose_2_pmq1
#> 1      100   1           2           2           1           1           3
#> 2      220   1           0           1           0           2           1
#> 3      304   2           0           1           0           0          NA
#>   dose_2_pmq2 dose_2_pmq3 dose_2_pmq4 visit_1_pmq1 visit_1_pmq2
#> 1           1           0           0            1            0
#> 2           2           0           1            0            3
#> 3          NA          NA          NA            2            0
#>   visit_1_pmq3 visit_1_pmq4 visit_2_pmq1 visit_2_pmq2 visit_2_pmq3
#> 1            0            0            0            1            0
#> 2            1            0            3            4            1
#> 3            0            0           NA           NA           NA
#>   visit_2_pmq4
#> 1            0
#> 2            0
#> 3           NA

SSL Options

The official cURL site discusses the process of using SSL to verify the server being connected to.

Use the SSL cert file that come with the openssl package.

cert_location <- system.file("cacert.pem", package="openssl")
if( file.exists(cert_location) ) {
  config_options         <- list(cainfo=cert_location)
  ds_different_cert_file <- redcap_read_oneshot(
    redcap_uri     = uri,
    token          = token_simple,
    config_options = config_options
  )$data
}
#> 5 records and 24 columns were read from REDCap in 0.4 seconds.  The http status code was 200.

Force the connection to use SSL=3 (which is not preferred, and possibly insecure).

config_options <- list(sslversion=3)
ds_ssl_3 <- redcap_read_oneshot(
  redcap_uri     = uri,
  token          = token_simple,
  config_options = config_options
)$data
#> 5 records and 24 columns were read from REDCap in 0.3 seconds.  The http status code was 200.
config_options <- list(ssl.verifypeer=FALSE)
ds_no_ssl <- redcap_read_oneshot(
   redcap_uri     = uri,
   token          = token_simple,
   config_options = config_options
)$data
#> 5 records and 24 columns were read from REDCap in 0.6 seconds.  The http status code was 200.

Session Information

For the sake of documentation and reproducibility, the current report was rendered in the following environment. Click the line below to expand.

Environment

#> ─ Session info ──────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 3.6.1 (2019-07-05)
#>  os       Ubuntu 18.04.3 LTS          
#>  system   x86_64, linux-gnu           
#>  ui       X11                         
#>  language (EN)                        
#>  collate  C                           
#>  ctype    en_US.UTF-8                 
#>  tz       America/Chicago             
#>  date     2019-09-22                  
#> 
#> ─ Packages ──────────────────────────────────────────────────────────────
#>  package     * version    date       lib source                         
#>  assertthat    0.2.1      2019-03-21 [3] CRAN (R 3.6.0)                 
#>  backports     1.1.4      2019-04-10 [3] CRAN (R 3.6.0)                 
#>  callr         3.3.1      2019-07-18 [3] CRAN (R 3.6.1)                 
#>  checkmate     1.9.4      2019-07-04 [3] CRAN (R 3.6.0)                 
#>  cli           1.1.0      2019-03-19 [3] CRAN (R 3.6.0)                 
#>  colorspace    1.4-1      2019-03-18 [3] CRAN (R 3.6.0)                 
#>  crayon        1.3.4      2017-09-16 [3] CRAN (R 3.6.0)                 
#>  curl          4.1        2019-09-16 [3] CRAN (R 3.6.1)                 
#>  desc          1.2.0      2018-05-01 [3] CRAN (R 3.6.0)                 
#>  devtools      2.2.0.9000 2019-09-21 [3] Github (r-lib/devtools@2765fbe)
#>  digest        0.6.21     2019-09-20 [3] CRAN (R 3.6.1)                 
#>  dplyr         0.8.3      2019-07-04 [3] CRAN (R 3.6.0)                 
#>  ellipsis      0.3.0      2019-09-20 [3] CRAN (R 3.6.1)                 
#>  evaluate      0.14       2019-05-28 [3] CRAN (R 3.6.0)                 
#>  fs            1.3.1      2019-05-06 [3] CRAN (R 3.6.0)                 
#>  glue          1.3.1      2019-03-12 [3] CRAN (R 3.6.0)                 
#>  hms           0.5.1      2019-08-23 [3] CRAN (R 3.6.1)                 
#>  htmltools     0.3.6      2017-04-28 [3] CRAN (R 3.6.0)                 
#>  httr          1.4.1      2019-08-05 [3] CRAN (R 3.6.1)                 
#>  kableExtra    1.1.0.9001 2019-05-18 [3] local                          
#>  knitr       * 1.25       2019-09-18 [3] CRAN (R 3.6.1)                 
#>  lifecycle     0.1.0      2019-08-01 [3] CRAN (R 3.6.1)                 
#>  magrittr    * 1.5        2014-11-22 [3] CRAN (R 3.6.0)                 
#>  memoise       1.1.0      2017-04-21 [3] CRAN (R 3.6.0)                 
#>  munsell       0.5.0      2018-06-12 [3] CRAN (R 3.6.0)                 
#>  pillar        1.4.2      2019-06-29 [3] CRAN (R 3.6.0)                 
#>  pkgbuild      1.0.5      2019-08-26 [3] CRAN (R 3.6.1)                 
#>  pkgconfig     2.0.2      2018-08-16 [3] CRAN (R 3.6.0)                 
#>  pkgload       1.0.2      2018-10-29 [3] CRAN (R 3.6.0)                 
#>  prettyunits   1.0.2      2015-07-13 [3] CRAN (R 3.6.0)                 
#>  processx      3.4.1      2019-07-18 [3] CRAN (R 3.6.1)                 
#>  ps            1.3.0      2018-12-21 [3] CRAN (R 3.6.0)                 
#>  purrr         0.3.2      2019-03-15 [3] CRAN (R 3.6.0)                 
#>  R6            2.4.0      2019-02-14 [3] CRAN (R 3.6.0)                 
#>  Rcpp          1.0.2      2019-07-25 [3] CRAN (R 3.6.1)                 
#>  readr         1.3.1      2018-12-21 [3] CRAN (R 3.6.0)                 
#>  REDCapR     * 0.10.2     2019-09-22 [1] local                          
#>  remotes       2.1.0      2019-06-24 [3] CRAN (R 3.6.0)                 
#>  rlang         0.4.0      2019-06-25 [3] CRAN (R 3.6.0)                 
#>  rmarkdown     1.15       2019-08-21 [3] CRAN (R 3.6.1)                 
#>  rprojroot     1.3-2      2018-01-03 [3] CRAN (R 3.6.0)                 
#>  rstudioapi    0.10       2019-03-19 [3] CRAN (R 3.6.0)                 
#>  rvest         0.3.4      2019-05-15 [3] CRAN (R 3.6.0)                 
#>  scales        1.0.0      2018-08-09 [3] CRAN (R 3.6.0)                 
#>  sessioninfo   1.1.1      2018-11-05 [3] CRAN (R 3.6.0)                 
#>  stringi       1.4.3      2019-03-12 [3] CRAN (R 3.6.0)                 
#>  stringr       1.4.0      2019-02-10 [3] CRAN (R 3.6.0)                 
#>  testthat      2.2.1      2019-07-25 [3] CRAN (R 3.6.1)                 
#>  tibble        2.1.3      2019-06-06 [3] CRAN (R 3.6.0)                 
#>  tidyr         1.0.0      2019-09-11 [3] CRAN (R 3.6.1)                 
#>  tidyselect    0.2.5      2018-10-11 [3] CRAN (R 3.6.0)                 
#>  usethis       1.5.1      2019-07-04 [3] CRAN (R 3.6.0)                 
#>  vctrs         0.2.0      2019-07-05 [3] CRAN (R 3.6.0)                 
#>  viridisLite   0.3.0      2018-02-01 [3] CRAN (R 3.6.0)                 
#>  webshot       0.5.1      2018-09-28 [3] CRAN (R 3.6.0)                 
#>  withr         2.1.2      2018-03-15 [3] CRAN (R 3.6.0)                 
#>  xfun          0.9        2019-08-21 [3] CRAN (R 3.6.1)                 
#>  xml2          1.2.2      2019-08-09 [3] CRAN (R 3.6.1)                 
#>  yaml          2.2.0      2018-07-25 [3] CRAN (R 3.6.0)                 
#>  zeallot       0.1.0      2018-01-28 [3] CRAN (R 3.6.0)                 
#> 
#> [1] /tmp/Rtmp8vaOvg/Rinst10c579b5cb6d
#> [2] /tmp/RtmpsgrWgH/temp_libpath7402255995b5
#> [3] /home/wibeasley/R/x86_64-pc-linux-gnu-library/3.6
#> [4] /usr/local/lib/R/site-library
#> [5] /usr/lib/R/site-library
#> [6] /usr/lib/R/library

Report rendered by wibeasley at 2019-09-22, 17:46 -0500 in 2 seconds.