2024-12-09 14:00:44 +01:00
|
|
|
library(readr)
|
|
|
|
library(MASS)
|
|
|
|
library(stats)
|
|
|
|
library(gtsummary)
|
|
|
|
library(gt)
|
|
|
|
library(openxlsx2)
|
|
|
|
library(haven)
|
|
|
|
library(readODS)
|
2024-12-17 11:44:01 +01:00
|
|
|
require(shiny)
|
2024-12-09 14:00:44 +01:00
|
|
|
library(bslib)
|
|
|
|
library(assertthat)
|
|
|
|
library(dplyr)
|
|
|
|
library(quarto)
|
|
|
|
library(here)
|
|
|
|
library(broom)
|
|
|
|
library(broom.helpers)
|
2024-12-19 15:26:23 +01:00
|
|
|
# library(REDCapCAST)
|
2024-12-09 14:00:44 +01:00
|
|
|
library(easystats)
|
|
|
|
library(patchwork)
|
|
|
|
library(DHARMa)
|
2025-01-15 16:21:38 +01:00
|
|
|
library(apexcharter)
|
2024-12-13 13:37:19 +01:00
|
|
|
library(toastui)
|
2025-01-15 16:21:38 +01:00
|
|
|
library(datamods)
|
|
|
|
library(data.table)
|
2024-12-13 13:37:19 +01:00
|
|
|
library(IDEAFilter)
|
2024-12-17 11:44:01 +01:00
|
|
|
library(shinyWidgets)
|
|
|
|
library(DT)
|
2024-12-19 15:26:23 +01:00
|
|
|
# library(freesearcheR)
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2024-12-18 10:37:37 +01:00
|
|
|
# source("functions.R")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# light <- custom_theme()
|
|
|
|
#
|
2024-12-19 11:34:25 +01:00
|
|
|
# dark <- custom_theme(bg = "#000",fg="#fff")
|
2024-12-18 10:37:37 +01:00
|
|
|
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
server <- function(input, output, session) {
|
|
|
|
## Listing files in www in session start to keep when ending and removing
|
|
|
|
## everything else.
|
|
|
|
files.to.keep <- list.files("www/")
|
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
output$docs_file <- shiny::renderUI({
|
2024-12-19 11:34:25 +01:00
|
|
|
# shiny::includeHTML("www/docs.html")
|
2025-01-15 16:21:38 +01:00
|
|
|
shiny::HTML(readLines("www/docs.html"))
|
2024-12-19 11:34:25 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Night mode (just very popular, not really needed)
|
|
|
|
#########
|
|
|
|
##############################################################################
|
|
|
|
|
2024-12-18 10:37:37 +01:00
|
|
|
# observeEvent(input$dark_mode,{
|
|
|
|
# session$setCurrentTheme(
|
|
|
|
# if (isTRUE(input$dark_mode)) dark else light
|
|
|
|
# )})
|
|
|
|
|
2024-12-19 11:34:25 +01:00
|
|
|
# observe({
|
|
|
|
# if(input$dark_mode==TRUE)
|
|
|
|
# session$setCurrentTheme(bs_theme_update(theme = custom_theme(version = 5)))
|
|
|
|
# if(input$dark_mode==FALSE)
|
|
|
|
# session$setCurrentTheme(bs_theme_update(theme = custom_theme(version = 5, bg = "#000",fg="#fff")))
|
|
|
|
# })
|
|
|
|
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Setting reactive values
|
|
|
|
#########
|
|
|
|
##############################################################################
|
2024-12-17 11:30:17 +01:00
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
rv <- shiny::reactiveValues(
|
2024-12-18 15:46:02 +01:00
|
|
|
list = list(),
|
2024-12-09 14:00:44 +01:00
|
|
|
ds = NULL,
|
|
|
|
local_temp = NULL,
|
2024-12-18 11:26:00 +01:00
|
|
|
ready = NULL,
|
2024-12-13 13:37:19 +01:00
|
|
|
test = "no",
|
2024-12-16 22:21:54 +01:00
|
|
|
data_original = NULL,
|
|
|
|
data = NULL,
|
2025-01-17 15:59:24 +01:00
|
|
|
data_filtered = NULL,
|
|
|
|
models = NULL,
|
|
|
|
check = NULL
|
2024-12-09 14:00:44 +01:00
|
|
|
)
|
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Data import section
|
|
|
|
#########
|
|
|
|
##############################################################################
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
data_file <- datamods::import_file_server(
|
|
|
|
id = "file_import",
|
|
|
|
show_data_in = "popup",
|
2024-12-13 13:37:19 +01:00
|
|
|
trigger_return = "change",
|
2024-12-09 14:00:44 +01:00
|
|
|
return_class = "data.frame",
|
|
|
|
read_fns = list(
|
|
|
|
ods = function(file) {
|
|
|
|
readODS::read_ods(path = file)
|
|
|
|
},
|
|
|
|
dta = function(file) {
|
|
|
|
haven::read_dta(file = file)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
shiny::observeEvent(data_file$data(), {
|
|
|
|
shiny::req(data_file$data())
|
|
|
|
rv$data_original <- data_file$data()
|
|
|
|
})
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
data_redcap <- m_redcap_readServer(
|
|
|
|
id = "redcap_import",
|
|
|
|
output.format = "list"
|
|
|
|
)
|
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
shiny::observeEvent(data_redcap(), {
|
|
|
|
rv$data_original <- purrr::pluck(data_redcap(), "data")()
|
|
|
|
})
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
output$redcap_prev <- DT::renderDT(
|
|
|
|
{
|
2024-12-13 13:37:19 +01:00
|
|
|
DT::datatable(head(purrr::pluck(data_redcap(), "data")(), 5),
|
2024-12-09 14:00:44 +01:00
|
|
|
caption = "First 5 observations"
|
|
|
|
)
|
|
|
|
},
|
|
|
|
server = TRUE
|
|
|
|
)
|
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
from_env <- import_globalenv_server(
|
|
|
|
id = "env",
|
|
|
|
trigger_return = "change",
|
|
|
|
btn_show_data = FALSE,
|
|
|
|
reset = reactive(input$hidden)
|
|
|
|
)
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
shiny::observeEvent(from_env$data(), {
|
|
|
|
shiny::req(from_env$data())
|
|
|
|
rv$data_original <- from_env$data()
|
|
|
|
})
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
|
2024-12-13 13:37:19 +01:00
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Data modification section
|
|
|
|
#########
|
|
|
|
##############################################################################
|
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
shiny::observeEvent(rv$data_original, {
|
|
|
|
rv$data <- rv$data_original |> default_parsing()
|
|
|
|
})
|
|
|
|
|
|
|
|
shiny::observeEvent(input$data_reset, {
|
|
|
|
shinyWidgets::ask_confirmation(
|
|
|
|
inputId = "reset_confirm",
|
|
|
|
title = "Please confirm data reset?"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
shiny::observeEvent(input$reset_confirm, {
|
|
|
|
rv$data <- rv$data_original |> default_parsing()
|
|
|
|
})
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
######### Overview
|
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
data_summary_server(
|
|
|
|
id = "data_summary",
|
|
|
|
data = shiny::reactive({
|
|
|
|
rv$data_filtered
|
|
|
|
}),
|
|
|
|
color.main = "#2A004E",
|
|
|
|
color.sec = "#C62300"
|
2025-01-15 16:21:38 +01:00
|
|
|
)
|
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
#########
|
2025-01-15 16:21:38 +01:00
|
|
|
######### Modifications
|
2025-01-16 11:24:26 +01:00
|
|
|
#########
|
2025-01-15 16:21:38 +01:00
|
|
|
|
2024-12-13 13:37:19 +01:00
|
|
|
## Using modified version of the datamods::cut_variable_server function
|
|
|
|
## Further modifications are needed to have cut/bin options based on class of variable
|
|
|
|
## Could be defined server-side
|
2025-01-16 11:24:26 +01:00
|
|
|
|
|
|
|
######### Create factor
|
|
|
|
|
|
|
|
shiny::observeEvent(
|
|
|
|
input$modal_cut,
|
|
|
|
modal_cut_variable("modal_cut")
|
|
|
|
)
|
2024-12-13 13:37:19 +01:00
|
|
|
data_modal_cut <- cut_variable_server(
|
|
|
|
id = "modal_cut",
|
2024-12-16 22:21:54 +01:00
|
|
|
data_r = shiny::reactive(rv$data)
|
2024-12-13 13:37:19 +01:00
|
|
|
)
|
2024-12-16 22:21:54 +01:00
|
|
|
shiny::observeEvent(data_modal_cut(), rv$data <- data_modal_cut())
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
######### Modify factor
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
shiny::observeEvent(
|
|
|
|
input$modal_update,
|
|
|
|
datamods::modal_update_factor(id = "modal_update")
|
|
|
|
)
|
2024-12-13 13:37:19 +01:00
|
|
|
data_modal_update <- datamods::update_factor_server(
|
|
|
|
id = "modal_update",
|
|
|
|
data_r = reactive(rv$data)
|
|
|
|
)
|
2024-12-16 22:21:54 +01:00
|
|
|
shiny::observeEvent(data_modal_update(), {
|
2024-12-13 13:37:19 +01:00
|
|
|
shiny::removeModal()
|
|
|
|
rv$data <- data_modal_update()
|
|
|
|
})
|
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
######### Create column
|
|
|
|
|
|
|
|
shiny::observeEvent(
|
|
|
|
input$modal_column,
|
|
|
|
datamods::modal_create_column(id = "modal_column")
|
|
|
|
)
|
|
|
|
data_modal_r <- datamods::create_column_server(
|
|
|
|
id = "modal_column",
|
|
|
|
data_r = reactive(rv$data)
|
|
|
|
)
|
|
|
|
shiny::observeEvent(data_modal_r(), rv$data <- data_modal_r())
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2025-01-16 11:24:26 +01:00
|
|
|
######### Show result
|
2024-12-13 13:37:19 +01:00
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
output$table_mod <- toastui::renderDatagrid({
|
|
|
|
shiny::req(rv$data)
|
2024-12-13 13:37:19 +01:00
|
|
|
# data <- rv$data
|
|
|
|
toastui::datagrid(
|
2024-12-16 22:21:54 +01:00
|
|
|
# data = rv$data # ,
|
|
|
|
data = data_filter()
|
2024-12-13 13:37:19 +01:00
|
|
|
# bordered = TRUE,
|
|
|
|
# compact = TRUE,
|
|
|
|
# striped = TRUE
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
output$code <- renderPrint({
|
|
|
|
attr(rv$data, "code")
|
|
|
|
})
|
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
# updated_data <- datamods::update_variables_server(
|
2025-01-16 11:24:26 +01:00
|
|
|
updated_data <- update_variables_server(
|
2024-12-13 13:37:19 +01:00
|
|
|
id = "vars_update",
|
|
|
|
data = reactive(rv$data),
|
|
|
|
return_data_on_init = FALSE
|
|
|
|
)
|
|
|
|
|
|
|
|
output$original_str <- renderPrint({
|
2024-12-17 11:30:17 +01:00
|
|
|
str(rv$data_original)
|
2024-12-13 13:37:19 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
output$modified_str <- renderPrint({
|
2025-01-16 11:24:26 +01:00
|
|
|
str(as.data.frame(rv$data_filtered) |>
|
|
|
|
REDCapCAST::set_attr(
|
|
|
|
label = NULL,
|
|
|
|
attr = "code"
|
|
|
|
))
|
2024-12-13 13:37:19 +01:00
|
|
|
})
|
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
shiny::observeEvent(updated_data(), {
|
2024-12-13 13:37:19 +01:00
|
|
|
rv$data <- updated_data()
|
|
|
|
})
|
|
|
|
|
|
|
|
# IDEAFilter has the least cluttered UI, but might have a License issue
|
|
|
|
data_filter <- IDEAFilter::IDEAFilter("data_filter", data = reactive(rv$data), verbose = TRUE)
|
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
shiny::observeEvent(
|
|
|
|
list(
|
|
|
|
shiny::reactive(rv$data),
|
|
|
|
shiny::reactive(rv$data_original),
|
|
|
|
data_filter(),
|
|
|
|
base_vars()
|
|
|
|
), {
|
2025-01-16 11:24:26 +01:00
|
|
|
rv$data_filtered <- data_filter()
|
2025-01-17 15:59:24 +01:00
|
|
|
|
|
|
|
rv$list$data <- data_filter() |>
|
|
|
|
REDCapCAST::fct_drop.data.frame() |>
|
|
|
|
(\(.x){
|
|
|
|
.x[base_vars()]
|
|
|
|
})()
|
2025-01-16 11:24:26 +01:00
|
|
|
})
|
2024-12-13 13:37:19 +01:00
|
|
|
|
|
|
|
output$filtered_code <- shiny::renderPrint({
|
2025-01-16 11:24:26 +01:00
|
|
|
out <- gsub(
|
|
|
|
"filter", "dplyr::filter",
|
2024-12-16 22:21:54 +01:00
|
|
|
gsub(
|
|
|
|
"\\s{2,}", " ",
|
2025-01-16 11:24:26 +01:00
|
|
|
paste0(
|
|
|
|
capture.output(attr(rv$data_filtered, "code")),
|
|
|
|
collapse = " "
|
2024-12-16 22:21:54 +01:00
|
|
|
)
|
|
|
|
)
|
2025-01-16 11:24:26 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
out <- strsplit(out, "%>%") |>
|
|
|
|
unlist() |>
|
|
|
|
(\(.x){
|
|
|
|
paste(c("data", .x[-1]), collapse = "|> \n ")
|
|
|
|
})()
|
|
|
|
|
|
|
|
cat(out)
|
2024-12-13 13:37:19 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Data analyses section
|
|
|
|
#########
|
|
|
|
##############################################################################
|
|
|
|
|
|
|
|
## Keep these "old" selection options as a simple alternative to the modification pane
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
output$include_vars <- shiny::renderUI({
|
2024-12-13 13:37:19 +01:00
|
|
|
shiny::selectizeInput(
|
2024-12-09 14:00:44 +01:00
|
|
|
inputId = "include_vars",
|
|
|
|
selected = NULL,
|
|
|
|
label = "Covariables to include",
|
2025-01-16 11:24:26 +01:00
|
|
|
choices = colnames(rv$data_filtered),
|
2024-12-09 14:00:44 +01:00
|
|
|
multiple = TRUE
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
output$outcome_var <- shiny::renderUI({
|
2024-12-13 13:37:19 +01:00
|
|
|
shiny::selectInput(
|
2024-12-09 14:00:44 +01:00
|
|
|
inputId = "outcome_var",
|
|
|
|
selected = NULL,
|
|
|
|
label = "Select outcome variable",
|
2025-01-16 11:24:26 +01:00
|
|
|
choices = colnames(rv$data_filtered),
|
2024-12-09 14:00:44 +01:00
|
|
|
multiple = FALSE
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
output$regression_type <- shiny::renderUI({
|
|
|
|
shiny::req(input$outcome_var)
|
|
|
|
shiny::selectizeInput(
|
|
|
|
inputId = "regression_type",
|
|
|
|
# selected = colnames(rv$data_filtered)[sapply(rv$data_filtered, is.factor)],
|
|
|
|
label = "Choose regression analysis",
|
|
|
|
choices = possible_functions(data = dplyr::select(rv$data_filtered, input$outcome_var), design = "cross-sectional"),
|
|
|
|
multiple = FALSE
|
|
|
|
)
|
|
|
|
})
|
2024-12-09 14:00:44 +01:00
|
|
|
|
|
|
|
output$factor_vars <- shiny::renderUI({
|
2024-12-13 13:37:19 +01:00
|
|
|
shiny::selectizeInput(
|
2024-12-09 14:00:44 +01:00
|
|
|
inputId = "factor_vars",
|
2025-01-16 11:24:26 +01:00
|
|
|
selected = colnames(rv$data_filtered)[sapply(rv$data_filtered, is.factor)],
|
2024-12-09 14:00:44 +01:00
|
|
|
label = "Covariables to format as categorical",
|
2025-01-16 11:24:26 +01:00
|
|
|
choices = colnames(rv$data_filtered),
|
2024-12-09 14:00:44 +01:00
|
|
|
multiple = TRUE
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
base_vars <- shiny::reactive({
|
|
|
|
if (is.null(input$include_vars)) {
|
2025-01-16 11:24:26 +01:00
|
|
|
out <- colnames(rv$data_filtered)
|
2024-12-09 14:00:44 +01:00
|
|
|
} else {
|
|
|
|
out <- unique(c(input$include_vars, input$outcome_var))
|
|
|
|
}
|
|
|
|
return(out)
|
|
|
|
})
|
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
output$strat_var <- shiny::renderUI({
|
|
|
|
shiny::selectInput(
|
|
|
|
inputId = "strat_var",
|
|
|
|
selected = "none",
|
|
|
|
label = "Select variable to stratify baseline",
|
2025-01-16 11:24:26 +01:00
|
|
|
choices = c(
|
|
|
|
"none",
|
|
|
|
rv$data_filtered[base_vars()] |>
|
|
|
|
(\(.x){
|
|
|
|
lapply(.x, \(.c){
|
|
|
|
if (identical("factor", class(.c))) {
|
|
|
|
.c
|
|
|
|
}
|
|
|
|
}) |>
|
|
|
|
dplyr::bind_cols()
|
|
|
|
})() |>
|
|
|
|
colnames()
|
|
|
|
),
|
2024-12-16 22:21:54 +01:00
|
|
|
multiple = FALSE
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
## Have a look at column filters at some point
|
|
|
|
## There should be a way to use the filtering the filter data for further analyses
|
|
|
|
## Disabled for now, as the JS is apparently not isolated
|
2024-12-17 11:30:17 +01:00
|
|
|
# output$data_table <-
|
|
|
|
# DT::renderDT(
|
|
|
|
# {
|
|
|
|
# DT::datatable(ds()[base_vars()])
|
|
|
|
# },
|
|
|
|
# server = FALSE
|
|
|
|
# )
|
|
|
|
#
|
|
|
|
# output$data.classes <- gt::render_gt({
|
|
|
|
# shiny::req(input$file)
|
|
|
|
# data.frame(matrix(sapply(ds(), \(.x){
|
|
|
|
# class(.x)[1]
|
|
|
|
# }), nrow = 1)) |>
|
|
|
|
# stats::setNames(names(ds())) |>
|
|
|
|
# gt::gt()
|
|
|
|
# })
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
|
|
|
|
### Outputs
|
|
|
|
|
|
|
|
# shiny::observeEvent(data_filter(), {
|
|
|
|
# rv$data_filtered <- data_filter()
|
|
|
|
# })
|
|
|
|
|
|
|
|
# shiny::observeEvent(
|
|
|
|
# shiny::reactive(rv$data_filtered),
|
|
|
|
# {
|
|
|
|
# rv$list$data <- rv$data_filtered |>
|
|
|
|
# # dplyr::mutate(dplyr::across(dplyr::where(is.character), as.factor)) |>
|
|
|
|
# REDCapCAST::fct_drop.data.frame() |>
|
|
|
|
# # factorize(vars = input$factor_vars) |>
|
|
|
|
# remove_na_attr()
|
|
|
|
#
|
|
|
|
# # rv$list$data <- data
|
|
|
|
# # rv$list$data <- data[base_vars()]
|
|
|
|
# }
|
|
|
|
# )
|
|
|
|
|
|
|
|
# shiny::observe({
|
|
|
|
# if (input$strat_var == "none") {
|
|
|
|
# by.var <- NULL
|
|
|
|
# } else {
|
|
|
|
# by.var <- input$strat_var
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# rv$list$table1 <- rv$list$data |>
|
|
|
|
# baseline_table(
|
|
|
|
# fun.args =
|
|
|
|
# list(
|
|
|
|
# by = by.var
|
|
|
|
# )
|
|
|
|
# ) |>
|
|
|
|
# (\(.x){
|
|
|
|
# if (!is.null(by.var)) {
|
|
|
|
# .x |> gtsummary::add_overall()
|
|
|
|
# } else {
|
|
|
|
# .x
|
|
|
|
# }
|
|
|
|
# })() |>
|
|
|
|
# (\(.x){
|
|
|
|
# if (input$add_p == "yes") {
|
|
|
|
# .x |>
|
|
|
|
# gtsummary::add_p() |>
|
|
|
|
# gtsummary::bold_p()
|
|
|
|
# } else {
|
|
|
|
# .x
|
|
|
|
# }
|
|
|
|
# })()
|
|
|
|
# })
|
|
|
|
#
|
|
|
|
# output$table1 <- gt::render_gt(
|
|
|
|
# rv$list$table1 |>
|
|
|
|
# gtsummary::as_gt() |>
|
|
|
|
# gt::tab_header(shiny::md("**Table 1. Patient Characteristics**"))
|
|
|
|
# )
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
shiny::observeEvent(
|
2025-01-17 15:59:24 +01:00
|
|
|
# ignoreInit = TRUE,
|
|
|
|
list(
|
|
|
|
shiny::reactive(rv$list$data),
|
|
|
|
shiny::reactive(rv$data),
|
|
|
|
input$strat_var,
|
|
|
|
input$include_vars,
|
|
|
|
input$add_p
|
|
|
|
),
|
2024-12-09 14:00:44 +01:00
|
|
|
{
|
2025-01-17 15:59:24 +01:00
|
|
|
shiny::req(input$strat_var)
|
|
|
|
shiny::req(rv$list$data)
|
|
|
|
|
|
|
|
if (input$strat_var == "none") {
|
|
|
|
by.var <- NULL
|
|
|
|
} else {
|
|
|
|
by.var <- input$strat_var
|
|
|
|
}
|
|
|
|
|
|
|
|
rv$list$table1 <-
|
|
|
|
rv$list$data |>
|
|
|
|
baseline_table(
|
|
|
|
fun.args =
|
|
|
|
list(
|
|
|
|
by = by.var
|
|
|
|
)
|
|
|
|
) |>
|
|
|
|
(\(.x){
|
|
|
|
if (!is.null(by.var)) {
|
|
|
|
.x |> gtsummary::add_overall()
|
|
|
|
} else {
|
|
|
|
.x
|
|
|
|
}
|
|
|
|
})() |>
|
|
|
|
(\(.x){
|
|
|
|
if (input$add_p == "yes") {
|
|
|
|
.x |>
|
|
|
|
gtsummary::add_p() |>
|
|
|
|
gtsummary::bold_p()
|
|
|
|
} else {
|
|
|
|
.x
|
|
|
|
}
|
|
|
|
})()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
output$table1 <- gt::render_gt({
|
|
|
|
shiny::req(rv$list$table1)
|
|
|
|
|
|
|
|
rv$list$table1 |>
|
|
|
|
gtsummary::as_gt() |>
|
|
|
|
gt::tab_header(gt::md("**Table 1: Baseline Characteristics**"))
|
|
|
|
})
|
|
|
|
|
|
|
|
shiny::observeEvent(
|
|
|
|
input$load,
|
2024-12-09 14:00:44 +01:00
|
|
|
{
|
|
|
|
shiny::req(input$outcome_var)
|
2024-12-13 13:37:19 +01:00
|
|
|
# browser()
|
2024-12-09 14:00:44 +01:00
|
|
|
# Assumes all character variables can be formatted as factors
|
2024-12-13 13:37:19 +01:00
|
|
|
# data <- data_filter$filtered() |>
|
2024-12-18 15:46:02 +01:00
|
|
|
tryCatch(
|
|
|
|
{
|
2025-01-17 15:59:24 +01:00
|
|
|
model_lists <- list(
|
|
|
|
"Univariable" = regression_model_uv_list,
|
|
|
|
"Multivariable" = regression_model_list
|
2024-12-09 14:00:44 +01:00
|
|
|
) |>
|
2024-12-18 15:46:02 +01:00
|
|
|
lapply(\(.fun){
|
2025-01-17 15:59:24 +01:00
|
|
|
ls <- do.call(
|
2024-12-18 15:46:02 +01:00
|
|
|
.fun,
|
|
|
|
c(
|
2025-01-17 15:59:24 +01:00
|
|
|
list(data = rv$list$data),
|
2024-12-18 15:46:02 +01:00
|
|
|
list(outcome.str = input$outcome_var),
|
2025-01-17 15:59:24 +01:00
|
|
|
list(fun.descr = input$regression_type)
|
2024-12-18 15:46:02 +01:00
|
|
|
)
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
rv$models <- model_lists
|
2024-12-18 15:46:02 +01:00
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
# rv$models <- lapply(model_lists, \(.x){
|
|
|
|
# .x$model
|
|
|
|
# })
|
|
|
|
},
|
|
|
|
warning = function(warn) {
|
|
|
|
showNotification(paste0(warn), type = "warning")
|
|
|
|
},
|
|
|
|
error = function(err) {
|
|
|
|
showNotification(paste0("Creating regression models failed with the following error: ", err), type = "err")
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
2024-12-18 15:46:02 +01:00
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
shiny::observeEvent(
|
|
|
|
ignoreInit = TRUE,
|
|
|
|
list(
|
|
|
|
rv$models
|
|
|
|
),
|
|
|
|
{
|
|
|
|
shiny::req(rv$models)
|
|
|
|
tryCatch(
|
|
|
|
{
|
|
|
|
rv$check <- lapply(rv$models, \(.x){
|
|
|
|
.x$model
|
|
|
|
}) |>
|
|
|
|
purrr::pluck("Multivariable") |>
|
2024-12-18 15:46:02 +01:00
|
|
|
performance::check_model()
|
2025-01-17 15:59:24 +01:00
|
|
|
},
|
|
|
|
warning = function(warn) {
|
|
|
|
showNotification(paste0(warn), type = "warning")
|
|
|
|
},
|
|
|
|
error = function(err) {
|
|
|
|
showNotification(paste0("Running model assumptions checks failed with the following error: ", err), type = "err")
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
2024-12-18 15:46:02 +01:00
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
output$check <- shiny::renderPlot({
|
|
|
|
shiny::req(rv$check)
|
|
|
|
p <- plot(rv$check) +
|
|
|
|
patchwork::plot_annotation(title = "Multivariable regression model checks")
|
|
|
|
p
|
|
|
|
# Generate checks in one column
|
|
|
|
# layout <- sapply(seq_len(length(p)), \(.x){
|
|
|
|
# patchwork::area(.x, 1)
|
|
|
|
# })
|
|
|
|
#
|
|
|
|
# p + patchwork::plot_layout(design = Reduce(c, layout))
|
|
|
|
|
|
|
|
# patchwork::wrap_plots(ncol=1) +
|
|
|
|
# patchwork::plot_annotation(title = 'Multivariable regression model checks')
|
|
|
|
})
|
2024-12-18 15:46:02 +01:00
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
|
|
|
|
shiny::observeEvent(
|
|
|
|
input$load,
|
|
|
|
{
|
|
|
|
shiny::req(rv$models)
|
|
|
|
# browser()
|
|
|
|
# Assumes all character variables can be formatted as factors
|
|
|
|
# data <- data_filter$filtered() |>
|
|
|
|
tryCatch(
|
|
|
|
{
|
|
|
|
tbl <- lapply(rv$models, \(.x){
|
|
|
|
.x$model
|
|
|
|
}) |>
|
2024-12-18 15:46:02 +01:00
|
|
|
purrr::map(regression_table) |>
|
|
|
|
tbl_merge()
|
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
rv$list$regression <- c(
|
|
|
|
rv$models,
|
|
|
|
list(Table = tbl)
|
2024-12-18 15:46:02 +01:00
|
|
|
)
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
rv$list$input <- input
|
2024-12-18 15:46:02 +01:00
|
|
|
},
|
|
|
|
warning = function(warn) {
|
|
|
|
showNotification(paste0(warn), type = "warning")
|
|
|
|
},
|
|
|
|
error = function(err) {
|
2025-01-17 15:59:24 +01:00
|
|
|
showNotification(paste0("Creating a regression table failed with the following error: ", err), type = "err")
|
2024-12-18 15:46:02 +01:00
|
|
|
}
|
2024-12-09 14:00:44 +01:00
|
|
|
)
|
2024-12-18 15:46:02 +01:00
|
|
|
rv$ready <- "ready"
|
2024-12-09 14:00:44 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2025-01-17 15:59:24 +01:00
|
|
|
output$table2 <- gt::render_gt({
|
|
|
|
shiny::req(rv$list$regression$Table)
|
|
|
|
rv$list$regression$Table |>
|
|
|
|
gtsummary::as_gt() |>
|
|
|
|
gt::tab_header(gt::md(glue::glue("**Table 2: {rv$list$regression$Multivariable$options$descr}**")))
|
|
|
|
})
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
shiny::conditionalPanel(
|
|
|
|
condition = "output.uploaded == 'yes'",
|
|
|
|
)
|
|
|
|
|
|
|
|
# observeEvent(input$act_start, {
|
|
|
|
# nav_show(id = "overview",target = "Import"
|
|
|
|
# )
|
|
|
|
# })
|
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Page navigation
|
|
|
|
#########
|
|
|
|
##############################################################################
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
shiny::observeEvent(input$act_start, {
|
2025-01-16 14:24:38 +01:00
|
|
|
bslib::nav_select(id = "main_panel", selected = "Data")
|
2025-01-15 16:21:38 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Reactivity
|
|
|
|
#########
|
|
|
|
##############################################################################
|
2024-12-09 14:00:44 +01:00
|
|
|
|
|
|
|
output$uploaded <- shiny::reactive({
|
2024-12-16 22:21:54 +01:00
|
|
|
if (is.null(rv$ds)) {
|
2024-12-09 14:00:44 +01:00
|
|
|
"no"
|
|
|
|
} else {
|
|
|
|
"yes"
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
shiny::outputOptions(output, "uploaded", suspendWhenHidden = FALSE)
|
|
|
|
|
2024-12-18 11:26:00 +01:00
|
|
|
output$ready <- shiny::reactive({
|
|
|
|
if (is.null(rv$ready)) {
|
|
|
|
"no"
|
|
|
|
} else {
|
|
|
|
"yes"
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
shiny::outputOptions(output, "ready", suspendWhenHidden = FALSE)
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2024-12-16 22:21:54 +01:00
|
|
|
# Reimplement from environment at later time
|
|
|
|
# output$has_input <- shiny::reactive({
|
|
|
|
# if (rv$input) {
|
|
|
|
# "yes"
|
|
|
|
# } else {
|
|
|
|
# "no"
|
|
|
|
# }
|
|
|
|
# })
|
|
|
|
|
|
|
|
# shiny::outputOptions(output, "has_input", suspendWhenHidden = FALSE)
|
2024-12-09 14:00:44 +01:00
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Downloads
|
|
|
|
#########
|
|
|
|
##############################################################################
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
# Could be rendered with other tables or should show progress
|
|
|
|
# Investigate quarto render problems
|
|
|
|
# On temp file handling: https://github.com/quarto-dev/quarto-cli/issues/3992
|
|
|
|
output$report <- downloadHandler(
|
|
|
|
filename = shiny::reactive({
|
|
|
|
paste0("report.", input$output_type)
|
|
|
|
}),
|
|
|
|
content = function(file, type = input$output_type) {
|
2025-01-17 15:59:24 +01:00
|
|
|
shiny::req(rv$list$regression)
|
2024-12-09 14:00:44 +01:00
|
|
|
## Notification is not progressing
|
|
|
|
## Presumably due to missing
|
2024-12-18 11:26:00 +01:00
|
|
|
shiny::withProgress(message = "Generating the report. Hold on for a moment..", {
|
2024-12-16 22:21:54 +01:00
|
|
|
rv$list |>
|
2024-12-09 14:00:44 +01:00
|
|
|
write_quarto(
|
|
|
|
output_format = type,
|
|
|
|
input = file.path(getwd(), "www/report.qmd")
|
|
|
|
)
|
|
|
|
})
|
|
|
|
file.rename(paste0("www/report.", type), file)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2025-01-15 16:21:38 +01:00
|
|
|
output$data_modified <- downloadHandler(
|
|
|
|
filename = shiny::reactive({
|
|
|
|
paste0("modified_data.", input$data_type)
|
|
|
|
}),
|
|
|
|
content = function(file, type = input$data_type) {
|
2025-01-16 11:24:26 +01:00
|
|
|
if (type == "rds") {
|
|
|
|
readr::write_rds(rv$list$data, file = file)
|
2025-01-15 16:21:38 +01:00
|
|
|
} else {
|
2025-01-16 11:24:26 +01:00
|
|
|
haven::write_dta(as.data.frame(rv$list$data), path = file)
|
2025-01-15 16:21:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
#########
|
|
|
|
######### Clearing the session on end
|
|
|
|
#########
|
|
|
|
##############################################################################
|
|
|
|
|
2024-12-09 14:00:44 +01:00
|
|
|
session$onSessionEnded(function() {
|
|
|
|
cat("Session Ended\n")
|
|
|
|
files <- list.files("www/")
|
|
|
|
lapply(files[!files %in% files.to.keep], \(.x){
|
|
|
|
unlink(paste0("www/", .x), recursive = FALSE)
|
|
|
|
print(paste(.x, "deleted"))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|