1 # Main logic block for data-related interactions.
2 data_logic
<- function(input
, output
, react_values
) {
3 # Initialize a data frame to hold the datasets.
4 react_values$data_table
<- data.frame(
6 `Time units`
= character(0),
7 `Case counts`
= character(0),
11 render_plot(input
, output
)
12 single_entry(input
, output
, react_values
)
13 bulk_entry(input
, output
, react_values
)
14 upload_entry(input
, output
, react_values
)
15 sample_entry(input
, output
, react_values
)
16 render_data(output
, react_values
)
17 delete_data(input
, react_values
)
18 export_data(output
, react_values
)
21 warnings
<- function(df
, df_elems
) {
25 # Ensure the dataset names are neither blank nor duplicates.
26 if (anyNA(df_elems
[[1]]) || any(df_elems
[[1]] == "")) {
27 warning_text
<- paste0(warning_text
, sep
= "<br>",
28 "Each row must begin with a non-blank dataset name."
32 if (length(unique(df_elems
[[1]])) != length(df_elems
[[1]])) {
33 warning_text
<- paste0(warning_text
, sep
= "<br>",
34 "The rows contain duplicate dataset names."
38 if (any(df_elems
[[1]] %in% react_values$data_table
[, 1])) {
39 warning_text
<- paste0(warning_text
, sep
= "<br>",
40 "The rows contain dataset names which already exist."
43 # Ensure the second entry in each row is a time unit equal to
45 if (!all(df_elems
[[2]] %in% c("Days", "Weeks"))) {
46 warning_text
<- paste0(warning_text
, sep
= "<br>",
47 "The second entry in each row must be either 'Days' or 'Weeks'."
50 # Ensure the counts in each row have at least one non-negative integer.
51 if (any(df_elems
[[3]] == "")) {
52 warning_text
<- paste0(warning_text
, sep
= "<br>",
53 "Each row must contain at least one non-negative integer."
60 # Convert the input case counts string to an integer vector.
61 tokenize_counts
<- function(counts_str
) {
62 suppressWarnings(as.integer(unlist(strsplit(trimws(counts_str
), ","))))
65 # Render the preview plot for single entry data.
66 render_plot
<- function(input
, output
) {
68 counts
<- tokenize_counts(input$data_counts
)
69 if (length(counts
) > 0 && !anyNA(counts
) && all(counts
>= 0)) {
70 output$data_plot
<- renderPlot(
71 plot(seq_along(counts
) - 1, counts
, type
= "o", pch
= 16, col
= "black",
72 xlab
= input$data_units
, ylab
= "Cases", cex.lab
= 1.5,
73 xlim
= c(0, max(length(counts
) - 1, 1)), ylim
= c(0, max(counts
, 1))
77 output$data_plot
<- renderPlot(
78 plot(NULL, xlim
= c(0, 10), ylim
= c(0, 10),
79 xlab
= input$data_units
, ylab
= "Cases", cex.lab
= 1.5
86 # Add a single dataset to the existing table.
87 single_entry
<- function(input
, output
, react_values
) {
88 observeEvent(input$data_single
, {
91 # Ensure the dataset name is neither blank nor a duplicate.
92 name
<- trimws(input$data_name
)
94 output$data_name_warn
<- renderText("The dataset name cannot be blank.")
96 } else if (name
%in% react_values$data_table
[, 1]) {
97 output$data_name_warn
<- renderText(
98 "There is already a dataset with the specified name."
102 output$data_name_warn
<- renderText("")
105 # Ensure the case counts are specified as a comma-separated of one or more
106 # non-negative integers.
107 counts
<- tokenize_counts(input$data_counts
)
108 if (length(counts
) == 0) {
109 output$data_counts_warn
<- renderText("Case counts cannot be blank.")
111 } else if (anyNA(counts
) || any(counts
< 0)) {
112 output$data_counts_warn
<- renderText(
113 "Case counts can only contain non-negative integers."
117 output$data_counts_warn
<- renderText("")
121 # Add the new dataset to the data table.
122 new_row
<- data.frame(name
, input$data_units
, toString(counts
))
123 colnames(new_row
) <- c("Name", "Time units", "Case counts")
124 react_values$data_table
<- rbind(react_values$data_table
, new_row
)
126 # Evaluate all existing estimators on the new dataset and update the
127 # corresponding row in the estimates table.
128 update_estimates_rows(new_row
, react_values
)
130 showNotification("Dataset added successfully.",
131 duration
= 3, id
= "notify-success"
137 # Add multiple datasets to the existing table.
138 bulk_entry
<- function(input
, output
, react_values
) {
139 observeEvent(input$data_bulk
, {
142 datasets
<- read.csv(text
= input$data_area
, header
= FALSE, sep
= ",")
144 names
<- trimws(datasets
[, 1])
145 units
<- trimws(datasets
[, 2])
146 counts
<- apply(datasets
[, 3:ncol(datasets
)], 1,
148 row
<- suppressWarnings(as.integer(row
))
149 toString(row
[!is.na(row
) & row
>= 0])
152 output$data_area_warn
<- renderText("")
153 warning_text
<- warnings(datasets
, list(names
, units
, counts
))
155 if (warning_text
== "") {
156 # Add the new datasets to the data table.
157 new_rows
<- data.frame(names
, units
, counts
)
158 colnames(new_rows
) <- c("Name", "Time units", "Case counts")
159 react_values$data_table
<- rbind(react_values$data_table
, new_rows
)
161 # Evaluate all existing estimators on the new dataset and update the
162 # corresponding row in the estimates table.
163 update_estimates_rows(new_rows
, react_values
)
165 showNotification("Datasets added successfully.",
166 duration
= 3, id
= "notify-success"
169 output$data_area_warn
<- renderUI(HTML(warning_text
))
172 error
= function(e
) {
173 output$data_area_warn
<- renderText(
174 "The input does not match the required format."
181 # Upload datasets to the existing table.
182 upload_entry
<- function(input
, output
, react_values
) {
183 observeEvent(input$data_load
, {
186 df
<- read.csv(file
= input$upload_csv$datapath
)
187 names
<- trimws(df
[, 1])
188 units
<- trimws(df
[, 2])
189 counts
<- sapply(tokenize_counts(df
[, 3:ncol(df
)]),
191 row
<- suppressWarnings(as.integer(row
))
192 toString(row
[!is.na(row
) & row
>= 0])
195 output$data_load_warn
<- renderText("")
197 warning_text
<- warnings(df
, list(names
, units
, counts
))
199 if (warning_text
== "") {
201 # Add the new datasets to the data table.
202 new_rows
<- read.csv(file
= input$upload_csv$datapath
)
203 colnames(new_rows
) <- c("Name", "Time units", "Case counts")
204 react_values$data_table
<- rbind(react_values$data_table
, new_rows
)
206 # Evaluate all existing estimators on the new dataset and update the
207 # corresponding row in the estimates table.
208 update_estimates_rows(new_rows
, react_values
)
210 showNotification("Datasets added successfully.",
211 duration
= 3, id
= "notify-success")
215 output$data_load_warn
<- renderUI(HTML(warning_text
))
218 error
= function(e
) {
219 output$data_load_warn
<- renderText(
220 "The input does not match the required format."
227 # Add sample datasets to the existing table.
228 sample_entry
<- function(input
, output
, react_values
) {
229 observeEvent(input$sample_entry
, {
232 # datasets <- read.csv(text = input$sample, header = FALSE, sep = ",")
239 names
<- append(names
, c("Covid-19 March 2020"))
240 units
<-append(units
, c("Daily"))
241 counts
<-append(counts
,c(covid_cases
[1]))}
242 if (input$april
){ names
<- append(names
, c("Covid-19 April 2020"))
243 units
<-append(units
, c("Daily"))
244 counts
<-append(counts
,c(covid_cases
[2]))}
245 if (input$may
){ names
<- append(names
, c("Covid-19 May 2020"))
246 units
<-append(units
, c("Daily"))
247 counts
<-append(counts
,c(covid_cases
[3]))}
250 if (input$june
){ names
<- append(names
, c("Covid-19 June 2020"))
251 units
<-append(units
, c("Daily"))
252 counts
<-append(counts
,c(covid_cases
[4]))}
254 if (input$july
){ names
<- append(names
, c("Covid-19 July 2020"))
255 units
<-append(units
, c("Daily"))
256 counts
<-append(counts
,c(covid_cases
[5]))}
260 # Ensure the dataset names are not duplicates.
263 if (any(names
%in% react_values$data_table
[, 1])) {
264 warning_text
<- paste0(warning_text
, sep
= "<br>",
265 "The rows contain dataset names which already exist."
271 output$sample_area_warn
<- renderUI(HTML(warning_text
))
273 if (warning_text
== "") {
274 # Add the new datasets to the data table.
276 new_rows
<- data.frame(names
, units
, counts
)
277 colnames(new_rows
) <- c("Name", "Time units", "Case counts")
278 react_values$data_table
<- rbind(react_values$data_table
, new_rows
)
280 # Evaluate all existing estimators on the new dataset and update the
281 # corresponding row in the estimates table.
282 update_estimates_rows(new_rows
, react_values
)
284 showNotification("Datasets added successfully.",
285 duration
= 3, id
= "notify-success"
293 # Render the data table when new datasets are added.
294 render_data
<- function(output
, react_values
) {
296 output$data_table
<- DT
::renderDataTable(react_values$data_table
)
300 # Delete rows in the data table,
301 # and the corresponding rows in the estimates table.
302 delete_data
<- function(input
, react_values
) {
303 observeEvent(input$data_delete
, {
304 new_table
<- react_values$data_table
[-input$data_table_rows_selected
, ]
305 if (nrow(new_table
) > 0) {
306 rownames(new_table
) <- seq_len(nrow(new_table
))
308 react_values$data_table
<- new_table
310 if (ncol(react_values$estimates_table
) == 1) {
311 react_values$estimates_table
<- data.frame(
312 Datasets
= react_values$data_table
[, 1]
315 react_values$estimates_table
<-
316 react_values$estimates_table
[-input$data_table_rows_selected
, ]
321 # Export data table as a CSV file.
322 export_data
<- function(output
, react_values
) {
323 output$data_export
<- downloadHandler(
324 filename
= function() {
325 paste0("Rnaught_data_", format(Sys.time(), "%y-%m-%d_%H-%M-%S"), ".csv")
327 content
= function(file
) {
328 write.csv(react_values$data_table
, file
, row.names
= FALSE)
333 # When new datasets are added, evaluate all existing estimators on them and
334 # add new rows to the estimates table.
335 update_estimates_rows
<- function(datasets
, react_values
) {
336 new_rows
<- data.frame(
337 matrix(nrow
= nrow(datasets
), ncol
= ncol(react_values$estimates_table
))
339 colnames(new_rows
) <- colnames(react_values$estimates_table
)
341 for (row
in seq_len(nrow(datasets
))) {
342 new_rows
[row
, 1] <- datasets
[row
, 1]
344 if (length(react_values$estimators
) > 0) {
345 for (col
in 2:ncol(react_values$estimates_table
)) {
346 new_rows
[row
, col
] <- eval_estimator(
347 react_values$estimators
[[col
- 1]], datasets
[row
, ]
353 react_values$estimates_table
<- rbind(
354 react_values$estimates_table
, new_rows
357 #Sample datasets case counts
358 covid_cases
= c("7,1,13,10,6,10,13,28,47,53,62,90,88,130,143,150,186,276,279,350,458,604,570,667,878,883,785,1085,1252",
359 "1469,1278,1346,1119,1109,1120,1202,1429,1178,1337,1165,1312,1551,1633,1870,1688,1888,1702,1535,1549,1563,1583,1777,1511,1482,1298,1350,1422,1502,1546",
360 "1499,1330,1232,1205,1101,1306,1317,1187,1115,997,953,903,1086,1101,1198,1133,1219,1057,954,1061,1056,1094,922,884,963,660,762,781,1038,763,827",
361 "678,656,602,545,557,497,464,411,391,481,402,427,380,322,309,345,358,375,373,300,315,340,288,297,280,330,344,358,242,267",
362 "315,291,267,284,244,220,269,313,359,343,348,351,277,362,451,443,517,490,457,472,507,509,573,497,425,408,344,493,405,466,455")