mirror of
https://github.com/agdamsbo/REDCapCAST.git
synced 2024-11-23 13:50:21 +01:00
Compare commits
5 Commits
05c0f35016
...
71e53e5cd6
Author | SHA1 | Date | |
---|---|---|---|
71e53e5cd6 | |||
538c6ee188 | |||
6467cc724b | |||
29cf7b2745 | |||
77989a21ed |
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ logo.R
|
||||
*.DS_Store
|
||||
docs
|
||||
drafting
|
||||
\.DS_Store
|
||||
.DS_Store
|
||||
|
@ -37,7 +37,8 @@ Suggests:
|
||||
styler,
|
||||
devtools,
|
||||
roxygen2,
|
||||
openxlsx2
|
||||
openxlsx2,
|
||||
rsconnect
|
||||
License: GPL (>= 3)
|
||||
Encoding: UTF-8
|
||||
LazyData: true
|
||||
|
177
R/shiny_cast.R
177
R/shiny_cast.R
@ -3,79 +3,9 @@
|
||||
#' @return shiny server
|
||||
#' @export
|
||||
server_factory <- function() {
|
||||
function(input, output, session) {
|
||||
require(REDCapCAST)
|
||||
|
||||
dat <- shiny::reactive({
|
||||
shiny::req(input$ds)
|
||||
|
||||
read_input(input$ds$datapath)
|
||||
})
|
||||
|
||||
dd <- shiny::reactive({
|
||||
ds2dd_detailed(data = dat())
|
||||
})
|
||||
|
||||
|
||||
output$data.tbl <- shiny::renderTable({
|
||||
dd() |>
|
||||
purrr::pluck("data") |>
|
||||
head(20) |>
|
||||
dplyr::tibble()
|
||||
})
|
||||
|
||||
output$meta.tbl <- shiny::renderTable({
|
||||
dd() |>
|
||||
purrr::pluck("meta") |>
|
||||
dplyr::tibble()
|
||||
})
|
||||
|
||||
# Downloadable csv of dataset ----
|
||||
output$downloadData <- shiny::downloadHandler(
|
||||
filename = "data_ready.csv",
|
||||
content = function(file) {
|
||||
write.csv(purrr::pluck(dd(), "data"), file, row.names = FALSE)
|
||||
source(here::here("app/server.R"))
|
||||
server
|
||||
}
|
||||
)
|
||||
|
||||
# Downloadable csv of data dictionary ----
|
||||
output$downloadMeta <- shiny::downloadHandler(
|
||||
filename = "dictionary_ready.csv",
|
||||
content = function(file) {
|
||||
write.csv(purrr::pluck(dd(), "meta"), file, row.names = FALSE)
|
||||
}
|
||||
)
|
||||
output$upload.data.print <- shiny::renderPrint({
|
||||
shiny::eventReactive(input$upload.meta, {
|
||||
shiny::req(input$uri)
|
||||
|
||||
shiny::req(input$api)
|
||||
|
||||
REDCapR::redcap_metadata_write(
|
||||
ds = purrr::pluck(dd(), "meta"),
|
||||
redcap_uri = input$uri,
|
||||
token = input$api
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
output$upload.data.print <- shiny::renderPrint({
|
||||
shiny::eventReactive(input$upload.data, {
|
||||
shiny::req(input$uri)
|
||||
|
||||
shiny::req(input$api)
|
||||
|
||||
REDCapR::redcap_write(
|
||||
ds = purrr::pluck(dd(), "data"),
|
||||
redcap_uri = input$uri,
|
||||
token = input$api
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#' UI factory for shiny app
|
||||
#'
|
||||
@ -83,86 +13,8 @@ server_factory <- function() {
|
||||
#' @export
|
||||
ui_factory <- function() {
|
||||
# require(ggplot2)
|
||||
source(here::here("app/ui.R"))
|
||||
|
||||
shiny::fluidPage(
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Application title
|
||||
## -----------------------------------------------------------------------------
|
||||
shiny::titlePanel("Simple REDCap data base creation and data upload from data set file via API",
|
||||
windowTitle = "REDCap databse creator"
|
||||
),
|
||||
shiny::h5("Please note, that this tool serves as a demonstration of some of the functionality
|
||||
of the REDCapCAST package. No responsibility for data loss or any other
|
||||
problems will be taken."),
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Side panel
|
||||
## -----------------------------------------------------------------------------
|
||||
|
||||
shiny::sidebarPanel(
|
||||
shiny::h4("REDCap database and dataset"),
|
||||
shiny::fileInput("ds", "Choose data file",
|
||||
multiple = FALSE,
|
||||
accept = c(
|
||||
".csv",
|
||||
".xls",
|
||||
".xlsx",
|
||||
".dta"
|
||||
)
|
||||
),
|
||||
shiny::h6("Below you can download the dataset formatted for upload and the
|
||||
corresponding data dictionary for a new data base."),
|
||||
# Button
|
||||
shiny::downloadButton("downloadData", "Download data"),
|
||||
|
||||
# Button
|
||||
shiny::downloadButton("downloadMeta", "Download dictionary"),
|
||||
|
||||
|
||||
# Horizontal line ----
|
||||
shiny::tags$hr(),
|
||||
shiny::h4("REDCap upload"),
|
||||
shiny::textInput(
|
||||
inputId = "uri",
|
||||
label = "URI",
|
||||
value = ""
|
||||
),
|
||||
shiny::textInput(
|
||||
inputId = "api",
|
||||
label = "API key",
|
||||
value = ""
|
||||
),
|
||||
shiny::actionButton(
|
||||
inputId = "upload.meta",
|
||||
label = "Upload dictionary", icon = icon("book-bookmark")
|
||||
),
|
||||
shiny::h6("Please note, that before uploading any real data, put your project
|
||||
into production mode."),
|
||||
shiny::actionButton(
|
||||
inputId = "upload.datata",
|
||||
label = "Upload data", icon = icon("upload")
|
||||
),
|
||||
|
||||
# Horizontal line ----
|
||||
shiny::tags$hr()
|
||||
),
|
||||
shiny::mainPanel(
|
||||
shiny::tabsetPanel(
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Summary tab
|
||||
## -----------------------------------------------------------------------------
|
||||
shiny::tabPanel(
|
||||
"Summary",
|
||||
shiny::h3("Data overview (first 20)"),
|
||||
shiny::htmlOutput("data.tbl", container = span),
|
||||
shiny::h3("Dictionary overview"),
|
||||
shiny::htmlOutput("meta.tbl", container = span)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#' Launch the included Shiny-app for database casting and upload
|
||||
@ -181,3 +33,26 @@ shiny_cast <- function() {
|
||||
server_factory()
|
||||
)
|
||||
}
|
||||
|
||||
#' Deploy the Shiny app with rsconnect
|
||||
#'
|
||||
#' @return deploy
|
||||
#' @export
|
||||
#'
|
||||
#' @examples
|
||||
#' # deploy_shiny
|
||||
#'
|
||||
deploy_shiny <- function(path=here::here("app/"), name.app="shiny_cast"){
|
||||
# Ensure to install latest package version
|
||||
renv::install("agdamsbo/REDCapCAST")
|
||||
|
||||
# Connecting
|
||||
rsconnect::setAccountInfo(
|
||||
name = "cognitiveindex",
|
||||
token = keyring::key_get(service = "rsconnect_cognitiveindex_token"),
|
||||
secret = keyring::key_get(service = "rsconnect_cognitiveindex_secret")
|
||||
)
|
||||
|
||||
# Deploying
|
||||
rsconnect::deployApp(appDir = path,lint = TRUE,appName = name.app,)
|
||||
}
|
||||
|
81
app/server.R
Normal file
81
app/server.R
Normal file
@ -0,0 +1,81 @@
|
||||
server <- function(input, output, session) {
|
||||
require(REDCapCAST)
|
||||
|
||||
dat <- shiny::reactive({
|
||||
shiny::req(input$ds)
|
||||
|
||||
read_input(input$ds$datapath)
|
||||
})
|
||||
|
||||
dd <- shiny::reactive({
|
||||
ds2dd_detailed(data = dat())
|
||||
})
|
||||
|
||||
|
||||
output$data.tbl <- shiny::renderTable({
|
||||
dd() |>
|
||||
purrr::pluck("data") |>
|
||||
head(20) |>
|
||||
dplyr::tibble()
|
||||
})
|
||||
|
||||
output$meta.tbl <- shiny::renderTable({
|
||||
dd() |>
|
||||
purrr::pluck("meta") |>
|
||||
dplyr::tibble()
|
||||
})
|
||||
|
||||
# Downloadable csv of dataset ----
|
||||
output$downloadData <- shiny::downloadHandler(
|
||||
filename = "data_ready.csv",
|
||||
content = function(file) {
|
||||
write.csv(purrr::pluck(dd(), "data"), file, row.names = FALSE)
|
||||
}
|
||||
)
|
||||
|
||||
# Downloadable csv of data dictionary ----
|
||||
output$downloadMeta <- shiny::downloadHandler(
|
||||
filename = "dictionary_ready.csv",
|
||||
content = function(file) {
|
||||
write.csv(purrr::pluck(dd(), "meta"), file, row.names = FALSE)
|
||||
}
|
||||
)
|
||||
|
||||
output_staging <- shiny::reactiveValues()
|
||||
output_staging$meta <- output_staging$data <- NA
|
||||
|
||||
shiny::observeEvent(input$upload.meta,{ upload_meta() })
|
||||
|
||||
shiny::observeEvent(input$upload.data,{ upload_data() })
|
||||
|
||||
upload_meta <- function(){
|
||||
|
||||
shiny::req(input$uri)
|
||||
|
||||
shiny::req(input$api)
|
||||
|
||||
output_staging$meta <- REDCapR::redcap_metadata_write(
|
||||
ds = purrr::pluck(dd(), "meta"),
|
||||
redcap_uri = input$uri,
|
||||
token = input$api
|
||||
)|> purrr::pluck("success")
|
||||
}
|
||||
|
||||
upload_data <- function(){
|
||||
|
||||
shiny::req(input$uri)
|
||||
|
||||
shiny::req(input$api)
|
||||
|
||||
output_staging$data <- REDCapR::redcap_write(
|
||||
ds = purrr::pluck(dd(), "data"),
|
||||
redcap_uri = input$uri,
|
||||
token = input$api
|
||||
) |> purrr::pluck("success")
|
||||
}
|
||||
|
||||
output$upload.meta.print <- renderText(output_staging$meta)
|
||||
|
||||
output$upload.data.print <- renderText(output_staging$data)
|
||||
|
||||
}
|
89
app/ui.R
Normal file
89
app/ui.R
Normal file
@ -0,0 +1,89 @@
|
||||
ui <- shiny::fluidPage(
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Application title
|
||||
## -----------------------------------------------------------------------------
|
||||
shiny::titlePanel("Simple REDCap data base creation and data upload from data set file via API",
|
||||
windowTitle = "REDCap databse creator"
|
||||
),
|
||||
shiny::h5("Please note, that this tool serves as a demonstration of some of the functionality
|
||||
of the REDCapCAST package. No responsibility for data loss or any other
|
||||
problems will be taken."),
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Side panel
|
||||
## -----------------------------------------------------------------------------
|
||||
|
||||
shiny::sidebarPanel(
|
||||
shiny::h4("REDCap database and dataset"),
|
||||
shiny::fileInput("ds", "Choose data file",
|
||||
multiple = FALSE,
|
||||
accept = c(
|
||||
".csv",
|
||||
".xls",
|
||||
".xlsx",
|
||||
".dta"
|
||||
)
|
||||
),
|
||||
shiny::h6("Below you can download the dataset formatted for upload and the
|
||||
corresponding data dictionary for a new data base."),
|
||||
# Button
|
||||
shiny::downloadButton("downloadData", "Download data"),
|
||||
|
||||
# Button
|
||||
shiny::downloadButton("downloadMeta", "Download dictionary"),
|
||||
|
||||
|
||||
# Horizontal line ----
|
||||
shiny::tags$hr(),
|
||||
shiny::h4("REDCap upload"),
|
||||
shiny::textInput(
|
||||
inputId = "uri",
|
||||
label = "URI",
|
||||
value = "https://redcap.au.dk/api/"
|
||||
),
|
||||
shiny::textInput(
|
||||
inputId = "api",
|
||||
label = "API key",
|
||||
value = "21CF2C17EA1CA4F3688DF991C8FE3EBF"
|
||||
),
|
||||
shiny::actionButton(
|
||||
inputId = "upload.meta",
|
||||
label = "Upload dictionary", icon = shiny::icon("book-bookmark")
|
||||
),
|
||||
shiny::h6("Please note, that before uploading any real data, put your project
|
||||
into production mode."),
|
||||
shiny::actionButton(
|
||||
inputId = "upload.data",
|
||||
label = "Upload data", icon = shiny::icon("upload")
|
||||
),
|
||||
|
||||
# Horizontal line ----
|
||||
shiny::tags$hr()
|
||||
),
|
||||
shiny::mainPanel(
|
||||
shiny::tabsetPanel(
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Summary tab
|
||||
## -----------------------------------------------------------------------------
|
||||
shiny::tabPanel(
|
||||
"Summary",
|
||||
shiny::h3("Data overview (first 20)"),
|
||||
shiny::htmlOutput("data.tbl", container = shiny::span),
|
||||
shiny::h3("Dictionary overview"),
|
||||
shiny::htmlOutput("meta.tbl", container = shiny::span)
|
||||
),
|
||||
## -----------------------------------------------------------------------------
|
||||
## Upload tab
|
||||
## -----------------------------------------------------------------------------
|
||||
shiny::tabPanel(
|
||||
"Upload",
|
||||
shiny::h3("Meta upload overview"),
|
||||
shiny::htmlOutput("upload.meta.print", container = shiny::span),
|
||||
shiny::h3("Data upload overview"),
|
||||
shiny::htmlOutput("upload.data.print", container = shiny::span)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
mtcars |> dplyr::mutate(record_id=seq_len(n()),
|
||||
name=rownames(mtcars)
|
||||
) |>
|
||||
dplyr::select(record_id,dplyr::everything()) |>
|
||||
write.csv(here::here("data/mtcars_redcap.csv"),row.names = FALSE)
|
33
data/mtcars_redcap.csv
Normal file
33
data/mtcars_redcap.csv
Normal file
@ -0,0 +1,33 @@
|
||||
"record_id","mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear","carb","name"
|
||||
1,21,6,160,110,3.9,2.62,16.46,0,1,4,4,"Mazda RX4"
|
||||
2,21,6,160,110,3.9,2.875,17.02,0,1,4,4,"Mazda RX4 Wag"
|
||||
3,22.8,4,108,93,3.85,2.32,18.61,1,1,4,1,"Datsun 710"
|
||||
4,21.4,6,258,110,3.08,3.215,19.44,1,0,3,1,"Hornet 4 Drive"
|
||||
5,18.7,8,360,175,3.15,3.44,17.02,0,0,3,2,"Hornet Sportabout"
|
||||
6,18.1,6,225,105,2.76,3.46,20.22,1,0,3,1,"Valiant"
|
||||
7,14.3,8,360,245,3.21,3.57,15.84,0,0,3,4,"Duster 360"
|
||||
8,24.4,4,146.7,62,3.69,3.19,20,1,0,4,2,"Merc 240D"
|
||||
9,22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2,"Merc 230"
|
||||
10,19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4,"Merc 280"
|
||||
11,17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4,"Merc 280C"
|
||||
12,16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3,"Merc 450SE"
|
||||
13,17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3,"Merc 450SL"
|
||||
14,15.2,8,275.8,180,3.07,3.78,18,0,0,3,3,"Merc 450SLC"
|
||||
15,10.4,8,472,205,2.93,5.25,17.98,0,0,3,4,"Cadillac Fleetwood"
|
||||
16,10.4,8,460,215,3,5.424,17.82,0,0,3,4,"Lincoln Continental"
|
||||
17,14.7,8,440,230,3.23,5.345,17.42,0,0,3,4,"Chrysler Imperial"
|
||||
18,32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1,"Fiat 128"
|
||||
19,30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2,"Honda Civic"
|
||||
20,33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1,"Toyota Corolla"
|
||||
21,21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1,"Toyota Corona"
|
||||
22,15.5,8,318,150,2.76,3.52,16.87,0,0,3,2,"Dodge Challenger"
|
||||
23,15.2,8,304,150,3.15,3.435,17.3,0,0,3,2,"AMC Javelin"
|
||||
24,13.3,8,350,245,3.73,3.84,15.41,0,0,3,4,"Camaro Z28"
|
||||
25,19.2,8,400,175,3.08,3.845,17.05,0,0,3,2,"Pontiac Firebird"
|
||||
26,27.3,4,79,66,4.08,1.935,18.9,1,1,4,1,"Fiat X1-9"
|
||||
27,26,4,120.3,91,4.43,2.14,16.7,0,1,5,2,"Porsche 914-2"
|
||||
28,30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2,"Lotus Europa"
|
||||
29,15.8,8,351,264,4.22,3.17,14.5,0,1,5,4,"Ford Pantera L"
|
||||
30,19.7,6,145,175,3.62,2.77,15.5,0,1,5,6,"Ferrari Dino"
|
||||
31,15,8,301,335,3.54,3.57,14.6,0,1,5,8,"Maserati Bora"
|
||||
32,21.4,4,121,109,4.11,2.78,18.6,1,1,4,2,"Volvo 142E"
|
|
@ -428,13 +428,13 @@
|
||||
},
|
||||
"renv": {
|
||||
"Package": "renv",
|
||||
"Version": "1.0.3",
|
||||
"Version": "1.0.4",
|
||||
"Source": "Repository",
|
||||
"Repository": "CRAN",
|
||||
"Requirements": [
|
||||
"utils"
|
||||
],
|
||||
"Hash": "41b847654f567341725473431dd0d5ab"
|
||||
"Hash": "11abaf7c540ff33f94514d50f929bfd1"
|
||||
},
|
||||
"rlang": {
|
||||
"Package": "rlang",
|
||||
|
@ -2,7 +2,7 @@
|
||||
local({
|
||||
|
||||
# the requested version of renv
|
||||
version <- "1.0.3"
|
||||
version <- "1.0.4"
|
||||
attr(version, "sha") <- NULL
|
||||
|
||||
# the project directory
|
||||
@ -31,6 +31,14 @@ local({
|
||||
if (!is.null(override))
|
||||
return(override)
|
||||
|
||||
# if we're being run in a context where R_LIBS is already set,
|
||||
# don't load -- presumably we're being run as a sub-process and
|
||||
# the parent process has already set up library paths for us
|
||||
rcmd <- Sys.getenv("R_CMD", unset = NA)
|
||||
rlibs <- Sys.getenv("R_LIBS", unset = NA)
|
||||
if (!is.na(rlibs) && !is.na(rcmd))
|
||||
return(FALSE)
|
||||
|
||||
# next, check environment variables
|
||||
# TODO: prefer using the configuration one in the future
|
||||
envvars <- c(
|
||||
@ -50,9 +58,22 @@ local({
|
||||
|
||||
})
|
||||
|
||||
if (!enabled)
|
||||
# bail if we're not enabled
|
||||
if (!enabled) {
|
||||
|
||||
# if we're not enabled, we might still need to manually load
|
||||
# the user profile here
|
||||
profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile")
|
||||
if (file.exists(profile)) {
|
||||
cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE")
|
||||
if (tolower(cfg) %in% c("true", "t", "1"))
|
||||
sys.source(profile, envir = globalenv())
|
||||
}
|
||||
|
||||
return(FALSE)
|
||||
|
||||
}
|
||||
|
||||
# avoid recursion
|
||||
if (identical(getOption("renv.autoloader.running"), TRUE)) {
|
||||
warning("ignoring recursive attempt to run renv autoloader")
|
||||
@ -1041,7 +1062,7 @@ local({
|
||||
# if jsonlite is loaded, use that instead
|
||||
if ("jsonlite" %in% loadedNamespaces()) {
|
||||
|
||||
json <- catch(renv_json_read_jsonlite(file, text))
|
||||
json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity)
|
||||
if (!inherits(json, "error"))
|
||||
return(json)
|
||||
|
||||
@ -1050,7 +1071,7 @@ local({
|
||||
}
|
||||
|
||||
# otherwise, fall back to the default JSON reader
|
||||
json <- catch(renv_json_read_default(file, text))
|
||||
json <- tryCatch(renv_json_read_default(file, text), error = identity)
|
||||
if (!inherits(json, "error"))
|
||||
return(json)
|
||||
|
||||
@ -1063,14 +1084,14 @@ local({
|
||||
}
|
||||
|
||||
renv_json_read_jsonlite <- function(file = NULL, text = NULL) {
|
||||
text <- paste(text %||% read(file), collapse = "\n")
|
||||
text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n")
|
||||
jsonlite::fromJSON(txt = text, simplifyVector = FALSE)
|
||||
}
|
||||
|
||||
renv_json_read_default <- function(file = NULL, text = NULL) {
|
||||
|
||||
# find strings in the JSON
|
||||
text <- paste(text %||% read(file), collapse = "\n")
|
||||
text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n")
|
||||
pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
locs <- gregexpr(pattern, text, perl = TRUE)[[1]]
|
||||
|
||||
@ -1118,14 +1139,14 @@ local({
|
||||
map <- as.list(map)
|
||||
|
||||
# remap strings in object
|
||||
remapped <- renv_json_remap(json, map)
|
||||
remapped <- renv_json_read_remap(json, map)
|
||||
|
||||
# evaluate
|
||||
eval(remapped, envir = baseenv())
|
||||
|
||||
}
|
||||
|
||||
renv_json_remap <- function(json, map) {
|
||||
renv_json_read_remap <- function(json, map) {
|
||||
|
||||
# fix names
|
||||
if (!is.null(names(json))) {
|
||||
@ -1152,7 +1173,7 @@ local({
|
||||
# recurse
|
||||
if (is.recursive(json)) {
|
||||
for (i in seq_along(json)) {
|
||||
json[i] <- list(renv_json_remap(json[[i]], map))
|
||||
json[i] <- list(renv_json_read_remap(json[[i]], map))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user