]> nmode's Git Repositories - Rnaught/blob - data.R
Sample data and Upload data
[Rnaught] / data.R
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(
5 Name = character(0),
6 `Time units` = character(0),
7 `Case counts` = character(0),
8 check.names = FALSE
9 )
10
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)
19 }
20
21 warnings <- function(df, df_elems) {
22
23 warning_text <- ''
24
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."
29 )
30 }
31
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."
35 )
36 }
37
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."
41 )
42 }
43 # Ensure the second entry in each row is a time unit equal to
44 # "Days" or "Weeks".
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'."
48 )
49 }
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."
54 )
55 }
56 return(warning_text)
57 }
58
59
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), ","))))
63 }
64
65 # Render the preview plot for single entry data.
66 render_plot <- function(input, output) {
67 observe({
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))
74 )
75 )
76 } else {
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
80 )
81 )
82 }
83 })
84 }
85
86 # Add a single dataset to the existing table.
87 single_entry <- function(input, output, react_values) {
88 observeEvent(input$data_single, {
89 valid <- TRUE
90
91 # Ensure the dataset name is neither blank nor a duplicate.
92 name <- trimws(input$data_name)
93 if (name == "") {
94 output$data_name_warn <- renderText("The dataset name cannot be blank.")
95 valid <- FALSE
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."
99 )
100 valid <- FALSE
101 } else {
102 output$data_name_warn <- renderText("")
103 }
104
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.")
110 valid <- FALSE
111 } else if (anyNA(counts) || any(counts < 0)) {
112 output$data_counts_warn <- renderText(
113 "Case counts can only contain non-negative integers."
114 )
115 valid <- FALSE
116 } else {
117 output$data_counts_warn <- renderText("")
118 }
119
120 if (valid) {
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)
125
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)
129
130 showNotification("Dataset added successfully.",
131 duration = 3, id = "notify-success"
132 )
133 }
134 })
135 }
136
137 # Add multiple datasets to the existing table.
138 bulk_entry <- function(input, output, react_values) {
139 observeEvent(input$data_bulk, {
140 tryCatch(
141 {
142 datasets <- read.csv(text = input$data_area, header = FALSE, sep = ",")
143
144 names <- trimws(datasets[, 1])
145 units <- trimws(datasets[, 2])
146 counts <- apply(datasets[, 3:ncol(datasets)], 1,
147 function(row) {
148 row <- suppressWarnings(as.integer(row))
149 toString(row[!is.na(row) & row >= 0])
150 }
151 )
152 output$data_area_warn <- renderText("")
153 warning_text <- warnings(datasets, list(names, units, counts))
154
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)
160
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)
164
165 showNotification("Datasets added successfully.",
166 duration = 3, id = "notify-success"
167 )
168 } else {
169 output$data_area_warn <- renderUI(HTML(warning_text))
170 }
171 },
172 error = function(e) {
173 output$data_area_warn <- renderText(
174 "The input does not match the required format."
175 )
176 }
177 )
178 })
179 }
180
181 # Upload datasets to the existing table.
182 upload_entry <- function(input, output, react_values) {
183 observeEvent(input$data_load, {
184 tryCatch(
185 {
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)]),
190 function(row) {
191 row <- suppressWarnings(as.integer(row))
192 toString(row[!is.na(row) & row >= 0])
193 }
194 )
195 output$data_load_warn <- renderText("")
196 warning_text <- ''
197 warning_text <- warnings(df, list(names, units, counts))
198
199 if (warning_text == "") {
200
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)
205
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)
209
210 showNotification("Datasets added successfully.",
211 duration = 3, id = "notify-success")
212
213
214 } else {
215 output$data_load_warn <- renderUI(HTML(warning_text))
216 }
217 },
218 error = function(e) {
219 output$data_load_warn <- renderText(
220 "The input does not match the required format."
221 )
222 }
223 )
224 })
225 }
226
227 # Add sample datasets to the existing table.
228 sample_entry <- function(input, output, react_values) {
229 observeEvent(input$sample_entry, {
230 tryCatch(
231 {
232 # datasets <- read.csv(text = input$sample, header = FALSE, sep = ",")
233
234 names <- c()
235 units <- c()
236 counts <-c()
237
238 if (input$march){
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]))}
248
249
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]))}
253
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]))}
257
258 warning_text <- ""
259
260 # Ensure the dataset names are not duplicates.
261
262
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."
266 )
267
268 }
269
270
271 output$sample_area_warn <- renderUI(HTML(warning_text))
272
273 if (warning_text == "") {
274 # Add the new datasets to the data table.
275
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)
279
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)
283
284 showNotification("Datasets added successfully.",
285 duration = 3, id = "notify-success"
286 )
287 }
288 }
289 )
290 })
291 }
292
293 # Render the data table when new datasets are added.
294 render_data <- function(output, react_values) {
295 observe({
296 output$data_table <- DT::renderDataTable(react_values$data_table)
297 })
298 }
299
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))
307 }
308 react_values$data_table <- new_table
309
310 if (ncol(react_values$estimates_table) == 1) {
311 react_values$estimates_table <- data.frame(
312 Datasets = react_values$data_table[, 1]
313 )
314 } else {
315 react_values$estimates_table <-
316 react_values$estimates_table[-input$data_table_rows_selected, ]
317 }
318 })
319 }
320
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")
326 },
327 content = function(file) {
328 write.csv(react_values$data_table, file, row.names = FALSE)
329 }
330 )
331 }
332
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))
338 )
339 colnames(new_rows) <- colnames(react_values$estimates_table)
340
341 for (row in seq_len(nrow(datasets))) {
342 new_rows[row, 1] <- datasets[row, 1]
343
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, ]
348 )
349 }
350 }
351 }
352
353 react_values$estimates_table <- rbind(
354 react_values$estimates_table, new_rows
355 )
356 }
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")
363