diff --git a/CITATION.cff b/CITATION.cff index 419ad2b8..29039358 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -9,7 +9,7 @@ type: software license: AGPL-3.0-or-later title: 'FreesearchR: A free and open-source browser based data analysis tool for researchers with publication ready output' -version: 25.6.2 +version: 25.6.1 doi: 10.5281/zenodo.14527429 identifiers: - type: url diff --git a/DESCRIPTION b/DESCRIPTION index cebd5484..5c9b2489 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: FreesearchR Title: A free and open-source browser based data analysis tool for researchers with publication ready output -Version: 25.6.3 +Version: 25.6.1 Authors@R: c( person("Andreas Gammelgaard", "Damsbo",email="agdamsbo@clin.au.dk", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-7559-1154")), @@ -64,8 +64,7 @@ Imports: RcppArmadillo, ggcorrplot, shinyjs, - emmeans, - visdat + emmeans Suggests: styler, devtools, diff --git a/NAMESPACE b/NAMESPACE index 5419ce5a..8e8a7a23 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -30,8 +30,6 @@ export(cut_variable_ui) export(data_correlations_server) export(data_correlations_ui) export(data_description) -export(data_missings_server) -export(data_missings_ui) export(data_summary_server) export(data_summary_ui) export(data_type) diff --git a/NEWS.md b/NEWS.md index 2b9c1524..05d0347f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,17 +1,3 @@ -# FreesearchR 25.6.3 - -- *NEW* First go at introducing more options to evaluate missings. Also reworded the text on the initial filter to only include variables missings less than the given threshold. - -# FreesearchR 25.6.2 - -- *FIX* Added warning about only using REDCap with sensitive data running locally. THis applies to all data actually. Considering taking REDCap out in hosted version. Standalone app is in the works. - -- *FIX* Reworded the completeness filter to be on missingness, as this is a more commonly used concept. - -- *FIX* Improved layout around data filters to improve usage. - -- *FIX* Regression table in report respects inclusion of p-values or not. - # FreesearchR 25.6.1 - *FIX* big not allowing to browse data diff --git a/R/app_version.R b/R/app_version.R index 440e842f..e81f97f3 100644 --- a/R/app_version.R +++ b/R/app_version.R @@ -1 +1 @@ -app_version <- function()'25.6.3' +app_version <- function()'25.6.1' diff --git a/R/helpers.R b/R/helpers.R index cb2a1aa4..73129194 100644 --- a/R/helpers.R +++ b/R/helpers.R @@ -50,7 +50,7 @@ write_quarto <- function(data, ...) { ) } -write_rmd <- function(data, ..., params.args=NULL) { +write_rmd <- function(data, ...) { # Exports data to temporary location # # I assume this is more secure than putting it in the www folder and deleting @@ -65,7 +65,7 @@ write_rmd <- function(data, ..., params.args=NULL) { ## Ref: https://github.com/quarto-dev/quarto-cli/discussions/4041 ## Outputs to the same as the .qmd file rmarkdown::render( - params = modifyList(list(data.file = "web_data.rds",version=app_version()),params.args), + params = list(data.file = "web_data.rds",version=app_version()), # execute_params = list(data.file = temp), ... ) diff --git a/R/hosted_version.R b/R/hosted_version.R index 6d5e327f..095d1d44 100644 --- a/R/hosted_version.R +++ b/R/hosted_version.R @@ -1 +1 @@ -hosted_version <- function()'v25.6.3-250620' +hosted_version <- function()'v25.6.1-250604' diff --git a/R/missings-module.R b/R/missings-module.R deleted file mode 100644 index 451d4abc..00000000 --- a/R/missings-module.R +++ /dev/null @@ -1,113 +0,0 @@ -#' Data correlations evaluation module -#' -#' @param id Module id -#' -#' @name data-missings -#' @returns Shiny ui module -#' @export -data_missings_ui <- function(id) { - ns <- shiny::NS(id) - - shiny::tagList( - gt::gt_output(outputId = ns("missings_table")), - shiny::plotOutput(outputId = ns("missings_plot")) - ) -} - - -#' -#' @param data data -#' @param output.format output format -#' -#' @name data-missings -#' @returns shiny server module -#' @export -data_missings_server <- function(id, - data, - ...) { - shiny::moduleServer( - id = id, - module = function(input, output, session) { - # ns <- session$ns - - rv <- shiny::reactiveValues( - data = NULL - ) - - rv$data <- if (is.reactive(data)) data else reactive(data) - - output$missings_plot <- shiny::renderPlot({ - visdat::vis_dat(rv$data(),palette = "cb_safe") - }) - } - ) -} - - -missing_demo_app <- function() { - ui <- shiny::fluidPage( - shiny::actionButton( - inputId = "modal_missings", - label = "Browse data", - width = "100%", - disabled = FALSE - )#, - # data_missings_ui("data") - ) - server <- function(input, output, session) { - data_demo <- mtcars - data_demo[2:4, "cyl"] <- NA - - observeEvent(input$modal_missings, { - tryCatch( - { - modal_data_missings(data = data_demo, id = "modal_missings") - }, - error = function(err) { - showNotification(paste0("We encountered the following error browsing your data: ", err), type = "err") - } - ) - }) - } - shiny::shinyApp(ui, server) -} - -missing_demo_app() - - -modal_data_missings <- function(data, - title = "Show missing pattern", - easyClose = TRUE, - size = "xl", - footer = NULL, - ...) { - - datar <- if (is.reactive(data)) data else reactive(data) - - showModal(modalDialog( - title = tagList(title, datamods:::button_close_modal()), - tags$div( - shiny::renderPlot({ - visdat::vis_dat(datar())+ - ggplot2::guides(fill = ggplot2::guide_legend(title = "Data class")) + - # ggplot2::theme_void() + - ggplot2::theme( - # legend.position = "none", - panel.grid.major = ggplot2::element_blank(), - panel.grid.minor = ggplot2::element_blank(), - # axis.text.y = element_blank(), - # axis.title.y = element_blank(), - text = ggplot2::element_text(size = 15), - # axis.text = ggplot2::element_blank(), - # panel.background = ggplot2::element_rect(fill = "white"), - # plot.background = ggplot2::element_rect(fill = "white"), - # panel.border = ggplot2::element_blank() - plot.title = ggplot2::element_blank() - ) - }) - ), - easyClose = easyClose, - size = size, - footer = footer - )) -} diff --git a/R/sysdata.rda b/R/sysdata.rda index e1714c39..66754e3c 100644 Binary files a/R/sysdata.rda and b/R/sysdata.rda differ diff --git a/SESSION.md b/SESSION.md index d7a6af1f..eeee39b9 100644 --- a/SESSION.md +++ b/SESSION.md @@ -11,11 +11,11 @@ |collate |en_US.UTF-8 | |ctype |en_US.UTF-8 | |tz |Europe/Copenhagen | -|date |2025-06-06 | +|date |2025-06-04 | |rstudio |2025.05.0+496 Mariposa Orchid (desktop) | |pandoc |3.6.4 @ /opt/homebrew/bin/ (via rmarkdown) | |quarto |1.7.30 @ /usr/local/bin/quarto | -|FreesearchR |25.6.2.250606 | +|FreesearchR |25.6.1.250604 | -------------------------------------------------------------------------------- @@ -76,6 +76,7 @@ |farver |2.1.2 |2024-05-13 |CRAN (R 4.4.1) | |fastmap |1.2.0 |2024-05-15 |CRAN (R 4.4.1) | |flextable |0.9.7 |2024-10-27 |CRAN (R 4.4.1) | +|fontawesome |0.5.3 |2024-11-16 |CRAN (R 4.4.1) | |fontBitstreamVera |0.1.1 |2017-02-01 |CRAN (R 4.4.1) | |fontLiberation |0.1.0 |2016-10-15 |CRAN (R 4.4.1) | |fontquiver |0.2.1 |2017-02-01 |CRAN (R 4.4.0) | @@ -83,7 +84,7 @@ |foreach |1.5.2 |2022-02-02 |CRAN (R 4.4.0) | |foreign |0.8-90 |2025-03-31 |CRAN (R 4.4.1) | |Formula |1.2-5 |2023-02-24 |CRAN (R 4.4.1) | -|FreesearchR |25.6.2 |NA |NA | +|FreesearchR |25.6.1 |NA |NA | |fs |1.6.6 |2025-04-12 |CRAN (R 4.4.1) | |gdtools |0.4.2 |2025-03-27 |CRAN (R 4.4.1) | |generics |0.1.3 |2022-07-05 |CRAN (R 4.4.1) | @@ -159,7 +160,6 @@ |R6 |2.6.1 |2025-02-15 |CRAN (R 4.4.1) | |ragg |1.4.0 |2025-04-10 |CRAN (R 4.4.1) | |rankinPlot |1.1.0 |2023-01-30 |CRAN (R 4.4.0) | -|rappdirs |0.3.3 |2021-01-31 |CRAN (R 4.4.1) | |rbibutils |2.3 |2024-10-04 |CRAN (R 4.4.1) | |RColorBrewer |1.1-3 |2022-04-03 |CRAN (R 4.4.1) | |Rcpp |1.0.14 |2025-01-12 |CRAN (R 4.4.1) | diff --git a/inst/apps/FreesearchR/app.R b/inst/apps/FreesearchR/app.R index 51b30506..235b1d45 100644 --- a/inst/apps/FreesearchR/app.R +++ b/inst/apps/FreesearchR/app.R @@ -16,7 +16,7 @@ library(shiny) # library(readODS) # library(bslib) # library(assertthat) -library(dplyr) +# library(dplyr) # library(quarto) # library(here) # library(broom) @@ -31,7 +31,7 @@ library(datamods) library(shinyWidgets) # library(DT) # library(data.table) -library(gtsummary) +# library(gtsummary) library(bsicons) library(rlang) # library(datamods) @@ -49,7 +49,7 @@ library(rlang) #### Current file: /Users/au301842/FreesearchR/R//app_version.R ######## -app_version <- function()'25.6.3' +app_version <- function()'25.6.1' ######## @@ -3374,7 +3374,7 @@ write_quarto <- function(data, ...) { ) } -write_rmd <- function(data, ..., params.args=NULL) { +write_rmd <- function(data, ...) { # Exports data to temporary location # # I assume this is more secure than putting it in the www folder and deleting @@ -3389,7 +3389,7 @@ write_rmd <- function(data, ..., params.args=NULL) { ## Ref: https://github.com/quarto-dev/quarto-cli/discussions/4041 ## Outputs to the same as the .qmd file rmarkdown::render( - params = modifyList(list(data.file = "web_data.rds",version=app_version()),params.args), + params = list(data.file = "web_data.rds",version=app_version()), # execute_params = list(data.file = temp), ... ) @@ -3996,7 +3996,7 @@ simple_snake <- function(data){ #### Current file: /Users/au301842/FreesearchR/R//hosted_version.R ######## -hosted_version <- function()'v25.6.3-250620' +hosted_version <- function()'v25.6.1-250604' ######## @@ -4655,125 +4655,6 @@ launch_FreesearchR <- function(...){ -######## -#### Current file: /Users/au301842/FreesearchR/R//missings-module.R -######## - -#' Data correlations evaluation module -#' -#' @param id Module id -#' -#' @name data-missings -#' @returns Shiny ui module -#' @export -data_missings_ui <- function(id) { - ns <- shiny::NS(id) - - shiny::tagList( - gt::gt_output(outputId = ns("missings_table")), - shiny::plotOutput(outputId = ns("missings_plot")) - ) -} - - -#' -#' @param data data -#' @param output.format output format -#' -#' @name data-missings -#' @returns shiny server module -#' @export -data_missings_server <- function(id, - data, - ...) { - shiny::moduleServer( - id = id, - module = function(input, output, session) { - # ns <- session$ns - - rv <- shiny::reactiveValues( - data = NULL - ) - - rv$data <- if (is.reactive(data)) data else reactive(data) - - output$missings_plot <- shiny::renderPlot({ - visdat::vis_dat(rv$data(),palette = "cb_safe") - }) - } - ) -} - - -missing_demo_app <- function() { - ui <- shiny::fluidPage( - shiny::actionButton( - inputId = "modal_missings", - label = "Browse data", - width = "100%", - disabled = FALSE - )#, - # data_missings_ui("data") - ) - server <- function(input, output, session) { - data_demo <- mtcars - data_demo[2:4, "cyl"] <- NA - - observeEvent(input$modal_missings, { - tryCatch( - { - modal_data_missings(data = data_demo, id = "modal_missings") - }, - error = function(err) { - showNotification(paste0("We encountered the following error browsing your data: ", err), type = "err") - } - ) - }) - } - shiny::shinyApp(ui, server) -} - -missing_demo_app() - - -modal_data_missings <- function(data, - title = "Show missing pattern", - easyClose = TRUE, - size = "xl", - footer = NULL, - ...) { - - datar <- if (is.reactive(data)) data else reactive(data) - - showModal(modalDialog( - title = tagList(title, datamods:::button_close_modal()), - tags$div( - shiny::renderPlot({ - visdat::vis_dat(datar())+ - ggplot2::guides(fill = ggplot2::guide_legend(title = "Data class")) + - # ggplot2::theme_void() + - ggplot2::theme( - # legend.position = "none", - panel.grid.major = ggplot2::element_blank(), - panel.grid.minor = ggplot2::element_blank(), - # axis.text.y = element_blank(), - # axis.title.y = element_blank(), - text = ggplot2::element_text(size = 15), - # axis.text = ggplot2::element_blank(), - # panel.background = ggplot2::element_rect(fill = "white"), - # plot.background = ggplot2::element_rect(fill = "white"), - # panel.border = ggplot2::element_blank() - plot.title = ggplot2::element_blank() - ) - }) - ), - easyClose = easyClose, - size = size, - footer = footer - )) -} - - ######## #### Current file: /Users/au301842/FreesearchR/R//plot_box.R ######## @@ -9523,7 +9404,6 @@ ui_elements <- list( width = 8, shiny::h4("Choose your data source"), shiny::br(), - # shiny::uiOutput(outputId = "source"), shinyWidgets::radioGroupButtons( inputId = "source", selected = "file", @@ -9549,13 +9429,6 @@ ui_elements <- list( ), shiny::conditionalPanel( condition = "input.source=='redcap'", - shinyWidgets::alert( - id = "redcap-warning", - status = "info", - shiny::tags$h2(shiny::markdown("Careful with sensitive data")), - shiny::tags$p("The", shiny::tags$i(shiny::tags$b("FreesearchR")), "app only stores data for analyses, but please only use with sensitive data when running locally.", "", shiny::tags$a("Read more here", href = "https://agdamsbo.github.io/FreesearchR/#run-locally-on-your-own-machine"),"."), - dismissible = TRUE - ), m_redcap_readUI( id = "redcap_import", title = "" @@ -9573,11 +9446,11 @@ ui_elements <- list( condition = "output.data_loaded == true", shiny::br(), shiny::br(), - shiny::h5("Select variables for final import"), + shiny::h5("Specify variables to include"), shiny::fluidRow( shiny::column( width = 6, - shiny::p("Exclude incomplete variables:"), + shiny::p("Filter by completeness threshold:"), shiny::br(), shinyWidgets::noUiSliderInput( inputId = "complete_cutoff", @@ -9586,16 +9459,16 @@ ui_elements <- list( min = 0, max = 100, step = 5, - value = 30, + value = 70, format = shinyWidgets::wNumbFormat(decimals = 0), color = datamods:::get_primary_color() ), - shiny::helpText("Only include variables with missingness below the specified percentage."), + shiny::helpText("Exclude variables with completeness below the specified percentage."), shiny::br() ), shiny::column( width = 6, - shiny::p("Manual selection:"), + shiny::p("Specify manually:"), shiny::br(), shiny::uiOutput(outputId = "import_var"), shiny::br() @@ -9655,45 +9528,34 @@ ui_elements <- list( ), shiny::column( width = 3, - shiny::actionButton( - inputId = "modal_missings", - label = "Visual overview", - width = "100%", - disabled = TRUE - ), - shiny::br(), - shiny::br(), shiny::actionButton( inputId = "modal_browse", label = "Browse data", width = "100%", disabled = TRUE ), - shiny::br(), - shiny::br(), - shiny::tags$h6("Filter data types"), - shiny::uiOutput( - outputId = "column_filter"), - shiny::helpText("Read more on how ", tags$a( - "data types", + shiny::tags$br(), + shiny::tags$br(), + shiny::uiOutput(outputId = "column_filter"), + shiny::helpText("Variable ", tags$a( + "data type", href = "https://agdamsbo.github.io/FreesearchR/articles/data-types.html", target = "_blank", rel = "noopener noreferrer" - ), " are defined."), - shiny::br(), - shiny::br(), - shiny::tags$h6("Create data filters"), - shiny::tags$p("Filter on observation level"), + ), " filtering."), + shiny::tags$br(), + shiny::tags$br(), IDEAFilter::IDEAFilter_ui("data_filter"), - shiny::br(), - shiny::br() + shiny::helpText("Observations level filtering."), + shiny::tags$br(), + shiny::tags$br() ) ), - shiny::br(), - shiny::br(), - # shiny::br(), - # shiny::br(), - shiny::br() + shiny::tags$br(), + shiny::tags$br(), + shiny::tags$br(), + shiny::tags$br(), + shiny::tags$br() ), bslib::nav_panel( title = "Modify", @@ -10091,15 +9953,9 @@ ui <- bslib::page_fixed( - +data(starwars) data(mtcars) - -# trial <- gtsummary::trial -# starwars <- dplyr::starwars -# -# mtcars_na <- rbind(mtcars,NA,NA) - -# thematic::thematic_shiny() +data(trial) load_data <- function() { Sys.sleep(1) @@ -10107,7 +9963,6 @@ load_data <- function() { shinyjs::show("main_content") } -# is_local = is.na(Sys.getenv('SHINY_SERVER_VERSION', NA)) server <- function(input, output, session) { ## Listing files in www in session start to keep when ending and removing @@ -10163,28 +10018,6 @@ server <- function(input, output, session) { ######### ############################################################################## - ## This does not render correctly apparently due to css and load order - # output$source <- shiny::renderUI({ - # - # choices <- c( - # "File upload" = "file", - # "REDCap server export" = "redcap", - # "Local or sample data" = "env" - # ) - # - # if (isTRUE(is_local)){ - # choices <- choices[c(1,3)] - # } - # - # shinyWidgets::radioGroupButtons( - # inputId = "source", - # selected = "file", - # choices = choices, - # size = "lg" - # ) - # }) - - data_file <- import_file_server( id = "file_import", show_data_in = "popup", @@ -10234,7 +10067,7 @@ server <- function(input, output, session) { output$import_var <- shiny::renderUI({ shiny::req(rv$data_temp) - preselect <- names(rv$data_temp)[sapply(rv$data_temp, missing_fraction) <= (input$complete_cutoff / 100)] + preselect <- names(rv$data_temp)[sapply(rv$data_temp, missing_fraction) <= input$complete_cutoff / 100] shinyWidgets::virtualSelectInput( inputId = "import_var", @@ -10303,12 +10136,10 @@ server <- function(input, output, session) { if (is.null(rv$data_original) | NROW(rv$data_original) == 0) { shiny::updateActionButton(inputId = "act_start", disabled = TRUE) shiny::updateActionButton(inputId = "modal_browse", disabled = TRUE) - shiny::updateActionButton(inputId = "modal_missings", disabled = TRUE) shiny::updateActionButton(inputId = "act_eval", disabled = TRUE) } else { shiny::updateActionButton(inputId = "act_start", disabled = FALSE) shiny::updateActionButton(inputId = "modal_browse", disabled = FALSE) - shiny::updateActionButton(inputId = "modal_missings", disabled = FALSE) shiny::updateActionButton(inputId = "act_eval", disabled = FALSE) } }) @@ -10448,7 +10279,7 @@ server <- function(input, output, session) { # c("dichotomous", "ordinal", "categorical", "datatime", "continuous") shinyWidgets::virtualSelectInput( inputId = "column_filter", - label = "Select data types to include", + label = "Select variable types to include", selected = unique(data_type(rv$data)), choices = unique(data_type(rv$data)), updateOn = "change", @@ -10547,19 +10378,6 @@ server <- function(input, output, session) { ) }) - observeEvent(input$modal_missings, { - tryCatch( - { - modal_data_missings(data = REDCapCAST::fct_drop(rv$data_filtered), - footer = "This pop-up gives you an overview of how your data is interpreted, and where data is missing. Use this information to consider if data is missing at random or if some observations are missing systematically wich may be caused by an observation bias.") - }, - error = function(err) { - showNotification(paste0("We encountered the following error showing missingness: ", err), type = "err") - } - ) - }) - - output$original_str <- renderPrint({ str(rv$data_original) }) @@ -10842,9 +10660,6 @@ server <- function(input, output, session) { { rv$list |> write_rmd( - params.args = list( - regression.p=rv$list$regression$input$add_regression_p - ), output_format = format, input = file.path(getwd(), "www/report.rmd") ) diff --git a/inst/apps/FreesearchR/www/report.rmd b/inst/apps/FreesearchR/www/report.rmd index fcc6d4d3..7f7c61f6 100644 --- a/inst/apps/FreesearchR/www/report.rmd +++ b/inst/apps/FreesearchR/www/report.rmd @@ -7,7 +7,6 @@ toc: false params: data.file: NA version: NA - regression.p: NA --- ```{r setup, echo = FALSE} @@ -66,15 +65,7 @@ if ("table1" %in% names(web_data)) { ```{r, results = 'asis'} if ("regression" %in% names(web_data) && length(web_data$regression) > 0) { reg_tbl <- web_data$regression$regression$tables - - merged <- tbl_merge(reg_tbl) - - if (params$regression.p == "no") { - merged <- merged |> - gtsummary::modify_column_hide(column = dplyr::starts_with("p.value")) - } - - knitr::knit_print(merged) + knitr::knit_print(tbl_merge(reg_tbl)) } ``` diff --git a/inst/apps/FreesearchR/www/umami-app.html b/inst/apps/FreesearchR/www/umami-app.html deleted file mode 100644 index f4e9a526..00000000 --- a/inst/apps/FreesearchR/www/umami-app.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/inst/apps/FreesearchR/www/web_data.rds b/inst/apps/FreesearchR/www/web_data.rds index a3256d47..bddd5583 100644 Binary files a/inst/apps/FreesearchR/www/web_data.rds and b/inst/apps/FreesearchR/www/web_data.rds differ diff --git a/man/data-missings.Rd b/man/data-missings.Rd deleted file mode 100644 index e79398fc..00000000 --- a/man/data-missings.Rd +++ /dev/null @@ -1,27 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/missings-module.R -\name{data-missings} -\alias{data-missings} -\alias{data_missings_ui} -\alias{data_missings_server} -\title{Data correlations evaluation module} -\usage{ -data_missings_ui(id) - -data_missings_server(id, data, ...) -} -\arguments{ -\item{id}{Module id} - -\item{data}{data} - -\item{output.format}{output format} -} -\value{ -Shiny ui module - -shiny server module -} -\description{ -Data correlations evaluation module -}