There and Back Again competition entry https://shiny.petras.space/commute/
rstats
rshiny
census
competition
leaflet
javascript
stats-nz

app.R 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. library(shiny)
  2. library(shinyjs)
  3. library(leaflet)
  4. library(rgdal)
  5. library(dplyr)
  6. library(leaflet.extras)
  7. source("leafletfunctions.R")
  8. # work_travel <- read_csv("../travel-work.csv")
  9. load(file="datasets.RData")
  10. shpf <- readOGR(dsn="../shapefiles/sa20025WGSfilcth")
  11. sa.in.dest <- shpf@data$SA22018_V1 %in% work_to$work_code
  12. sa.in.home <- shpf@data$SA22018_V1 %in% work_from$res_code
  13. transport.t <- c("Work at home", "Private car", "Company car",
  14. "Carpool", "Bus", "Train", "Bicycle", "Walk",
  15. "Ferry", "Other", "None")
  16. cols.labs <- c(transport.t[1:10], "Total")
  17. codelist <- shpf@data %>%
  18. mutate(sa2_code = as.numeric(as.character(SA22018_V1))) %>%
  19. select(sa2_code)
  20. startcols.res <- codelist %>% left_join(work_from, by = c("sa2_code" = "res_code"))
  21. startcols.res <- tencols[startcols.res$MAX]
  22. startcols.res <- ifelse(is.na(startcols.res), "#808080", startcols.res)
  23. startcols.work <- codelist %>% left_join(work_to, by = c("sa2_code" = "work_code"))
  24. startcols.work <- tencols[startcols.work$MAX]
  25. startcols.work <- ifelse(is.na(startcols.work), "#808080", startcols.work)
  26. # Define UI
  27. ui <- fluidPage(
  28. useShinyjs(),
  29. leafletjs,
  30. tags$style(type = "text/css",
  31. "html, body {
  32. width:100%;
  33. height:100%
  34. }
  35. #map {
  36. height: 100% !important;
  37. position: absolute !important;
  38. top: 0;
  39. left: 0;
  40. }
  41. #loading {
  42. cursor: progress !important;
  43. }
  44. #loading p {
  45. border-radius: 5px;
  46. background-color: rgba(255, 255, 255, 0.8);
  47. padding: 6px 8px;
  48. box-shadow: 0 0 15px rgba(0,0,0,0.2);
  49. font-size: 1.5em;
  50. font-weight: bold;
  51. }
  52. #mapcontrol {
  53. background-color: rgba(255, 255, 255, 0.8);
  54. border-radius: 5px;
  55. box-shadow: 0 0 15px rgba(0,0,0,0.2);
  56. padding: 6px 8px;
  57. font: 14px/16px Arial, Helvetica, sans-serif;
  58. }
  59. #lochtml ul {
  60. padding-left: 15px;
  61. }
  62. .radio label span p {
  63. margin-top: 3px;
  64. margin-bottom: 0px;
  65. }"),
  66. leafletOutput("map"),
  67. absolutePanel(top = 10, right = 10, id="mapcontrol",
  68. radioButtons("radioinout", label="Show commuters who",
  69. choiceNames = list(
  70. HTML("<p>Commute <b>from</b> selected area</p>"),
  71. HTML("<p>Commute <b>to</b> selected area</p>")),
  72. choiceValues = list(
  73. "res",
  74. "work"
  75. ),
  76. inline = FALSE),
  77. radioButtons("radiocolour",
  78. label = "Colour by",
  79. choiceNames = list(
  80. HTML("<p>Most common commute method</p>"),
  81. HTML("<p>Number of commuters</p>")
  82. ),
  83. choiceValues = list(
  84. "type",
  85. "number"
  86. ),
  87. inline = FALSE),
  88. div(id="locinfo",
  89. htmlOutput("lochtml"))),
  90. absolutePanel(bottom = 30, left = 30, id="loading",
  91. p("Loading..."))
  92. )
  93. # Define server logic
  94. server <- function(input, output) {
  95. sel.SA2.code <- reactiveVal(0)
  96. p.layers <- c("polya", "polyb")
  97. output$map <- renderLeaflet({
  98. leaf <- leaflet(shpf, options = leafletOptions(minZoom = 3, maxZoom = 13)) %>%
  99. addPolygons(color="#000", opacity = 1, weight=1,
  100. fillColor = startcols.res,
  101. layerId = ~SA22018_V1,
  102. label = shpf@data$SA22018__1,
  103. fillOpacity = 1) %>%
  104. setView(174, -41, 5) %>%
  105. addResetMapButton() %>%
  106. addLegend(position = "topleft",
  107. colors = c(tencols, "#808080"),
  108. labels = transport.t, opacity = 1,
  109. title = "Commute method")
  110. shinyjs::hideElement(selector="#loading p", asis = TRUE,
  111. anim=TRUE, animType = "slide", time=7)
  112. leaf
  113. })
  114. updateMap <- function() {
  115. shinyjs::showElement(selector="#loading p", asis = TRUE,
  116. anim=TRUE, animType = "slide")
  117. selcode <- sel.SA2.code()
  118. selcode <- ifelse(is.na(selcode), 0, selcode)
  119. psel <- selcode %in% shpf@data$SA22018_V1
  120. if (input$radiocolour == "type") {
  121. if (input$radioinout == "work") {
  122. fcols <- startcols.work
  123. if (psel) {
  124. codvs <- work_simp %>% filter(work_code == selcode)
  125. codvs <- codelist %>% left_join(codvs, by=c("sa2_code" = "res_code"))
  126. codvs <- tencols[codvs$MAX]
  127. fcols <- ifelse(is.na(codvs), "#808080", codvs)
  128. }
  129. } else {
  130. fcols <- startcols.res
  131. if (psel) {
  132. codvs <- work_simp %>% filter(res_code == selcode)
  133. codvs <- codelist %>% left_join(codvs, by=c("sa2_code" = "work_code"))
  134. codvs <- tencols[codvs$MAX]
  135. fcols <- ifelse(is.na(codvs), "#808080", codvs)
  136. }
  137. }
  138. lp <- leafletProxy("map", data = shpf) %>%
  139. setShapeStyle(layerId = ~SA22018_V1, fillColor = fcols) %>%
  140. clearControls() %>%
  141. addLegend(position = "topleft",
  142. colors = c(tencols, "#808080"),
  143. labels = transport.t, opacity = 1,
  144. title = "Commute method"
  145. ) %>%
  146. clearGroup("hpoly")
  147. } else {
  148. if (input$radioinout == "work") {
  149. if (psel) {
  150. codvs <- work_simp %>% filter(work_code == selcode)
  151. codvs <- codelist %>% left_join(codvs, by=c("sa2_code" = "res_code"))
  152. cvals <- ifelse(codvs$total == 0, NA, codvs$total)
  153. } else {
  154. codvs <- codelist %>%
  155. left_join(work_to, by = c("sa2_code" = "work_code"))
  156. cvals <- ifelse(codvs$total == 0, NA, codvs$total)
  157. }
  158. } else {
  159. if (psel) {
  160. codvs <- work_simp %>% filter(res_code == selcode)
  161. codvs <- codelist %>% left_join(codvs, by=c("sa2_code" = "work_code"))
  162. cvals <- ifelse(codvs$total == 0, NA, codvs$total)
  163. } else {
  164. codvs <- codelist %>%
  165. left_join(work_from, by = c("sa2_code" = "res_code"))
  166. cvals <- ifelse(codvs$total == 0, NA, codvs$total)
  167. }
  168. }
  169. cvr <- range(cvals, na.rm = TRUE)
  170. binner <- colorBin(c("white", "red"), cvr, bins = 7, pretty = TRUE)
  171. lp <- leafletProxy("map", data = shpf) %>%
  172. setShapeStyle(layerId = ~SA22018_V1, fillColor = binner(cvals)) %>%
  173. clearControls() %>%
  174. addLegend(position = "topleft",
  175. pal = binner,
  176. values = cvals, opacity = 1,
  177. na.label = "None",
  178. title = "Number of commuters") %>%
  179. clearGroup("hpoly")
  180. }
  181. if (psel) {
  182. lp %>% addPolygons(group = "hpoly",
  183. weight = 4,
  184. data = shpf[which(shpf@data$SA22018_V1 == selcode),],
  185. color = "#000000",
  186. fill = FALSE, opacity = 1)
  187. }
  188. shinyjs::hideElement(selector="#loading p", asis=TRUE,
  189. anim=TRUE, animType = "slide",
  190. time = 1)
  191. }
  192. observeEvent(input$map_shape_click, ignoreInit = TRUE, {
  193. p <- input$map_shape_click
  194. pdat <- data.frame(Longitude = p$lng,
  195. Latitude =p$lat)
  196. coordinates(pdat) <- ~ Longitude + Latitude
  197. proj4string(pdat) <- proj4string(shpf)
  198. ppoly <- over(pdat, shpf)
  199. codetmp <- as.numeric(as.character(ppoly[1,"SA22018_V1"]))
  200. codetmp <- ifelse(is.na(codetmp), 0, codetmp)
  201. sel.SA2.code(ifelse(sel.SA2.code() == codetmp, 0, codetmp))
  202. updateMap()
  203. })
  204. observeEvent(input$radioinout, ignoreInit = TRUE, {
  205. updateMap()
  206. })
  207. observeEvent(input$radiocolour, ignoreInit = TRUE, {
  208. updateMap()
  209. })
  210. output$lochtml <- renderUI({
  211. seled <- sel.SA2.code()
  212. seled <- ifelse(is.na(seled), 0, seled)
  213. if (!(seled %in% shpf@data$SA22018_V1)) {
  214. HTML("")
  215. } else {
  216. namesel <- shpf@data$SA22018__1[shpf@data$SA22018_V1 == seled]
  217. hrstr <- "<hr style='border-top: 1px solid #000;'/>"
  218. if (input$radiocolour == "type") {
  219. str <- sprintf("<b>%s</b>", namesel)
  220. if (input$radioinout == "work") {
  221. str <- sprintf("<p>Commuting method of people who <b>work</b> in</p>
  222. <p><b><u>%s</u></b></p>", str)
  223. vals <- as.numeric(work_to[work_to$work_code == seled, 5:15])
  224. vals <- ifelse(is.na(vals), 0, vals)
  225. vals <- ifelse(vals < 0, "~0", as.character(vals))
  226. listi <- paste0(sprintf("<li>%s: %s</li>", cols.labs,
  227. vals),
  228. collapse="")
  229. str <- paste0(hrstr, str, "<ul>", listi, "</ul>")
  230. } else {
  231. str <- sprintf("<p>Commuting method of people who <b>live</b> in</p>
  232. <p><u>%s</u></p>", str)
  233. vals <- as.numeric(work_from[work_from$res_code == seled, 5:15])
  234. vals <- ifelse(is.na(vals), 0, vals)
  235. vals <- ifelse(vals < 0, "~0", as.character(vals))
  236. listi <- paste0(sprintf("<li>%s: %s</li>", cols.labs,
  237. vals),
  238. collapse="")
  239. str <- paste0(hrstr, str, "<ul>", listi, "</ul>")
  240. }
  241. HTML(str)
  242. } else {
  243. str <- hrstr
  244. if (input$radioinout == "work") {
  245. val <- as.numeric(work_to[work_to$work_code == seled, 15])
  246. val <- ifelse(is.na(val), 0, ifelse(val < 0, 0, val))
  247. str <- sprintf("%s<p>%d people commute <b>to</b></p>
  248. <p><b><u>%s</u></b></p>", str, val, namesel)
  249. if (val > 0) {
  250. subs <- work_simp %>% filter(work_code == seled) %>%
  251. arrange(desc(total)) %>% head(10)
  252. listi <- paste0(sprintf("<li>%s: %s</li>", subs$res_name,
  253. subs$total),
  254. collapse="")
  255. str <- sprintf("%s<p>Top areas to commute from<p>
  256. <ul>%s</ul>", str, listi)
  257. }
  258. } else {
  259. val <- as.numeric(work_from[work_from$res_code == seled, 15])
  260. val <- ifelse(is.na(val), 0, ifelse(val < 0, 0, val))
  261. str <- sprintf("%s<p>%d people commute <b>from</b></p>
  262. <p><b><u>%s</u></b></p>", str, val, namesel)
  263. if (val > 0) {
  264. subs <- work_simp %>% filter(res_code == seled) %>%
  265. arrange(desc(total)) %>% head(10)
  266. listi <- paste0(sprintf("<li>%s: %s</li>", subs$work_name,
  267. subs$total),
  268. collapse="")
  269. str <- sprintf("%s<p>Top areas to commute to<p>
  270. <ul>%s</ul>", str, listi)
  271. }
  272. }
  273. HTML(str)
  274. }
  275. }
  276. })
  277. }
  278. # Run the application
  279. shinyApp(ui = ui, server = server)