xref: /aosp_15_r20/external/rappor/apps/rappor-analysis/server.R (revision 2abb31345f6c95944768b5222a9a5ed3fc68cc00)
1library(shiny)
2
3source("../../analysis/R/read_input.R")
4source("../../analysis/R/decode.R")
5
6# Random number associated with the session used in exported file names.
7seed <- sample(10^6, 1)
8
9PlotCohorts <- function(x, highlighted, color = "grey") {
10  n <- nrow(x)
11  k <- ncol(x)
12  if (n < 16) {
13    par(mfrow = c(n, 1), mai = c(0, .5, .5, 0))
14  } else if (n < 64) {
15    par(mfrow = c(n / 2, 2), mai = c(0, .5, .5, 0))
16  } else {
17    par(mfrow = c(n / 4, 4), mai = c(0, .5, .5, 0))
18  }
19  for (i in 1:n) {
20    cc <- rep(color, k)
21    if (!is.null(highlighted)) {
22      ind <- highlighted[which(ceiling(highlighted / k) == i)] %% k
23      cc[ind] <- "greenyellow"
24    }
25    barplot(x[i, ], main = paste0("Cohort ", i), col = cc, border = cc,
26            names.arg = "")
27  }
28}
29
30shinyServer(function(input, output, session) {
31  Params <- reactive({
32    param_file <- input$params
33    if (!is.null(param_file)) {
34      params <- ReadParameterFile(param_file$datapath)
35      updateSelectInput(session, "size", selected = params$k)
36      updateSelectInput(session, "hashes", selected = params$h)
37      updateSelectInput(session, "instances", selected = params$m)
38      updateSliderInput(session, "p", value = params$p)
39      updateSliderInput(session, "q", value = params$q)
40      updateSliderInput(session, "f", value = params$f)
41    } else {
42      params <- list(k = as.numeric(input$size),
43                     h = as.numeric(input$hashes),
44                     m = as.numeric(input$instances),
45                     p = as.numeric(input$p),
46                     q = as.numeric(input$q),
47                     f = as.numeric(input$f))
48    }
49    params
50  })
51
52  Counts <- reactive({
53    params <- Params()
54    counts_file <- input$counts
55    if (is.null(counts_file)) {
56      return(NULL)
57    }
58
59    counts <- ReadCountsFile(counts_file$datapath, params)
60    updateNumericInput(session, "N", value = sum(counts[, 1]))
61    counts
62  })
63
64  output$countsUploaded <- reactive({
65    ifelse(is.null(input$counts), FALSE, TRUE)
66  })
67  outputOptions(output, 'countsUploaded', suspendWhenHidden=FALSE)
68
69  Map <- reactive({
70    params <- Params()
71    map_file <- input$map
72    if (is.null(map_file)) {
73      return(NULL)
74    }
75
76    map <- ReadMapFile(map_file$datapath, params)
77    updateSelectInput(session, "selected_string", choices = map$strs, selected = map$strs[1])
78    map
79  })
80
81  output$mapUploaded <- reactive({
82    ifelse(is.null(input$map), FALSE, TRUE)
83  })
84  outputOptions(output, 'mapUploaded', suspendWhenHidden=FALSE)
85
86  DecodingParams <- reactive({
87    list(alpha = as.numeric(input$alpha),
88         correction = input$correction)
89  })
90
91  Analyze <- reactive({
92    if (is.null(input$map) || is.null(input$counts)) {
93      return()
94    }
95    params <- Params()
96    map <- Map()
97    counts <- Counts()
98    decoding_params <- DecodingParams()
99
100    fit <- Decode(counts, map$map, params,
101                  alpha = decoding_params$alpha,
102                  correction = decoding_params$correction)
103    fit
104  })
105
106  # Results summary.
107  output$pr <- renderTable({
108    Analyze()$summary
109  },
110                           include.rownames = FALSE, include.colnames = FALSE)
111
112  # Results table.
113  output$tab <- renderDataTable({
114     Analyze()$fit
115   },
116     options = list(iDisplayLength = 100))
117
118  # Results barplot.
119  output$res_barplot <- renderPlot({
120    fit <- Analyze()$fit
121
122    par(mai = c(2, 1, 1, .5))
123
124    bp <- barplot(fit$proportion, col = "palegreen",
125            main = "Discovered String Distribution")
126    abline(h = Analyze()$privacy[7, 2], col = "darkred", lty = 2, lwd = 2)
127    text(bp[, 1], 0, paste(fit$strings, " "), srt = 45, adj = c(1, 1), xpd = NA)
128    legend("topright", legend = "Detection Frequency", lty = 2, lwd = 2, col = "darkred",
129           bty = "n")
130  })
131
132  # Epsilon.
133  output$epsilon <- renderTable({
134    Analyze()$privacy
135  },
136                                include.rownames = FALSE, include.colnames = FALSE, digits = 4)
137
138  output$map <- renderPlot({
139    image(as.matrix(Map()$map), col = c("white", "darkred"), xaxt = "n", yaxt = "n", bty = "n")
140  })
141
142  # Estimated bits patterns.
143  output$ests <- renderPlot({
144    ests <- Analyze()$ests
145    ind <- which(input$selected_string == Map()$strs)
146    high <- unlist(Map()$map_pos[ind, -1])
147    PlotCohorts(ests, high, color = "darkred")
148  })
149
150  # Collisions.
151  output$collisions <- renderPlot({
152    params <- Params()
153    map <- Map()
154    tab <- table(unlist(map$map_pos[, -1]))
155    tab <- tab[as.character(1:(params$k * params$m))]
156    tab[is.na(tab)] <- 0
157    tab <- matrix(tab, nrow = params$m, byrow = TRUE)
158
159    ind <- which(input$selected_string == map$strs)
160    high <- unlist(map$map_pos[ind, -1])
161
162    PlotCohorts(tab, high, color = "navajowhite")
163  })
164
165  # Observed counts.
166  output$counts <- renderPlot({
167    counts <- as.matrix(Analyze()$counts)
168    ind <- which(input$selected_string == Map()$strs)
169    high <- unlist(Map()$map_pos[ind, -1])
170    PlotCohorts(counts, high, color = "darkblue")
171  })
172
173  # Downloadable datasets.
174  output$download_fit <- downloadHandler(
175                                         filename = function() { paste("results_", seed, "_", date(), '.csv', sep='') },
176                                         content = function(file) {
177                                                     write.csv(Analyze()$fit, file, row.names = FALSE)
178                                                   }
179                                         )
180
181  output$download_summary <- downloadHandler(
182                                         filename = function() { paste("summary_", seed, "_", date(), '.csv', sep='') },
183                                         content = function(file) {
184                                                     write.csv(rbind(Analyze()$summary, Analyze()$privacy, Analyze()$params),
185                                                               file, row.names = FALSE)
186                                                   }
187                                         )
188
189  output$example_params <- renderTable({
190    as.data.frame(ReadParameterFile("params.csv"))
191  },
192                                include.rownames = FALSE)
193
194  output$example_counts <- renderTable({
195    counts <- ReadCountsFile("counts.csv")[, 1:15]
196    cbind(counts, rep("...", nrow(counts)))
197  },
198                                include.rownames = FALSE, include.colnames = FALSE)
199
200  output$example_map <- renderTable({
201    map <- ReadMapFile("map.csv", ReadParameterFile("params.csv"))
202    map$map_pos[1:10, ]
203  },
204                                include.rownames = FALSE, include.colnames = FALSE)
205
206})
207