From 9cf25e707fbd49d357cf295ad62f83d805c59c2c Mon Sep 17 00:00:00 2001 From: Naeem Model Date: Sun, 26 May 2024 02:38:19 +0000 Subject: Update Shiny app - Refactor data upload and sample data - Create custom data upload button - Create script.js - Change Shiny notification colour - Bug fix: ensure the case counts in bulk data that have only one row are treated as a data frame, by wrapping them in 'data.frame' before passing to 'apply' --- inst/app/scripts/data.R | 183 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 59 deletions(-) (limited to 'inst/app/scripts/data.R') diff --git a/inst/app/scripts/data.R b/inst/app/scripts/data.R index eebd14f..02b57c5 100644 --- a/inst/app/scripts/data.R +++ b/inst/app/scripts/data.R @@ -10,7 +10,9 @@ data_logic <- function(input, output, react_values) { render_plot(input, output) single_entry(input, output, react_values) - bulk_entry(input, output, react_values) + manual_bulk_entry(input, output, react_values) + upload_data(input, output, react_values) + load_samples(input, output, react_values) render_data(output, react_values) delete_data(input, react_values) export_data(output, react_values) @@ -93,80 +95,143 @@ single_entry <- function(input, output, react_values) { }) } -# Add multiple datasets to the existing table. -bulk_entry <- function(input, output, react_values) { +manual_bulk_entry <- function(input, output, react_values) { observeEvent(input$data_bulk, { - tryCatch( - { - datasets <- read.csv(text = input$data_area, header = FALSE, sep = ",") + validate_bulk_data(input, output, react_values, "data_area") + }) +} - names <- trimws(datasets[, 1]) - units <- trimws(datasets[, 2]) - counts <- apply(datasets[, 3:ncol(datasets)], 1, - function(row) { - row <- suppressWarnings(as.integer(row)) - toString(row[!is.na(row) & row >= 0]) - } - ) +upload_data <- function(input, output, react_values) { + observeEvent(input$data_upload, { + validate_bulk_data(input, output, react_values, "data_upload") + }) +} - warning_text <- "" +validate_bulk_data <- function(input, output, react_values, data_source) { + tryCatch( + { + if (data_source == "data_area") { + datasets <- read.csv(text = input$data_area, header = FALSE, sep = ",") + } else if (data_source == "data_upload") { + datasets <- read.csv( + file = input$data_upload$datapath, header = FALSE, sep = "," + ) + } - # Ensure the dataset names are neither blank nor duplicates. - if (anyNA(names) || any(names == "")) { - warning_text <- paste0(warning_text, sep = "
", - "Each row must begin with a non-blank dataset name." - ) - } else { - if (length(unique(names)) != length(names)) { - warning_text <- paste0(warning_text, sep = "
", - "The rows contain duplicate dataset names." - ) - } - if (any(names %in% react_values$data_table[, 1])) { - warning_text <- paste0(warning_text, sep = "
", - "The rows contain dataset names which already exist." - ) - } + names <- trimws(datasets[, 1]) + units <- trimws(datasets[, 2]) + counts <- apply(data.frame(datasets[, 3:ncol(datasets)]), 1, + function(row) { + row <- suppressWarnings(as.integer(row)) + toString(row[!is.na(row) & row >= 0]) } + ) - # Ensure the second entry in each row is a time unit equal to - # "Days" or "Weeks". - if (!all(units %in% c("Days", "Weeks"))) { - warning_text <- paste0(warning_text, sep = "
", - "The second entry in each row must be either 'Days' or 'Weeks'." + warning_text <- "" + + # Ensure the dataset names are neither blank nor duplicates. + if (anyNA(names) || any(names == "")) { + warning_text <- paste0(warning_text, + "Each row must begin with a non-blank dataset name.
" + ) + } else { + if (length(unique(names)) != length(names)) { + warning_text <- paste0(warning_text, + "The rows contain duplicate dataset names.
" ) } - - # Ensure the counts in each row have at least one non-negative integer. - if (any(counts == "")) { - warning_text <- paste0(warning_text, sep = "
", - "Each row must contain at least one non-negative integer." + if (any(names %in% react_values$data_table[, 1])) { + warning_text <- paste0(warning_text, + "The rows contain dataset names which already exist.
" ) } + } - output$data_area_warn <- renderUI(HTML(warning_text)) + # Ensure the second entry in each row is a time unit equal to + # "Days" or "Weeks". + if (!all(units %in% c("Days", "Weeks"))) { + warning_text <- paste0(warning_text, + "The second entry in each row must be either 'Days' or 'Weeks'.
" + ) + } - if (warning_text == "") { - # Add the new datasets to the data table. - new_rows <- data.frame(names, units, counts) - colnames(new_rows) <- c("Name", "Time units", "Case counts") - react_values$data_table <- rbind(react_values$data_table, new_rows) + # Ensure the counts in each row have at least one non-negative integer. + if (any(counts == "")) { + warning_text <- paste0(warning_text, + "Each row must contain at least one non-negative integer.
" + ) + } - # Evaluate all existing estimators on the new dataset and update the - # corresponding row in the estimates table. - update_estimates_rows(new_rows, react_values) + output[[paste0(data_source, "_warn")]] <- renderUI(HTML(warning_text)) - showNotification("Datasets added successfully.", - duration = 3, id = "notify-success" - ) - } - }, - error = function(e) { - output$data_area_warn <- renderText( - "The input does not match the required format." + if (warning_text == "") { + # Add the new datasets to the data table. + new_rows <- data.frame(names, units, counts) + colnames(new_rows) <- c("Name", "Time units", "Case counts") + react_values$data_table <- rbind(react_values$data_table, new_rows) + + # Evaluate all existing estimators on the new datasets and update the + # corresponding rows in the estimates table. + update_estimates_rows(new_rows, react_values) + + showNotification("Datasets added successfully.", + duration = 3, id = "notify-success" ) } - ) + }, + error = function(e) { + output[[paste0(data_source, "_warn")]] <- renderText( + "The input does not match the required format." + ) + } + ) +} + +# Load sample datasets. +load_samples <- function(input, output, react_values) { + observeEvent(input$data_samples, { + names <- c() + units <- c() + counts <- c() + + # COVID-19 Canada, March 2020 (weekly). + if (input$covid_canada) { + names <- c(names, "COVID-19 Canada 2020/03/03 - 2020/03/31") + units <- c(units, "Weeks") + counts <- c(counts, toString(Rnaught::COVIDCanada[seq(41, 69, 7), 2])) + } + # COVID-19 Ontario, March 2020 (weekly). + if (input$covid_ontario) { + names <- c(names, "COVID-19 Ontario 2020/03/03 - 2020/03/31") + units <- c(units, "Weeks") + counts <- c(counts, + toString(Rnaught::COVIDCanadaPT[seq(10176, 10204, 7), 3]) + ) + } + + if (length(names) == 0) { + output$data_samples_warn <- renderText( + "At least one sample dataset must be selected." + ) + } else if (any(names %in% react_values$data_table[, 1])) { + output$data_samples_warn <- renderText( + "At least one of the selected dataset names already exist." + ) + } else { + output$data_samples_warn <- renderText("") + + new_rows <- data.frame(names, units, counts) + colnames(new_rows) <- c("Name", "Time units", "Case counts") + react_values$data_table <- rbind(react_values$data_table, new_rows) + + # Evaluate all existing estimators on the sample datasets and update the + # corresponding rows in the estimates table. + update_estimates_rows(new_rows, react_values) + + showNotification("Datasets added successfully.", + duration = 3, id = "notify-success" + ) + } }) } -- cgit v1.2.3