diff options
author | Naeem Model <me@nmode.ca> | 2024-06-09 16:01:51 +0000 |
---|---|---|
committer | Naeem Model <me@nmode.ca> | 2024-06-09 16:01:51 +0000 |
commit | 9fd931aeeba4ab7bdede1a625f64e7024c2b55aa (patch) | |
tree | b59967df497f898e9b8f7e1cd0e345ed0ff71e36 | |
parent | 887c57c423ca8318d482a9f85514b3d6f281a696 (diff) |
Update Shiny app
- Remove template/logic for single data entry
- Change 'Add estimators' to 'About estimators'; adding estimators and viewing estimates are now done in the same tab
- Swap rows and columns in estimates table (estimators as row names, datasets as column names)
- Add a separate column for the serial interval to the estimates table
- Add plots for daily and weekly data using the Plotly library
- Remove italics from the subscript in all occurences of 'R_0'
- Fix code/text formatting
50 files changed, 345 insertions, 439 deletions
diff --git a/DESCRIPTION b/DESCRIPTION index 7a5b6e8..774891e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -19,9 +19,10 @@ Imports: Suggests: knitr, rmarkdown, - shiny, bslib, - DT + shiny, + DT, + plotly Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) @@ -6,15 +6,18 @@ app <- function() { missing_pkgs <- c() # Check for any missing, required packages. - if (!requireNamespace("shiny", quietly = TRUE)) { - missing_pkgs <- c(missing_pkgs, "shiny") - } if (!requireNamespace("bslib", quietly = TRUE)) { missing_pkgs <- c(missing_pkgs, "bslib") } + if (!requireNamespace("shiny", quietly = TRUE)) { + missing_pkgs <- c(missing_pkgs, "shiny") + } if (!requireNamespace("DT", quietly = TRUE)) { missing_pkgs <- c(missing_pkgs, "DT") } + if (!requireNamespace("plotly", quietly = TRUE)) { + missing_pkgs <- c(missing_pkgs, "plotly") + } # If any of the required packages are missing, # prompt the user to install them. diff --git a/inst/app/scripts/data.R b/inst/app/scripts/data.R index 02b57c5..c85e27b 100644 --- a/inst/app/scripts/data.R +++ b/inst/app/scripts/data.R @@ -8,12 +8,12 @@ data_logic <- function(input, output, react_values) { check.names = FALSE ) - render_plot(input, output) - single_entry(input, output, react_values) - manual_bulk_entry(input, output, react_values) + manual_entry(input, output, react_values) upload_data(input, output, react_values) load_samples(input, output, react_values) - render_data(output, react_values) + render_data_table(output, react_values) + render_plot(input, output, react_values, "Days") + render_plot(input, output, react_values, "Weeks") delete_data(input, react_values) export_data(output, react_values) } @@ -23,91 +23,58 @@ tokenize_counts <- function(counts_str) { suppressWarnings(as.integer(unlist(strsplit(trimws(counts_str), ",")))) } -# Render the preview plot for single entry data. -render_plot <- function(input, output) { +# Render the plots for daily and weekly data when the data table is updated. +render_plot <- function(input, output, react_values, time_units) { observe({ - counts <- tokenize_counts(input$data_counts) - if (length(counts) > 0 && !anyNA(counts) && all(counts >= 0)) { - output$data_plot <- renderPlot( - plot(seq_along(counts) - 1, counts, type = "o", pch = 16, col = "black", - xlab = input$data_units, ylab = "Cases", cex.lab = 1.5, - xlim = c(0, max(length(counts) - 1, 1)), ylim = c(0, max(counts, 1)) + datasets <- react_values$data_table[ + which(react_values$data_table[["Time units"]] == time_units), + ] + + data_plot <- plotly::plot_ly(type = "scatter", mode = "lines") + if (nrow(datasets) > 0) { + for (i in seq_len(nrow(datasets))) { + counts <- tokenize_counts(datasets[i, 3]) + data_plot <- plotly::add_trace(data_plot, + x = seq_along(counts) - 1, y = counts, name = datasets[i, 1] ) - ) - } else { - output$data_plot <- renderPlot( - plot(NULL, xlim = c(0, 10), ylim = c(0, 10), - xlab = input$data_units, ylab = "Cases", cex.lab = 1.5 - ) - ) - } - }) -} - -# Add a single dataset to the existing table. -single_entry <- function(input, output, react_values) { - observeEvent(input$data_single, { - valid <- TRUE - - # Ensure the dataset name is neither blank nor a duplicate. - name <- trimws(input$data_name) - if (name == "") { - output$data_name_warn <- renderText("The dataset name cannot be blank.") - valid <- FALSE - } else if (name %in% react_values$data_table[, 1]) { - output$data_name_warn <- renderText( - "There is already a dataset with the specified name." - ) - valid <- FALSE - } else { - output$data_name_warn <- renderText("") - } - - # Ensure the case counts are specified as a comma-separated of one or more - # non-negative integers. - counts <- tokenize_counts(input$data_counts) - if (length(counts) == 0) { - output$data_counts_warn <- renderText("Case counts cannot be blank.") - valid <- FALSE - } else if (anyNA(counts) || any(counts < 0)) { - output$data_counts_warn <- renderText( - "Case counts can only contain non-negative integers." - ) - valid <- FALSE - } else { - output$data_counts_warn <- renderText("") + } } - if (valid) { - # Add the new dataset to the data table. - new_row <- data.frame(name, input$data_units, toString(counts)) - colnames(new_row) <- c("Name", "Time units", "Case counts") - react_values$data_table <- rbind(react_values$data_table, new_row) + plot_title <- paste( + if (time_units == "Days") "Daily" else "Weekly", "case counts" + ) - # Evaluate all existing estimators on the new dataset and update the - # corresponding row in the estimates table. - update_estimates_rows(new_row, react_values) + data_plot <- plotly::layout(data_plot, title = plot_title, + xaxis = list(title = time_units), yaxis = list(title = "Cases") + ) - showNotification("Dataset added successfully.", - duration = 3, id = "notify-success" + data_plot <- plotly::config(data_plot, displaylogo = FALSE, + toImageButtonOptions = list( + filename = paste0("Rnaught_data_", tolower(time_units), "_plot") ) - } + ) + + output[[paste0("data_plot_", tolower(time_units))]] <- + plotly::renderPlotly(data_plot) }) } -manual_bulk_entry <- function(input, output, react_values) { +# Validate and add manually-entered datasets. +manual_entry <- function(input, output, react_values) { observeEvent(input$data_bulk, { - validate_bulk_data(input, output, react_values, "data_area") + validate_data(input, output, react_values, "data_area") }) } +# Validate and add datasets from a CSV file. upload_data <- function(input, output, react_values) { observeEvent(input$data_upload, { - validate_bulk_data(input, output, react_values, "data_upload") + validate_data(input, output, react_values, "data_upload") }) } -validate_bulk_data <- function(input, output, react_values, data_source) { +# Validate datasets and update the data table. +validate_data <- function(input, output, react_values, data_source) { tryCatch( { if (data_source == "data_area") { @@ -171,8 +138,8 @@ validate_bulk_data <- function(input, output, react_values, data_source) { 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) + # corresponding columns in the estimates table. + update_estimates_cols(new_rows, react_values) showNotification("Datasets added successfully.", duration = 3, id = "notify-success" @@ -225,8 +192,8 @@ load_samples <- function(input, output, react_values) { 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) + # corresponding columns in the estimates table. + update_estimates_cols(new_rows, react_values) showNotification("Datasets added successfully.", duration = 3, id = "notify-success" @@ -236,30 +203,22 @@ load_samples <- function(input, output, react_values) { } # Render the data table when new datasets are added. -render_data <- function(output, react_values) { +render_data_table <- function(output, react_values) { observe({ - output$data_table <- DT::renderDataTable(react_values$data_table) + output$data_table <- DT::renderDataTable( + react_values$data_table, rownames = FALSE + ) }) } -# Delete rows in the data table, -# and the corresponding rows in the estimates table. +# Delete rows in the data table and the corresponding columns in the estimates +# table. delete_data <- function(input, react_values) { observeEvent(input$data_delete, { - new_table <- react_values$data_table[-input$data_table_rows_selected, ] - if (nrow(new_table) > 0) { - rownames(new_table) <- seq_len(nrow(new_table)) - } - react_values$data_table <- new_table - - if (ncol(react_values$estimates_table) == 1) { - react_values$estimates_table <- data.frame( - Datasets = react_values$data_table[, 1] - ) - } else { - react_values$estimates_table <- - react_values$estimates_table[-input$data_table_rows_selected, ] - } + rows_selected <- input$data_table_rows_selected + react_values$data_table <- react_values$data_table[-rows_selected, ] + react_values$estimates_table <- + react_values$estimates_table[, -(rows_selected + 2)] }) } @@ -276,26 +235,23 @@ export_data <- function(output, react_values) { } # When new datasets are added, evaluate all existing estimators on them and -# add new rows to the estimates table. -update_estimates_rows <- function(datasets, react_values) { - new_rows <- data.frame( - matrix(nrow = nrow(datasets), ncol = ncol(react_values$estimates_table)) +# add new columns to the estimates table. +update_estimates_cols <- function(datasets, react_values) { + new_cols <- data.frame( + matrix(nrow = nrow(react_values$estimates_table), ncol = nrow(datasets)) ) - colnames(new_rows) <- colnames(react_values$estimates_table) - - for (row in seq_len(nrow(datasets))) { - new_rows[row, 1] <- datasets[row, 1] + colnames(new_cols) <- datasets[, 1] - if (length(react_values$estimators) > 0) { - for (col in 2:ncol(react_values$estimates_table)) { - new_rows[row, col] <- eval_estimator( - react_values$estimators[[col - 1]], datasets[row, ] - ) + if (nrow(new_cols) > 0) { + for (row in seq_len(nrow(new_cols))) { + estimator <- react_values$estimators[[row]] + for (col in seq_len(ncol(new_cols))) { + new_cols[row, col] <- eval_estimator(estimator, datasets[col, ]) } } } - react_values$estimates_table <- rbind( - react_values$estimates_table, new_rows + react_values$estimates_table <- cbind( + react_values$estimates_table, new_cols ) } diff --git a/inst/app/scripts/estimators.R b/inst/app/scripts/estimators.R index 171d197..b61f4d4 100644 --- a/inst/app/scripts/estimators.R +++ b/inst/app/scripts/estimators.R @@ -1,6 +1,12 @@ +# Main logic block for estimator-related interactions. estimators_logic <- function(input, output, react_values) { # Initialize a data frame to hold estimates. - react_values$estimates_table <- data.frame(Dataset = character(0)) + react_values$estimates_table <- data.frame( + Estimator = character(0), + `Serial interval` = character(0), + check.names = FALSE + + ) # Initialize a list to hold added estimators. react_values$estimators <- list() @@ -37,9 +43,9 @@ add_estimator <- function(method, new_estimator, output, react_values) { duration = 3, id = "notify-success" ) - # Evaluate all the new estimator on all existing datasets and create a new - # column in the estimates table. - update_estimates_col(new_estimator, react_values) + # Evaluate the new estimator on all existing datasets and create a new row in + # the estimates table. + update_estimates_row(new_estimator, react_values) } # Ensure serial intervals are specified as positive numbers. @@ -176,21 +182,26 @@ convert_mu_units <- function(data_units, estimator_units, mu) { mu } -# Add a column to the estimates table when a new estimator is added. -update_estimates_col <- function(estimator, react_values) { +# Add a row to the estimates table when a new estimator is added. +update_estimates_row <- function(estimator, react_values) { dataset_rows <- seq_len(nrow(react_values$data_table)) - estimates <- dataset_rows + estimates <- c() - for (row in dataset_rows) { - estimate <- eval_estimator(estimator, react_values$data_table[row, ]) - estimates[row] <- estimate + if (nrow(react_values$data_table) > 0) { + estimates <- dataset_rows + for (row in dataset_rows) { + estimate <- eval_estimator(estimator, react_values$data_table[row, ]) + estimates[row] <- estimate + } } - estimates <- data.frame(estimates) - colnames(estimates) <- estimates_col_name(estimates, estimator) + new_row <- data.frame( + t(c(estimator_name(estimator), estimator_mu_text(estimator), estimates)) + ) + colnames(new_row) <- colnames(react_values$estimates_table) - react_values$estimates_table <- cbind( - react_values$estimates_table, estimates + react_values$estimates_table <- rbind( + react_values$estimates_table, new_row ) } @@ -214,7 +225,7 @@ eval_estimator <- function(estimator, dataset) { max_shape = estimator$max_shape, max_scale = estimator$max_scale ) estimated_mu <- round(sum(estimate$supp * estimate$pmf), 2) - estimate <- paste0(round(estimate$r0, 2), " (μ = ", estimated_mu, + estimate <- paste0(round(estimate$r0, 2), " (SI = ", estimated_mu, " ", tolower(dataset[, 2]), ")" ) } else { @@ -226,39 +237,39 @@ eval_estimator <- function(estimator, dataset) { return(estimate) } -# Create the column name of an estimator when it is -# added to the estimates table. -estimates_col_name <- function(estimates, estimator) { +# Create the name of an estimator to be added to the first column of the +# estimates table. +estimator_name <- function(estimator) { if (estimator$method == "id") { - return(paste0("ID", " (μ = ", estimator$mu, " ", - tolower(estimator$mu_units), ")" - )) + return("ID") } else if (estimator$method == "idea") { - return(paste0("IDEA", " (μ = ", estimator$mu, " ", - tolower(estimator$mu_units), ")" - )) + return("IDEA") } else if (estimator$method == "seq_bayes") { - return(paste0("seqB", " (μ = ", estimator$mu, " ", - tolower(estimator$mu_units), ", κ = ", estimator$kappa, ")" - )) + return(paste0("seqB", " (κ = ", estimator$kappa, ")")) } else if (estimator$method == "wp") { if (is.na(estimator$mu)) { return(paste0("WP (", estimator$grid_length, ", ", round(estimator$max_shape, 3), ", ", round(estimator$max_scale, 3), ")" )) } else { - return(paste0("WP", " (μ = ", estimator$mu, " ", - tolower(estimator$mu_units), ")" - )) + return("WP") } } } +# Create the text to be displayed for the serial interval in the second column +# of the estimates table. +estimator_mu_text <- function(estimator) { + if (is.na(estimator$mu)) { + return("—") + } + paste(estimator$mu, tolower(estimator$mu_units)) +} + # Render the estimates table whenever it is updated. render_estimates <- function(output, react_values) { observe({ output$estimates_table <- DT::renderDataTable(react_values$estimates_table, - selection = list(target = "column", selectable = c(0)), escape = FALSE, rownames = FALSE, options = list( columnDefs = list(list(className = "dt-left", targets = "_all")) @@ -267,13 +278,13 @@ render_estimates <- function(output, react_values) { }) } -# Delete columns from the estimates table, -# as well as the corresponding estimators. +# Delete rows from the estimates table and the corresponding estimators. delete_estimators <- function(input, react_values) { observeEvent(input$estimators_delete, { - cols_selected <- input$estimates_table_columns_selected - react_values$estimators <- react_values$estimators[-cols_selected] - react_values$estimates_table[, cols_selected + 1] <- NULL + rows_selected <- input$estimates_table_rows_selected + react_values$estimators <- react_values$estimators[-rows_selected] + react_values$estimates_table <- + react_values$estimates_table[-rows_selected, ] }) } @@ -299,7 +310,6 @@ export_estimates <- function(output, react_values) { # Substitute HTML entity codes with natural names. sub_entity <- function(obj) { - obj <- gsub("μ", "mu", obj) obj <- gsub("κ", "kappa", obj) obj } diff --git a/inst/app/templates/content.html b/inst/app/templates/content.html index 8147c07..da69f08 100644 --- a/inst/app/templates/content.html +++ b/inst/app/templates/content.html @@ -5,8 +5,8 @@ <div id="data" class="tab-pane fade"> {{ htmlTemplate("templates/content/data.html") }} </div> - <div id="estimators" class="tab-pane fade"> - {{ htmlTemplate("templates/content/estimators.html") }} + <div id="estimation" class="tab-pane fade"> + {{ htmlTemplate("templates/content/estimation.html") }} </div> <div id="help" class="tab-pane fade"> {{ htmlTemplate("templates/content/help.html") }} diff --git a/inst/app/templates/content/about.html b/inst/app/templates/content/about.html index d88738f..73b75ea 100644 --- a/inst/app/templates/content/about.html +++ b/inst/app/templates/content/about.html @@ -10,18 +10,19 @@ Technical details about the estimators featured in this project can be found in the reference <a href="https://doi.org/10.1371/journal.pone.0269306" target="_blank">article</a>. </p> - <h4>What is the basic reproduction number?</h4> <p> - The basic reproduction number, denoted <em>R<sub>0</sub></em>, is defined as the expected number of infections caused by a - single infectious individual when introduced into a totally susceptible population. It assumes that all individuals in a given population are susceptible to the disease, - and that no preventive measures (such as lockdowns or vaccinations) have been enforced. It is a useful - indicator of the transmissibility of an infectious disease during the early stages of its spread and detection. + The basic reproduction number, denoted <em>R</em><sub>0</sub>, is defined as the expected number of infections caused + by a single infectious individual when introduced into a totally susceptible population. It assumes that all + individuals in a given population are susceptible to the disease, and that no preventive measures (such as lockdowns + or vaccinations) have been enforced. It is a useful indicator of the transmissibility of an infectious disease during + the early stages of its spread and detection. </p> <p> - If <em>R<sub>0</sub></em> < 1, the disease will eventually die out. On the other hand, if - <em>R<sub>0</sub></em> > 1, the disease will spread (the higher the <em>R<sub>0</sub></em>, the faster this will happen). Due to uncertainty of known data about the disease, it is difficult to - determine <em>R<sub>0</sub></em> precisely. - Therefore, many estimation methods exist, each based on different assumptions and yielding different estimates. It is the - responsibility of users to employ the most appropriate estimator (or suite of estimators) given the situation at hand. + If <em>R</em><sub>0</sub> < 1, the disease will eventually die out. On the other hand, if + <em>R</em><sub>0</sub> > 1, the disease will spread (the higher the <em>R</em><sub>0</sub>, the faster this will + happen). Due to uncertainty of known data about the disease, it is difficult to determine <em>R</em><sub>0</sub> + precisely. Therefore, many estimation methods exist, each based on different assumptions and yielding different + estimates. It is the responsibility of users to employ the most appropriate estimator (or suite of estimators) given + the situation at hand. </p> diff --git a/inst/app/templates/content/data.html b/inst/app/templates/content/data.html index eaae571..574f003 100644 --- a/inst/app/templates/content/data.html +++ b/inst/app/templates/content/data.html @@ -2,7 +2,6 @@ <a class="nav-link active" data-bs-toggle="tab" href="#enter-data">Enter data</a> <a class="nav-link" data-bs-toggle="tab" href="#view-data">View data</a> </nav> - <div class="container-fluid tab-content"> <div id="enter-data" class="pt-3 tab-pane fade show active"> {{ htmlTemplate("templates/content/data/enter-data.html") }} diff --git a/inst/app/templates/content/data/enter-data.html b/inst/app/templates/content/data/enter-data.html index 77846fa..254f1d7 100644 --- a/inst/app/templates/content/data/enter-data.html +++ b/inst/app/templates/content/data/enter-data.html @@ -1,8 +1,9 @@ -
-<form class="mb-5">
- {{ htmlTemplate("templates/content/data/enter-data/entry.html") }}
-</form>
-<hr>
-<form>
- {{ htmlTemplate("templates/content/data/enter-data/load-samples.html") }}
-</form>
+<form class="mb-5"> + {{ htmlTemplate("templates/content/data/enter-data/required-format.html") }} + {{ htmlTemplate("templates/content/data/enter-data/manual-entry.html") }} + {{ htmlTemplate("templates/content/data/enter-data/upload-data.html") }} +</form> +<hr> +<form> + {{ htmlTemplate("templates/content/data/enter-data/load-samples.html") }} +</form> diff --git a/inst/app/templates/content/data/enter-data/bulk-entry.html b/inst/app/templates/content/data/enter-data/bulk-entry.html deleted file mode 100644 index 30fab06..0000000 --- a/inst/app/templates/content/data/enter-data/bulk-entry.html +++ /dev/null @@ -1,48 +0,0 @@ -<h4 class="mb-3">Bulk entry</h4> -<!-- Button to toggle help text. --> -<button type="button" class="btn btn-outline-primary btn-sm" id="bulk-help-toggle" - data-bs-toggle="collapse" data-bs-target="#bulk-help">Show required format</button> -<!-- Help text for bulk input format. --> -<div class="collapse mt-2" id="bulk-help"> - <div class="card card-body border-primary"> - <p>Manually enter rows or upload a CSV file in the following format:</p> - <p class="overflow-x-scroll text-nowrap font-monospace"> - <u>Dataset name</u>,<u>Time units</u>,<u>Case counts</u> - </p> - <p> - <u class="font-monospace">Time units</u> must be one of - <u class="font-monospace">Days</u> or - <u class="font-monospace">Weeks</u>, and - <u class="font-monospace">Case counts</u> - must be a comma-separated list of one or more non-negative integers. - </p> - <p>Example:</p> - <p class="overflow-x-scroll text-nowrap font-monospace lh-sm"> - Montreal,Days,1,2,3,4,5,6,7,8,9,19<br> - Ottawa,Weeks,1,2,3,4,5,6,7,8,9,19<br> - Toronto,Days,1,2,3,4,5,6,7,8,9,19 - </p> - </div> -</div> -<!-- Data input area. --> -<div class="my-4"> - <label class="form-label" for="data_area">Enter manually</label> - <textarea id="data_area" class="form-control" rows="3" wrap="off"></textarea> - <div> - <small id="data_area_warn" class="form-text text-primary shiny-html-output"></small> - </div> - <button id="data_bulk" type="button" class="btn btn-outline-primary btn-sm action-button mt-3"> - <span class="glyphicon glyphicon-plus"></span> Add - </button> -</div> -<!-- File input for data upload (hidden). --> -<input class="form-control" type="file" id="data_upload" accept="text/csv,text/comma-separated-values,text/plain,.csv"> -<!-- Custom button to trigger file selector for data upload (visible). --> -<label class="form-label" for="data-upload-select">Upload a CSV file</label> -<div class="input-group"> - <button id="data-upload-select" type="button" class="btn btn-outline-primary btn-sm"> - <span class="glyphicon glyphicon-file"></span> Select file - </button> - <input type="text" id="data-upload-name" class="form-control" placeholder="No file selected" disabled> -</div> -<small id="data_upload_warn" class="form-text text-primary shiny-html-output"></small> diff --git a/inst/app/templates/content/data/enter-data/entry.html b/inst/app/templates/content/data/enter-data/entry.html deleted file mode 100644 index be43625..0000000 --- a/inst/app/templates/content/data/enter-data/entry.html +++ /dev/null @@ -1,48 +0,0 @@ -
-<!-- Button to toggle help text. -->
-<button type="button" class="btn btn-outline-primary btn-sm" id="bulk-help-toggle"
- data-bs-toggle="collapse" data-bs-target="#bulk-help">Show required format</button>
-<!-- Help text for bulk input format. -->
-<div class="collapse mt-2" id="bulk-help">
- <div class="card card-body border-primary">
- <p>Manually enter rows or upload a CSV file in the following format:</p>
- <p class="overflow-x-scroll text-nowrap font-monospace">
- <u>Dataset name</u>,<u>Time units</u>,<u>Case counts</u>
- </p>
- <p>
- <u class="font-monospace">Time units</u> must be one of
- <u class="font-monospace">Days</u> or
- <u class="font-monospace">Weeks</u>, and
- <u class="font-monospace">Case counts</u>
- must be a comma-separated list of one or more non-negative integers.
- </p>
- <p>Example:</p>
- <p class="overflow-x-scroll text-nowrap font-monospace lh-sm">
- Montreal,Days,1,2,3,4,5,6,7,8,9,19<br>
- Ottawa,Weeks,1,2,3,4,5,6,7,8,9,19<br>
- Toronto,Days,1,2,3,4,5,6,7,8,9,19
- </p>
- </div>
-</div>
-<!-- Data input area. -->
-<div class="my-4">
- <label class="form-label" for="data_area">Enter manually</label>
- <textarea id="data_area" class="form-control" rows="3" wrap="off"></textarea>
- <div>
- <small id="data_area_warn" class="form-text text-primary shiny-html-output"></small>
- </div>
- <button id="data_bulk" type="button" class="btn btn-outline-primary btn-sm action-button mt-3">
- <span class="glyphicon glyphicon-plus"></span> Add
- </button>
-</div>
-<!-- File input for data upload (hidden). -->
-<input class="form-control" type="file" id="data_upload" accept="text/csv,text/comma-separated-values,text/plain,.csv">
-<!-- Custom button to trigger file selector for data upload (visible). -->
-<label class="form-label" for="data-upload-select">Upload a CSV file</label>
-<div class="input-group">
- <button id="data-upload-select" type="button" class="btn btn-outline-primary btn-sm">
- <span class="glyphicon glyphicon-file"></span> Select file
- </button>
- <input type="text" id="data-upload-name" class="form-control" placeholder="No file selected" disabled>
-</div>
-<small id="data_upload_warn" class="form-text text-primary shiny-html-output"></small>
diff --git a/inst/app/templates/content/data/enter-data/load-samples.html b/inst/app/templates/content/data/enter-data/load-samples.html index a42a8c8..2a4f013 100644 --- a/inst/app/templates/content/data/enter-data/load-samples.html +++ b/inst/app/templates/content/data/enter-data/load-samples.html @@ -1,4 +1,5 @@ <h4 class="mb-3">Load samples</h4> +<!-- Checkboxes for sample data. --> {{ checkboxInput(inputId = "covid_canada", label = "COVID-19 Canada, 2020/03/03 - 2020/03/31 (Weekly)", value = FALSE, width = "100%" @@ -9,6 +10,7 @@ value = FALSE, width = "100%" ) }} +<!-- Warning text. --> <div> <small id="data_samples_warn" class="form-text text-primary shiny-text-output"></small> </div> diff --git a/inst/app/templates/content/data/enter-data/manual-entry.html b/inst/app/templates/content/data/enter-data/manual-entry.html new file mode 100644 index 0000000..a6319d9 --- /dev/null +++ b/inst/app/templates/content/data/enter-data/manual-entry.html @@ -0,0 +1,11 @@ +<!-- Data input area (manual entry). --> +<div class="my-4"> + <label class="form-label" for="data_area">Enter manually</label> + <textarea id="data_area" class="form-control" rows="3" wrap="off"></textarea> + <div> + <small id="data_area_warn" class="form-text text-primary shiny-html-output"></small> + </div> + <button id="data_bulk" type="button" class="btn btn-outline-primary btn-sm action-button mt-3"> + <span class="glyphicon glyphicon-plus"></span> Add + </button> +</div> diff --git a/inst/app/templates/content/data/enter-data/required-format.html b/inst/app/templates/content/data/enter-data/required-format.html new file mode 100644 index 0000000..724dd83 --- /dev/null +++ b/inst/app/templates/content/data/enter-data/required-format.html @@ -0,0 +1,25 @@ +<!-- Button to toggle help text. --> +<button type="button" class="btn btn-outline-primary btn-sm" id="data-format-toggle" + data-bs-toggle="collapse" data-bs-target="#data-format">Show required format</button> +<!-- Help text for data input format. --> +<div class="collapse mt-2" id="data-format"> + <div class="card card-body border-primary"> + <p>Manually enter rows or upload a CSV file in the following format:</p> + <p class="overflow-x-scroll text-nowrap font-monospace"> + <u>Dataset name</u>,<u>Time units</u>,<u>Case counts</u> + </p> + <p> + <u class="font-monospace">Time units</u> must be one of + <u class="font-monospace">Days</u> or + <u class="font-monospace">Weeks</u>, and + <u class="font-monospace">Case counts</u> + must be a comma-separated list of one or more non-negative integers. + </p> + <p>Example:</p> + <p class="overflow-x-scroll text-nowrap font-monospace lh-sm"> + Disease A,Days,1,2,3,4,5,6,7,8,9<br> + Disease B,Weeks,3,1,4,1,5,2,9<br> + Disease C,Days,2,3,5,7,11,13,17,19 + </p> + </div> +</div> diff --git a/inst/app/templates/content/data/enter-data/single-entry.html b/inst/app/templates/content/data/enter-data/single-entry.html deleted file mode 100644 index 9f249d9..0000000 --- a/inst/app/templates/content/data/enter-data/single-entry.html +++ /dev/null @@ -1,39 +0,0 @@ -<h4>Single entry</h4> -<!-- Dataset name. --> -<div class="my-3"> - <label class="form-label" for="data_name">Dataset name</label> - <input name="data_name" class="form-control" type="text"> - <small id="data_name_warn" class="form-text text-primary shiny-text-output"></small> -</div> -<!-- Case counts. --> -<div class="mb-3"> - <label class="form-label" for="data_counts"> - Case counts - <sup data-bs-toggle="tooltip" data-bs-placement="right" - data-bs-title="Enter as a comma-separated list of non-negative integers (example: 0,1,1,2,3,5,8,13)."> - [?] - </sup> - </label> - <input name="data_counts" class="form-control" type="text"> - <small id="data_counts_warn" class="form-text text-primary shiny-text-output"></small> -</div> -<!-- Time units. --> -<div class="mb-3"> - <label class="form-label" for="data_units">Time units</label> - <div class="shiny-input-radiogroup" id="data_units"> - <div class="form-check form-check-inline"> - <label class="form-check-label"> - <input type="radio" class="form-check-input me-2" name="data_units" value="Days">Days - </label> - </div> - <div class="form-check form-check-inline"> - <label class="form-check-label"> - <input type="radio" class="form-check-input me-2" name="data_units" value="Weeks" checked>Weeks - </label> - </div> - </div> -</div> -<!-- Submit data. --> -<button id="data_single" type="button" class="btn btn-outline-primary btn-sm action-button"> - <span class="glyphicon glyphicon-plus"></span> Add -</button> diff --git a/inst/app/templates/content/data/enter-data/upload-data.html b/inst/app/templates/content/data/enter-data/upload-data.html new file mode 100644 index 0000000..740047b --- /dev/null +++ b/inst/app/templates/content/data/enter-data/upload-data.html @@ -0,0 +1,12 @@ +<!-- File input for data upload (hidden). --> +<input class="form-control" type="file" id="data_upload" accept="text/csv,text/comma-separated-values,text/plain,.csv"> +<!-- Custom button to trigger file selector for data upload (visible). --> +<label class="form-label" for="data-upload-select">Upload a CSV file</label> +<div class="input-group"> + <button id="data-upload-select" type="button" class="btn btn-outline-primary btn-sm"> + <span class="glyphicon glyphicon-file"></span> Select file + </button> + <input type="text" id="data-upload-name" class="form-control" placeholder="No file selected" disabled> +</div> +<!-- Warning text. --> +<small id="data_upload_warn" class="form-text text-primary shiny-html-output"></small> diff --git a/inst/app/templates/content/data/view-data.html b/inst/app/templates/content/data/view-data.html index 52f1e85..880cf7f 100644 --- a/inst/app/templates/content/data/view-data.html +++ b/inst/app/templates/content/data/view-data.html @@ -1,19 +1,3 @@ -<h4>Data table</h4> -<!-- Data table. --> -<div class="my-3"> - {{ DT::dataTableOutput(outputId = "data_table") }} -</div> -<!-- Display inactive delete button when no rows are selected. --> -<button type="button" class="btn btn-primary btn-sm text-white" disabled - data-display-if="'data_table_rows_selected' in input && input.data_table_rows_selected.length == 0"> - <span class="glyphicon glyphicon-remove"></span> Delete row(s) -</button> -<!-- Display active delete button when at least one row is selected. --> -<button id="data_delete" type="button" class="btn btn-primary btn-sm action-button text-white" - data-display-if="'data_table_rows_selected' in input && input.data_table_rows_selected.length != 0"> - <span class="glyphicon glyphicon-remove"></span> Delete row(s) -</button> -<!-- Button to export data table as a CSV file. --> -<a id="data_export" type="button" class="btn btn-outline-primary btn-sm shiny-download-link"> - <span class="glyphicon glyphicon-download-alt"></span> Export table -</a> +{{ htmlTemplate("templates/content/data/view-data/data-table.html") }} +<hr> +{{ htmlTemplate("templates/content/data/view-data/data-plots.html") }} diff --git a/inst/app/templates/content/data/view-data/data-plots.html b/inst/app/templates/content/data/view-data/data-plots.html new file mode 100644 index 0000000..5019088 --- /dev/null +++ b/inst/app/templates/content/data/view-data/data-plots.html @@ -0,0 +1,7 @@ +<h4>Data plots</h4> +<div class="container my-5"> + {{ plotly::plotlyOutput(outputId = "data_plot_days") }} +</div> +<div class="container"> + {{ plotly::plotlyOutput(outputId = "data_plot_weeks") }} +</div> diff --git a/inst/app/templates/content/data/view-data/data-table.html b/inst/app/templates/content/data/view-data/data-table.html new file mode 100644 index 0000000..590a5b9 --- /dev/null +++ b/inst/app/templates/content/data/view-data/data-table.html @@ -0,0 +1,18 @@ +<h4>Data table</h4> +<div class="my-3"> + {{ DT::dataTableOutput(outputId = "data_table") }} +</div> +<!-- Display inactive delete button when no rows are selected. --> +<button type="button" class="btn btn-primary btn-sm text-white" disabled + data-display-if="'data_table_rows_selected' in input && input.data_table_rows_selected.length == 0"> + <span class="glyphicon glyphicon-remove"></span> Delete row(s) +</button> +<!-- Display active delete button when at least one row is selected. --> +<button id="data_delete" type="button" class="btn btn-primary btn-sm action-button text-white" + data-display-if="'data_table_rows_selected' in input && input.data_table_rows_selected.length != 0"> + <span class="glyphicon glyphicon-remove"></span> Delete row(s) +</button> +<!-- Button to export data table as a CSV file. --> +<a id="data_export" type="button" class="btn btn-outline-primary btn-sm shiny-download-link"> + <span class="glyphicon glyphicon-download-alt"></span> Export table +</a> diff --git a/inst/app/templates/content/estimation.html b/inst/app/templates/content/estimation.html new file mode 100644 index 0000000..5764057 --- /dev/null +++ b/inst/app/templates/content/estimation.html @@ -0,0 +1,13 @@ +<nav class="nav nav-tabs"> + <a class="nav-link active" data-bs-toggle="tab" href="#about-estimators">About the estimators</a> + <a class="nav-link" data-bs-toggle="tab" href="#estimates">Compute and view estimates</a> +</nav> + +<div class="container-fluid tab-content"> + <div id="about-estimators" class="pt-3 tab-pane fade show active"> + {{ htmlTemplate("templates/content/estimation/about-estimators.html") }} + </div> + <div id="estimates" class="pt-3 tab-pane fade"> + {{ htmlTemplate("templates/content/estimation/estimates.html") }} + </div> +</div> diff --git a/inst/app/templates/content/estimation/about-estimators.html b/inst/app/templates/content/estimation/about-estimators.html new file mode 100644 index 0000000..db2898b --- /dev/null +++ b/inst/app/templates/content/estimation/about-estimators.html @@ -0,0 +1,31 @@ +<div class="accordion accordion-flush" id="estimation-accordion"> + {{ + htmlTemplate("templates/content/estimation/about-estimators/panel.html", + id = "id", + header = "Incidence Decay (ID)", + reference_label = "Fisman et al. (PloS One, 2013)", + reference_url = "https://doi.org/10.1371/journal.pone.0083622" + ) + }} + {{ + htmlTemplate("templates/content/estimation/about-estimators/panel.html", + id = "idea", header = "Incidence Decay and Exponential Adjustment (IDEA)", + reference_label = "Fisman et al. (PloS One, 2013)", + reference_url = "https://doi.org/10.1371/journal.pone.0083622" + ) + }} + {{ + htmlTemplate("templates/content/estimation/about-estimators/panel.html", + id = "seq_bayes", header = "Sequential Bayes (seqB)", + reference_label = "Bettencourt and Riberio (PloS One, 2008)", + reference_url = "https://doi.org/10.1371/journal.pone.0002185" + ) + }} + {{ + htmlTemplate("templates/content/estimation/about-estimators/panel.html", + id = "wp", header = "White and Pagano (WP)", + reference_label = "White and Pagano (Statistics in Medicine, 2008)", + reference_url = "https://doi.org/10.1002/sim.3136" + ) + }} +</div> diff --git a/inst/app/templates/content/estimation/about-estimators/id.html b/inst/app/templates/content/estimation/about-estimators/id.html new file mode 100644 index 0000000..3200c00 --- /dev/null +++ b/inst/app/templates/content/estimation/about-estimators/id.html @@ -0,0 +1,5 @@ +The incidence decay (ID) estimator assumes an exponential model and finds the parameters by minimizing the sum of the +squared differences between the observed cases counts and the case counts expected based on the assumed model. +The method assumes that the serial interval is known. This means that the user needs to input the value of the serial +interval. The serial interval is the average time between the first infection and the time the first infected individual +exhibits disease symptoms. diff --git a/inst/app/templates/content/estimators/add-estimators/descriptions/idea.html b/inst/app/templates/content/estimation/about-estimators/idea.html index edfbb79..edfbb79 100644 --- a/inst/app/templates/content/estimators/add-estimators/descriptions/idea.html +++ b/inst/app/templates/content/estimation/about-estimators/idea.html diff --git a/inst/app/templates/content/estimators/add-estimators/components/panel.html b/inst/app/templates/content/estimation/about-estimators/panel.html index b1e0378..98fe155 100644 --- a/inst/app/templates/content/estimators/add-estimators/components/panel.html +++ b/inst/app/templates/content/estimation/about-estimators/panel.html @@ -8,14 +8,7 @@ <div id="{{ id }}" class="accordion-collapse collapse" data-bs-parent="#estimators-accordion"> <div class="accordion-body"> <p>Reference: <a href="{{ reference_url }}" target="_blank"><em>{{ reference_label }}</em></a></p> - <p>{{ htmlTemplate(paste0("templates/content/estimators/add-estimators/descriptions/", id, ".html")) }}</p> - <h5>Parameters</h5> - <form class="my-3"> - {{ htmlTemplate(paste0("templates/content/estimators/add-estimators/parameters/", id, ".html")) }} - </form> - <button id="add_{{ id }}" type="button" class="btn btn-outline-primary btn-sm action-button"> - <span class="glyphicon glyphicon-plus"></span> Add - </button> + <p>{{ htmlTemplate(paste0("templates/content/estimation/about-estimators/", id, ".html")) }}</p> </div> </div> </div> diff --git a/inst/app/templates/content/estimators/add-estimators/descriptions/seq_bayes.html b/inst/app/templates/content/estimation/about-estimators/seq_bayes.html index f6df3ee..f6df3ee 100644 --- a/inst/app/templates/content/estimators/add-estimators/descriptions/seq_bayes.html +++ b/inst/app/templates/content/estimation/about-estimators/seq_bayes.html diff --git a/inst/app/templates/content/estimators/add-estimators/descriptions/wp.html b/inst/app/templates/content/estimation/about-estimators/wp.html index 640b44d..640b44d 100644 --- a/inst/app/templates/content/estimators/add-estimators/descriptions/wp.html +++ b/inst/app/templates/content/estimation/about-estimators/wp.html diff --git a/inst/app/templates/content/estimation/estimates.html b/inst/app/templates/content/estimation/estimates.html new file mode 100644 index 0000000..bc9124e --- /dev/null +++ b/inst/app/templates/content/estimation/estimates.html @@ -0,0 +1,3 @@ +{{ htmlTemplate("templates/content/estimation/estimates/estimates-table.html") }} +<hr> +{{ htmlTemplate("templates/content/estimation/estimates/add-estimators.html") }} diff --git a/inst/app/templates/content/estimation/estimates/add-estimators.html b/inst/app/templates/content/estimation/estimates/add-estimators.html new file mode 100644 index 0000000..60111c7 --- /dev/null +++ b/inst/app/templates/content/estimation/estimates/add-estimators.html @@ -0,0 +1,16 @@ +<h4>Add estimators</h4> +<form class="my-3"> + <!-- Dropdown to select estimator. --> + <label class="form-label" for="estimator_select">Select estimator:</label> + <select name="estimator_select" class="form-select"> + <option value="id" selected>Incidence Decay (ID)</option> + <option value="idea">Incidence Decay and Exponential Adjustment (IDEA)</option> + <option value="seq_bayes">Sequential Bayes (seqB)</option> + <option value="wp">White and Pagano (WP)</option> + </select> + <!-- Parameters. --> + {{ htmlTemplate("templates/content/estimation/estimates/add-estimators/parameters.html", id = "id") }} + {{ htmlTemplate("templates/content/estimation/estimates/add-estimators/parameters.html", id = "idea") }} + {{ htmlTemplate("templates/content/estimation/estimates/add-estimators/parameters.html", id = "seq_bayes") }} + {{ htmlTemplate("templates/content/estimation/estimates/add-estimators/parameters.html", id = "wp") }} +</form> diff --git a/inst/app/templates/content/estimation/estimates/add-estimators/id.html b/inst/app/templates/content/estimation/estimates/add-estimators/id.html new file mode 100644 index 0000000..7c35e55 --- /dev/null +++ b/inst/app/templates/content/estimation/estimates/add-estimators/id.html @@ -0,0 +1 @@ +{{ htmlTemplate("templates/content/estimation/estimates/add-estimators/mu.html", id = "id") }} diff --git a/inst/app/templates/content/estimation/estimates/add-estimators/idea.html b/inst/app/templates/content/estimation/estimates/add-estimators/idea.html new file mode 100644 index 0000000..781349f --- /dev/null +++ b/inst/app/templates/content/estimation/estimates/add-estimators/idea.html @@ -0,0 +1 @@ +{{ htmlTemplate("templates/content/estimation/estimates/add-estimators/mu.html", id = "idea") }} diff --git a/inst/app/templates/content/estimators/add-estimators/components/mu.html b/inst/app/templates/content/estimation/estimates/add-estimators/mu.html index f25a1c8..8781574 100644 --- a/inst/app/templates/content/estimators/add-estimators/components/mu.html +++ b/inst/app/templates/content/estimation/estimates/add-estimators/mu.html @@ -1,6 +1,6 @@ <!-- Serial interval label and help tooltip. --> <label class="form-label" for="mu_{{ id }}"> - Serial interval (μ) + Serial interval <sup data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="The serial interval is the time between when an infected individual (the infector) becomes symptomatic, to when another individual (who is infected by the infector) becomes symptomatic."> @@ -17,4 +17,6 @@ </select> </div> <!-- Warning text for incorrect values. --> -<small id="mu_{{ id }}_warn" class="form-text text-primary shiny-text-output"></small> +<div> + <small id="mu_{{ id }}_warn" class="form-text text-primary shiny-text-output"></small> +</div> diff --git a/inst/app/templates/content/estimation/estimates/add-estimators/parameters.html b/inst/app/templates/content/estimation/estimates/add-estimators/parameters.html new file mode 100644 index 0000000..5250e31 --- /dev/null +++ b/inst/app/templates/content/estimation/estimates/add-estimators/parameters.html @@ -0,0 +1,7 @@ +<div class="my-4" data-display-if="input.estimator_select === '{{ id }}'"> + <h5>Parameters</h5> + {{ htmlTemplate(paste0("templates/content/estimation/estimates/add-estimators/", id, ".html")) }} + <button id="add_{{ id }}" type="button" class="btn btn-outline-primary btn-sm action-button mt-3"> + <span class="glyphicon glyphicon-plus"></span> Add + </button> +</div> diff --git a/inst/app/templates/content/estimators/add-estimators/parameters/seq_bayes.html b/inst/app/templates/content/estimation/estimates/add-estimators/seq_bayes.html index bcc82b7..028fabc 100644 --- a/inst/app/templates/content/estimators/add-estimators/parameters/seq_bayes.html +++ b/inst/app/templates/content/estimation/estimates/add-estimators/seq_bayes.html @@ -1,7 +1,7 @@ <div class="row"> <!-- Serial interval (mu). --> <div class="col-md"> - {{ htmlTemplate("templates/content/estimators/add-estimators/components/mu.html", id = "seq_bayes") }} + {{ htmlTemplate("templates/content/estimation/estimates/add-estimators/mu.html", id = "seq_bayes") }} </div> <!-- Maximum value of the uniform prior (kappa). --> <div class="col-md mt-2 mt-md-0"> @@ -9,8 +9,8 @@ <label class="form-label" for="kappa"> Maximum prior (κ) <sup data-bs-toggle="tooltip" data-bs-placement="right" data-bs-html="true" - data-bs-title="The initial maximum belief of <em>R<sub>0</sub></em>. The higher this value, the higher - <em>R<sub>0</sub></em> is believed to be prior to the estimation."> + data-bs-title="The initial maximum belief of <em>R</em><sub>0</sub>. The higher this value, the higher + <em>R</em><sub>0</sub> is believed to be prior to the estimation."> [?] </sup> </label> diff --git a/inst/app/templates/content/estimators/add-estimators/parameters/wp.html b/inst/app/templates/content/estimation/estimates/add-estimators/wp.html index b789a23..511170f 100644 --- a/inst/app/templates/content/estimators/add-estimators/parameters/wp.html +++ b/inst/app/templates/content/estimation/estimates/add-estimators/wp.html @@ -14,7 +14,7 @@ </div> <!-- Show the input field for the serial interval if it is known. --> <div data-display-if="input.wp_mu_known == 'Yes'" class="mt-2 mt-md-0"> - {{ htmlTemplate("templates/content/estimators/add-estimators/components/mu.html", id = "wp") }} + {{ htmlTemplate("templates/content/estimation/estimates/add-estimators/mu.html", id = "wp") }} </div> <!-- Show the input fields for the grid search parameters if the serial interval is unknown. --> <div data-display-if="input.wp_mu_known == 'No'" class="row"> diff --git a/inst/app/templates/content/estimation/estimates/estimates-table.html b/inst/app/templates/content/estimation/estimates/estimates-table.html new file mode 100644 index 0000000..4704d03 --- /dev/null +++ b/inst/app/templates/content/estimation/estimates/estimates-table.html @@ -0,0 +1,19 @@ +<h4>Estimates table</h4> +<!-- Estimates table. --> +<div class="my-3"> + {{ DT::dataTableOutput(outputId = "estimates_table") }} +</div> +<!-- Display inactive delete button when no rows are selected. --> +<button type="button" class="btn btn-primary btn-sm text-white" disabled + data-display-if="'estimates_table_rows_selected' in input && input.estimates_table_rows_selected.length == 0"> + <span class="glyphicon glyphicon-remove"></span> Delete row(s) +</button> +<!-- Display active delete button when at least one row is selected. --> +<button id="estimators_delete" type="button" class="btn btn-primary btn-sm action-button text-white" + data-display-if="'estimates_table_rows_selected' in input && input.estimates_table_rows_selected.length != 0"> + <span class="glyphicon glyphicon-remove"></span> Delete row(s) +</button> +<!-- Button to export estimates table as a CSV file. --> +<a id="estimates_export" type="button" class="btn btn-outline-primary btn-sm shiny-download-link"> + <span class="glyphicon glyphicon-download-alt"></span> Export table +</a> diff --git a/inst/app/templates/content/estimators.html b/inst/app/templates/content/estimators.html deleted file mode 100644 index 133241a..0000000 --- a/inst/app/templates/content/estimators.html +++ /dev/null @@ -1,13 +0,0 @@ -<nav class="nav nav-tabs"> - <a class="nav-link active" data-bs-toggle="tab" href="#add-estimators">About the estimators</a> - <a class="nav-link" data-bs-toggle="tab" href="#view-estimates">Select and compute estimates</a> -</nav> - -<div class="container-fluid tab-content"> - <div id="add-estimators" class="pt-3 tab-pane fade show active"> - {{ htmlTemplate("templates/content/estimators/add-estimators.html") }} - </div> - <div id="view-estimates" class="pt-3 tab-pane fade"> - {{ htmlTemplate("templates/content/estimators/view-estimates.html") }} - </div> -</div> diff --git a/inst/app/templates/content/estimators/add-estimators.html b/inst/app/templates/content/estimators/add-estimators.html deleted file mode 100644 index 0d7562e..0000000 --- a/inst/app/templates/content/estimators/add-estimators.html +++ /dev/null @@ -1,19 +0,0 @@ -<div class="accordion accordion-flush" id="estimators-accordion"> - {{ - htmlTemplate("templates/content/estimators/add-estimators/components/panel.html", - id = "id", header = "Incidence Decay (ID)", reference_label = "Fisman et al. - (PloS One, 2013)", reference_url = - "https://doi.org/10.1371/journal.pone.0083622" ) }} {{ - htmlTemplate("templates/content/estimators/add-estimators/components/panel.html", - id = "idea", header = "Incidence Decay and Exponential Adjustment (IDEA)", - reference_label = "Fisman et al. (PloS One, 2013)", reference_url = - "https://doi.org/10.1371/journal.pone.0083622" ) }} {{ - htmlTemplate("templates/content/estimators/add-estimators/components/panel.html", - id = "seq_bayes", header = "Sequential Bayes (seqB)", reference_label = - "Bettencourt and Riberio (PloS One, 2008)", reference_url = - "https://doi.org/10.1371/journal.pone.0002185" ) }} {{ - htmlTemplate("templates/content/estimators/add-estimators/components/panel.html", - id = "wp", header = "White and Pagano (WP)", reference_label = "White and - Pagano (Statistics in Medicine, 2008)", reference_url = - "https://doi.org/10.1002/sim.3136" ) }} -</div> diff --git a/inst/app/templates/content/estimators/add-estimators/descriptions/id.html b/inst/app/templates/content/estimators/add-estimators/descriptions/id.html deleted file mode 100644 index b47850f..0000000 --- a/inst/app/templates/content/estimators/add-estimators/descriptions/id.html +++ /dev/null @@ -1 +0,0 @@ -The incidence decay (ID) estimator assumes an exponential model and finds the parameters by minimizing the sum of the squared differences between the observed cases counts and the case counts expected based on the assumed model. The method assumes that the serial interval is known. This means that the user needs to input the value of the serial interval. The serial interval is the average time between the first infection and the time the first infected individual exhibits disease symptoms. diff --git a/inst/app/templates/content/estimators/add-estimators/descriptions/mu.html b/inst/app/templates/content/estimators/add-estimators/descriptions/mu.html deleted file mode 100644 index 6e7bfe9..0000000 --- a/inst/app/templates/content/estimators/add-estimators/descriptions/mu.html +++ /dev/null @@ -1,7 +0,0 @@ -The serial interval (SI) is NOT one of the estimators. - -<p>The SI is a parameter required by all of the estimators, and can also be estimated by the WP method.</p> - -<p>The SI is defined as the average time between successive infections in a chain of transmission i.e., the time between the infection of an infected and their subsequent transmissions. </p> - -<P> Make the tab a different shade (light gray) and then this won't have parameters. It will let us not have to explain SI every single time. We'll expand the description later.</p> diff --git a/inst/app/templates/content/estimators/add-estimators/parameters/id.html b/inst/app/templates/content/estimators/add-estimators/parameters/id.html deleted file mode 100644 index a3159ca..0000000 --- a/inst/app/templates/content/estimators/add-estimators/parameters/id.html +++ /dev/null @@ -1 +0,0 @@ -{{ htmlTemplate("templates/content/estimators/add-estimators/components/mu.html", id = "id") }} diff --git a/inst/app/templates/content/estimators/add-estimators/parameters/idea.html b/inst/app/templates/content/estimators/add-estimators/parameters/idea.html deleted file mode 100644 index 379be84..0000000 --- a/inst/app/templates/content/estimators/add-estimators/parameters/idea.html +++ /dev/null @@ -1 +0,0 @@ -{{ htmlTemplate("templates/content/estimators/add-estimators/components/mu.html", id = "idea") }} diff --git a/inst/app/templates/content/estimators/add-estimators/parameters/mu.html b/inst/app/templates/content/estimators/add-estimators/parameters/mu.html deleted file mode 100644 index a3159ca..0000000 --- a/inst/app/templates/content/estimators/add-estimators/parameters/mu.html +++ /dev/null @@ -1 +0,0 @@ -{{ htmlTemplate("templates/content/estimators/add-estimators/components/mu.html", id = "id") }} diff --git a/inst/app/templates/content/estimators/view-estimates.html b/inst/app/templates/content/estimators/view-estimates.html deleted file mode 100644 index e81fff6..0000000 --- a/inst/app/templates/content/estimators/view-estimates.html +++ /dev/null @@ -1,21 +0,0 @@ -<h4>Estimates table</h4> -<!-- Estimates table. --> -<div class="my-3"> - {{ DT::dataTableOutput(outputId = "estimates_table") }} -</div> -<!-- Display inactive delete button when no columns are selected. --> -<button type="button" class="btn btn-primary btn-sm text-white" disabled - data-display-if="'estimates_table_columns_selected' in input && - input.estimates_table_columns_selected.length == 0"> - <span class="glyphicon glyphicon-remove"></span> Delete column(s) -</button> -<!-- Display active delete button when at least one column is selected. --> -<button id="estimators_delete" type="button" class="btn btn-primary btn-sm action-button text-white" - data-display-if="'estimates_table_columns_selected' in input && - input.estimates_table_columns_selected.length != 0"> - <span class="glyphicon glyphicon-remove"></span> Delete column(s) -</button> -<!-- Button to export estimates table as a CSV file. --> -<a id="estimates_export" type="button" class="btn btn-outline-primary btn-sm shiny-download-link"> - <span class="glyphicon glyphicon-download-alt"></span> Export table -</a> diff --git a/inst/app/templates/content/help.html b/inst/app/templates/content/help.html index 51192fc..df4e887 100644 --- a/inst/app/templates/content/help.html +++ b/inst/app/templates/content/help.html @@ -1,6 +1,8 @@ <div class="accordion accordion-flush" id="help-accordion"> - {{ htmlTemplate("templates/content/help/panel.html", id = "serial-interval", - header = "What is a Serial Interval(mu) ?" ) }} {{ - htmlTemplate("templates/content/help/panel.html", id = "example-help-2", - header = "Example help 2" ) }} + {{ + htmlTemplate("templates/content/help/panel.html", + id = "serial-interval", + header = "What is the serial interval?" + ) + }} </div> diff --git a/inst/app/templates/content/help/example-help-1.html b/inst/app/templates/content/help/example-help-1.html deleted file mode 100644 index 245b9b6..0000000 --- a/inst/app/templates/content/help/example-help-1.html +++ /dev/null @@ -1 +0,0 @@ -Example help 1 diff --git a/inst/app/templates/content/help/example-help-2.html b/inst/app/templates/content/help/example-help-2.html deleted file mode 100644 index a4817b5..0000000 --- a/inst/app/templates/content/help/example-help-2.html +++ /dev/null @@ -1 +0,0 @@ -Example help 2 diff --git a/inst/app/templates/content/help/serial-interval.html b/inst/app/templates/content/help/serial-interval.html index 88bf82c..e061115 100644 --- a/inst/app/templates/content/help/serial-interval.html +++ b/inst/app/templates/content/help/serial-interval.html @@ -1,18 +1,9 @@ -Reference -<a href="https://en.wikipedia.org/wiki/Serial_interval" target="_blank" - ><i>Wikipedia</i></a -> -<br /> -<br /> - -<p>The serial interval (SI) is NOT one of the estimators.</p> +<p>Reference: <a href="https://en.wikipedia.org/wiki/Serial_interval" target="_blank"><em>Wikipedia</em></a> <p> - The SI is a parameter required by all of the estimators, and can also be - estimated by the WP method. + The serial interval (SI) is not one of the estimators. It is a parameter required by most of the estimators, and can + also be estimated by some of them (if not specified). </p> - <p> - The SI is defined as the average time between successive infections in a chain - of transmission i.e., the time between the infection of an infected and their - subsequent transmissions. + The SI is defined as the average time between successive infections in a chain of transmission (i.e., the time between + the infection of an infected individual and their subsequent transmissions). </p> diff --git a/inst/app/templates/navbar.html b/inst/app/templates/navbar.html index 1f86953..d447fba 100644 --- a/inst/app/templates/navbar.html +++ b/inst/app/templates/navbar.html @@ -3,7 +3,7 @@ <!-- Project name and description. --> <a class="navbar-brand text-primary" href="/">Rnaught Web</a> <span class="navbar-text d-none d-md-block"> - An estimation suite for <em>R<sub>0</sub></em> + An estimation suite for <em>R</em><sub>0</sub> </span> <!-- Navigation toggler for smaller screens. --> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav-toggle"> diff --git a/inst/app/templates/tabs.html b/inst/app/templates/tabs.html index 22985f9..351b480 100644 --- a/inst/app/templates/tabs.html +++ b/inst/app/templates/tabs.html @@ -3,10 +3,10 @@ About <span class="glyphicon glyphicon-info-sign"></span> </a> <a class="nav-link rounded-0" data-bs-toggle="pill" href="#data"> - Upload Data <span class="glyphicon glyphicon-list-alt"></span> + Data <span class="glyphicon glyphicon-list-alt"></span> </a> - <a class="nav-link rounded-0" data-bs-toggle="pill" href="#estimators"> - Select and Compute Estimators <span class="glyphicon glyphicon-random"></span> + <a class="nav-link rounded-0" data-bs-toggle="pill" href="#estimation"> + Estimation <span class="glyphicon glyphicon-random"></span> </a> <a class="nav-link rounded-0" data-bs-toggle="pill" href="#help"> Help <span class="glyphicon glyphicon-question-sign"></span> diff --git a/inst/app/www/script.js b/inst/app/www/script.js index c31584f..30066d1 100644 --- a/inst/app/www/script.js +++ b/inst/app/www/script.js @@ -3,7 +3,7 @@ $(document).ready(() => { $('[data-bs-toggle="tooltip"]').tooltip(); // Toggle the text in the bulk data help button. - $('#bulk-help-toggle').on('click', event => { + $('#data-format-toggle').on('click', event => { btn = $(event.target); show_format = 'Show required format'; btn.text(btn.text() === show_format ? 'Hide required format' : show_format); diff --git a/inst/app/www/styles.css b/inst/app/www/styles.css index d53a387..a6fc3cd 100644 --- a/inst/app/www/styles.css +++ b/inst/app/www/styles.css @@ -8,23 +8,16 @@ noscript { text-align: center; } -.nav-pills .active { - color: white !important; +.shiny-notification { + background-color: black; + color: white; } -.action-button:hover, #bulk-help-toggle:hover, #data_export:hover { +.plotly-notifier .notifier-note { + background-color: black !important; color: white !important; } -#data_plot { - margin-top: -0.5rem; -} - -td.selected, .shiny-notification { - background-color: black; - color: white; -} - #data_upload { display: none; } |