From 77a8648a5dd0784125a94b7051979055817f112a Mon Sep 17 00:00:00 2001 From: Ed Ivimey-Cook Date: Thu, 3 Jul 2025 16:10:54 +0100 Subject: [PATCH 1/4] Add files via upload Detects if the original dataset changes, then updates existing saved file. --- README.md | 4 +- inst/metRscreen/server.R | 82 +++++++++++++++++++++++----------------- metRscreen.Rproj | 1 + 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 81e76aa..39c060c 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ metRscreen(screen.file = "~/Desktop/Example.csv") ``` ## metRscreen arguments -You can give specific rejection reasons as a vector with "reject.vec = c()". +You can give specific rejection reasons as a vector with "reject.list = c()". ```{r} -metRscreen(screen.file = "~/Desktop/Example.csv", reject.vec = c("no control", "wrong study system")) +metRscreen(screen.file = "~/Desktop/Example.csv", reject.list = c("no control", "wrong study system")) ``` The .rds file that's produced allows for reloading of previous screening decisions. This will be automatically reloaded the next instance metRscreen is run and will return screening to the same state (i.e. with the same reject list, hidden or showing paper components, and any previous screening decisions). diff --git a/inst/metRscreen/server.R b/inst/metRscreen/server.R index 868fcf9..cdabbce 100644 --- a/inst/metRscreen/server.R +++ b/inst/metRscreen/server.R @@ -87,15 +87,29 @@ server <- function(input, output, session) { ) import$first.load <- FALSE cat("\nReading in new screening file and creating new screening output(s)\n") - } else if (!is.null(screen.history) & import$first.load == TRUE) { + } else if (!is.null(screen.history)) { settings.store <<- do.call("reactiveValues", readRDS(screen.history)) - original$new.data <- settings.store$new.data - cat("\nReading in saved screening file and using existing screening output\n") - import$first.load <- FALSE - import$first.import <- TRUE - counter$countervalue <- settings.store$counter + + if (nrow(settings.store$new.data) == nrow(read.csv(screen.file)) & import$first.load == TRUE) { + original$new.data <- settings.store$new.data + cat("\nReading in saved screening file and using existing screening output\n") + import$first.load <- FALSE + import$first.import <- TRUE + counter$countervalue <- settings.store$counter + } else if (nrow(settings.store$new.data) != nrow(read.csv(screen.file)) & import$first.load == TRUE) { + original$new.data <- cbind( + read.csv(screen.file), + Screen = "To be screened", + Reason = "No reason given", + Comment = "No comments given", + Screen.Name = "No screener name given" + ) + cat("\nDifferences detected between screening file and stored history. Reading in new screening file and creating new screening output(s)\n") + import$first.load <- FALSE + } } + # save a temp output settings.store$counter <- counter$countervalue settings.store$new.data <- original$new.data @@ -265,27 +279,27 @@ server <- function(input, output, session) { ) )) }) - + # render title text highlighted based on search###### output$title <- shiny::renderUI({ shiny::HTML(paste( "", highlight_text(as.character(StudyData()$Title), - search = list( - input$search1, - input$search2, - input$search3, - input$search4, - input$search5 - ) + search = list( + input$search1, + input$search2, + input$search3, + input$search4, + input$search5 + ) ), "" )) }) - #error + # error output$hist.reason <- shiny::renderUI({ - if(StudyData()$Screen == "Reject"){ + if (StudyData()$Screen == "Reject") { shiny::HTML(paste( "

", "Reject Reason:", @@ -305,21 +319,21 @@ server <- function(input, output, session) { }) output$screen.comment <- shiny::renderUI({ - shiny::HTML(paste( - "

", - "Comment:", - as.character(StudyData()$Comment), - "

" - )) + shiny::HTML(paste( + "

", + "Comment:", + as.character(StudyData()$Comment), + "

" + )) }) output$name.screener <- shiny::renderUI({ - shiny::HTML(paste( - "

", - "Screener:", - as.character(StudyData()$Screen.Name), - "

" - )) + shiny::HTML(paste( + "

", + "Screener:", + as.character(StudyData()$Screen.Name), + "

" + )) }) output$author <- shiny::renderUI({ @@ -371,7 +385,7 @@ server <- function(input, output, session) { shinyalert::shinyalert( title = "Congratulations", text = "You've finished screening all papers!", - size = "s", + size = "s", closeOnEsc = TRUE, closeOnClickOutside = TRUE, html = FALSE, @@ -384,7 +398,7 @@ server <- function(input, output, session) { imageUrl = "", animation = TRUE ) - cat(paste("\nCongratulations - you have finished screening", countertot$total, "papers \n")) + cat(paste("\nCongratulations - you have finished screening", countertot$total, "papers \n")) counter$countervalue <- countertot$total } if (counter$countervalue == 0) { @@ -453,7 +467,7 @@ server <- function(input, output, session) { shinyalert::shinyalert( title = "Congratulations", text = "You've finished screening all papers!", - size = "s", + size = "s", closeOnEsc = TRUE, closeOnClickOutside = TRUE, html = FALSE, @@ -466,7 +480,7 @@ server <- function(input, output, session) { imageUrl = "", animation = TRUE ) - cat(paste("\nCongratulations - you have finished screening", countertot$total, "papers \n")) + cat(paste("\nCongratulations - you have finished screening", countertot$total, "papers \n")) counter$countervalue <- countertot$total } if (counter$countervalue == 0) { @@ -530,7 +544,7 @@ server <- function(input, output, session) { shinyalert::shinyalert( title = "Congratulations", text = "You've finished screening all papers!", - size = "s", + size = "s", closeOnEsc = TRUE, closeOnClickOutside = TRUE, html = FALSE, @@ -543,7 +557,7 @@ server <- function(input, output, session) { imageUrl = "", animation = TRUE ) - cat(paste("\nCongratulations - you have finished screening", countertot$total, "papers \n")) + cat(paste("\nCongratulations - you have finished screening", countertot$total, "papers \n")) counter$countervalue <- countertot$total } if (counter$countervalue == 0) { diff --git a/metRscreen.Rproj b/metRscreen.Rproj index 21a4da0..44e11d0 100644 --- a/metRscreen.Rproj +++ b/metRscreen.Rproj @@ -1,4 +1,5 @@ Version: 1.0 +ProjectId: bce1fe8b-f015-4032-af0d-02ecf1f3463c RestoreWorkspace: Default SaveWorkspace: Default From b2280059aa15591ced40fdf7357c692388c15d41 Mon Sep 17 00:00:00 2001 From: Ed Ivimey-Cook Date: Thu, 3 Jul 2025 20:27:54 +0100 Subject: [PATCH 2/4] Add files via upload --- inst/metRscreen/server.R | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/inst/metRscreen/server.R b/inst/metRscreen/server.R index cdabbce..9e676b9 100644 --- a/inst/metRscreen/server.R +++ b/inst/metRscreen/server.R @@ -29,6 +29,9 @@ server <- function(input, output, session) { # create a new dataframe based on the old data in a reactive ovject original <- shiny::reactiveValues(new.data = NULL) + + # create a new dataframe for hcecking + check_dat <- shiny::reactiveValues(check = NULL) # create a temp data file temp <- shiny::reactiveValues(import.data = NULL) @@ -87,25 +90,37 @@ server <- function(input, output, session) { ) import$first.load <- FALSE cat("\nReading in new screening file and creating new screening output(s)\n") - } else if (!is.null(screen.history)) { + } else if (!is.null(screen.history) & import$first.load == TRUE) { + settings.store <<- do.call("reactiveValues", readRDS(screen.history)) + check_dat$check <- read.csv(screen.file) - if (nrow(settings.store$new.data) == nrow(read.csv(screen.file)) & import$first.load == TRUE) { + if (isTRUE(all.equal(settings.store$new.data$Title, check_dat$check$Title))) { original$new.data <- settings.store$new.data cat("\nReading in saved screening file and using existing screening output\n") + counter$countervalue <- settings.store$counter import$first.load <- FALSE import$first.import <- TRUE + + } else if(!isTRUE(all.equal(settings.store$new.data$Title, check_dat$check$Title))) { counter$countervalue <- settings.store$counter - } else if (nrow(settings.store$new.data) != nrow(read.csv(screen.file)) & import$first.load == TRUE) { - original$new.data <- cbind( - read.csv(screen.file), - Screen = "To be screened", - Reason = "No reason given", - Comment = "No comments given", - Screen.Name = "No screener name given" + cat("\nData frame inconsistencies between saved and loaded data frames - please revert to previous version\n") + shinyalert::shinyalert( + title = "Warning", + text = "Data frame inconsistencies between saved and loaded data frames - please revert to previous version", + size = "m", + closeOnClickOutside = FALSE, + html = TRUE, + type = "warning", + showConfirmButton = TRUE, + showCancelButton = FALSE, + confirmButtonText = "OK", + confirmButtonCol = "#AEDEF4", + animation = TRUE, + imageHeight = "88", + imageWidth = "80" ) - cat("\nDifferences detected between screening file and stored history. Reading in new screening file and creating new screening output(s)\n") - import$first.load <- FALSE + shiny::stopApp() } } @@ -237,6 +252,9 @@ server <- function(input, output, session) { # counter total###### shiny::observe({ countertot$total <- nrow(original$new.data) + if(!isTRUE(all.equal(settings.store$new.data$Title, check_dat$check$Title))) { + countertot$total <- 1 + } }) # change the study with next and previous####### From 227132f0ea3f1e042fb6ceac259323208f2f8d27 Mon Sep 17 00:00:00 2001 From: Ed Ivimey-Cook Date: Tue, 8 Jul 2025 09:24:13 +0100 Subject: [PATCH 3/4] Add files via upload --- inst/metRscreen/server.R | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/inst/metRscreen/server.R b/inst/metRscreen/server.R index 9e676b9..65abdea 100644 --- a/inst/metRscreen/server.R +++ b/inst/metRscreen/server.R @@ -80,6 +80,7 @@ server <- function(input, output, session) { # input dataframe and create saving empty template####### shiny::observe({ + if (is.null(screen.history) & import$first.load == TRUE) { original$new.data <- cbind( read.csv(screen.file), @@ -88,22 +89,30 @@ server <- function(input, output, session) { Comment = "No comments given", Screen.Name = "No screener name given" ) + import$first.load <- FALSE + countertot$total <- nrow(original$new.data) cat("\nReading in new screening file and creating new screening output(s)\n") + } else if (!is.null(screen.history) & import$first.load == TRUE) { settings.store <<- do.call("reactiveValues", readRDS(screen.history)) check_dat$check <- read.csv(screen.file) + countertot$total <- nrow(settings.store$new.data) + counter$countervalue <- settings.store$counter + if (isTRUE(all.equal(settings.store$new.data$Title, check_dat$check$Title))) { + original$new.data <- settings.store$new.data - cat("\nReading in saved screening file and using existing screening output\n") - counter$countervalue <- settings.store$counter + import$first.load <- FALSE import$first.import <- TRUE + cat("\nReading in saved screening file and using existing screening output\n") + } else if(!isTRUE(all.equal(settings.store$new.data$Title, check_dat$check$Title))) { - counter$countervalue <- settings.store$counter + cat("\nData frame inconsistencies between saved and loaded data frames - please revert to previous version\n") shinyalert::shinyalert( title = "Warning", @@ -245,18 +254,6 @@ server <- function(input, output, session) { } }) - - - - - # counter total###### - shiny::observe({ - countertot$total <- nrow(original$new.data) - if(!isTRUE(all.equal(settings.store$new.data$Title, check_dat$check$Title))) { - countertot$total <- 1 - } - }) - # change the study with next and previous####### shiny::observeEvent(input$Next, { counter$countervalue <- counter$countervalue + 1 @@ -465,7 +462,7 @@ server <- function(input, output, session) { shiny::observeEvent(input$Reject, { original$new.data[counter$countervalue, ]$Screen <- "Reject" - if (length(input$reject.reason > 0)) { + if (length(input$reject.reason > 0) & input$reject.reason != "") { original$new.data[counter$countervalue, ]$Reason <- input$reject.reason } if (input$comments != "") { From e3d9c614fcfa97a01874639fe0ffdff637a0755b Mon Sep 17 00:00:00 2001 From: Ed Ivimey-Cook Date: Tue, 8 Jul 2025 09:30:22 +0100 Subject: [PATCH 4/4] Add files via upload --- DESCRIPTION | 2 +- R/runApp.R | 8 ++++---- inst/metRscreen/server.R | 20 ++++++++++---------- man/metRscreen.Rd | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index e7a8e6b..0748e3f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,7 @@ Description: The metRscreen shiny app allows you to screen papers via their abst License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Imports: bslib, dplyr, diff --git a/R/runApp.R b/R/runApp.R index 78e0ce5..d065d73 100644 --- a/R/runApp.R +++ b/R/runApp.R @@ -2,14 +2,14 @@ #' @description The metRscreen shiny app allows you to screen papers via their abstracts and titles and allows for highlighting of keywords in multiple colours. #' @return A dataframe of decisioned papers #' @param screen.file path to the csv file containing references you wish to screen. -#' @param reject.vec vector of rejection reasons to be added to metRscreen, can be left empty +#' @param reject.list list of rejection reasons to be added to metRscreen, can be left empty #' @param collab.names vector of names to identify screeners to be added to metRscreen, can be left empty #' @export -metRscreen <- function(screen.file, reject.vec = NULL, collab.names = NULL) { +metRscreen <- function(screen.file, reject.list = NULL, collab.names = NULL) { # if data.str if missing, assign an empty data.frame if (missing(screen.file)) cat("\nError: Please provide a .csv file to screen\n") - if (missing(reject.vec)) reject.vec <- NULL + if (missing(reject.list)) reject.list <- NULL if (missing(collab.names)) collab.names <- NULL if (file.exists(screen.file)) { @@ -25,7 +25,7 @@ metRscreen <- function(screen.file, reject.vec = NULL, collab.names = NULL) { shiny_env <- 1 envir <- as.environment(shiny_env) assign("screen.file", screen.file, envir = envir) - assign("reject.vec", reject.vec, envir = envir) + assign("reject.list", reject.list, envir = envir) assign("collab.names", collab.names, envir = envir) assign("screen.history", screen.history, envir = envir) diff --git a/inst/metRscreen/server.R b/inst/metRscreen/server.R index 65abdea..59d0d2a 100644 --- a/inst/metRscreen/server.R +++ b/inst/metRscreen/server.R @@ -4,7 +4,7 @@ server <- function(input, output, session) { # settings object settings.store <- shiny::reactiveValues( - reject.vec = NULL, + reject.list = NULL, counter = NULL, datapath = NULL, new.data = NULL, @@ -152,10 +152,10 @@ server <- function(input, output, session) { shiny::observe({ if (!is.null(screen.history) & import$first.import == "TRUE") { # update params - if (!identical(reject.vec, settings.store$reject.vec) & !is.null(reject.vec)) { - reject.vec <<- reject.vec + if (!identical(reject.list, settings.store$reject.list) & !is.null(reject.list)) { + reject.list <<- reject.list } else { - reject.vec <<- settings.store$reject.vec + reject.list <<- settings.store$reject.list } if (!identical(collab.names, settings.store$collab.names) & !is.null(collab.names)) { @@ -234,12 +234,12 @@ server <- function(input, output, session) { # update radiogroup with imported reasons#### shiny::observe({ - if (length(reject.vec > 0)) { + if (length(reject.list > 0)) { shinyjs::show("reject.reason") shinyWidgets::updatePrettyRadioButtons( session = session, inputId = "reject.reason", - choices = reject.vec, + choices = reject.list, selected = character(0), inline = TRUE, prettyOptions = list( @@ -250,7 +250,7 @@ server <- function(input, output, session) { ) ) - settings.store$reject.vec <- reject.vec + settings.store$reject.list <- reject.list } }) @@ -430,7 +430,7 @@ server <- function(input, output, session) { shinyWidgets::updatePrettyRadioButtons( session = session, inputId = "reject.reason", - choices = reject.vec, + choices = reject.list, selected = character(0), inline = TRUE, prettyOptions = list( @@ -507,7 +507,7 @@ server <- function(input, output, session) { shinyWidgets::updatePrettyRadioButtons( session = session, inputId = "reject.reason", - choices = reject.vec, + choices = reject.list, selected = character(0), inline = TRUE, prettyOptions = list( @@ -584,7 +584,7 @@ server <- function(input, output, session) { shinyWidgets::updatePrettyRadioButtons( session = session, inputId = "reject.reason", - choices = reject.vec, + choices = reject.list, selected = character(0), inline = TRUE, prettyOptions = list( diff --git a/man/metRscreen.Rd b/man/metRscreen.Rd index 1c8d267..373176b 100644 --- a/man/metRscreen.Rd +++ b/man/metRscreen.Rd @@ -4,12 +4,12 @@ \alias{metRscreen} \title{Run the metRscreen paper screening app} \usage{ -metRscreen(screen.file, reject.vec = NULL, collab.names = NULL) +metRscreen(screen.file, reject.list = NULL, collab.names = NULL) } \arguments{ \item{screen.file}{path to the csv file containing references you wish to screen.} -\item{reject.vec}{vector of rejection reasons to be added to metRscreen, can be left empty} +\item{reject.list}{list of rejection reasons to be added to metRscreen, can be left empty} \item{collab.names}{vector of names to identify screeners to be added to metRscreen, can be left empty} }