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

extras.R 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. extracss <- "
  2. #map {
  3. height: 100% !important;
  4. position: absolute !important;
  5. top: 0;
  6. left: 0;
  7. }
  8. #loading {
  9. cursor: progress !important;
  10. z-index: 1002;
  11. }
  12. #loading p {
  13. border-radius: 5px;
  14. background-color: rgba(255, 255, 255, 0.8);
  15. padding: 6px 8px;
  16. box-shadow: 0 0 15px rgba(0,0,0,0.2);
  17. font-size: 1.5em;
  18. font-weight: bold;
  19. margin: 0;
  20. }
  21. #mapcontrol, #infopanel {
  22. background-color: rgba(255, 255, 255, 0.8);
  23. border-radius: 5px;
  24. box-shadow: 0 0 15px rgba(0,0,0,0.2);
  25. padding: 6px 8px;
  26. font: 14px/16px Arial, Helvetica, sans-serif;
  27. }
  28. #mapcontrol, #control2 {
  29. z-index: 1000;
  30. }
  31. #mapcontrol {
  32. width: 20em;
  33. max-height: 95%;
  34. overflow: auto;
  35. -ms-overflow-style: none; /* IE and Edge */
  36. scrollbar-width: none; /* Firefox */
  37. }
  38. #mapcontrol::-webkit-scrollbar {
  39. display: none;
  40. }
  41. #infopanel {
  42. background-color: rgba(255, 255, 255, 0.9);
  43. padding: 10px;
  44. z-index: 1001;
  45. }
  46. #lochtml ul {
  47. padding-left: 15px;
  48. }
  49. .leaflet-container {
  50. background-color: #84e1e1;
  51. }
  52. #infobuttoncontainer {
  53. padding: 6px 8px;
  54. z-index: 1002;
  55. font: 14px/16px Arial, Helvetica, sans-serif;
  56. }
  57. #infobuttoncontainer .shiny-input-container,
  58. #infobuttoncontainer div div {
  59. margin-right: 0px !important;
  60. margin-bottom: 0px !important;
  61. }
  62. h3 {
  63. margin-top: 5px;
  64. margin-bottom: 5px;
  65. }
  66. .overflowable {
  67. max-height: 100%;
  68. overflow: auto;
  69. -ms-overflow-style: none; /* IE and Edge */
  70. scrollbar-width: none; /* Firefox */
  71. }
  72. .overflowable::-webkit-scrollbar {
  73. display: none;
  74. }
  75. blockquote {
  76. font-size: 1em;
  77. font-style: italic;
  78. border: none;
  79. margin: 0;
  80. }
  81. .scrollbuffer {
  82. height: 50px;
  83. }
  84. .overflowable:before {
  85. content:'';
  86. width:100%;
  87. height:50px;
  88. position:absolute;
  89. left:0;
  90. bottom:5px;
  91. right:0;
  92. background:linear-gradient(rgba(255, 255, 255, 0) 0px, rgba(255, 255, 255, 0.9));
  93. }
  94. #infobuttoncontainer label {
  95. font-weight: bold;
  96. }
  97. .locinfo {
  98. max-width: 100%;
  99. }
  100. .loading p {
  101. margin: 0;
  102. }
  103. hr {
  104. margin-top: 10px;
  105. margin-bottom: 10px;
  106. border-top: 1px solid #000;
  107. }
  108. .leaflet-control-search {
  109. box-shadow: none;
  110. }
  111. .shortcut {
  112. text-decoration: underline 1px dotted;
  113. }
  114. #shortcutlist {
  115. columns: 20em 2;
  116. }
  117. kbd {
  118. color: black;
  119. background-color: #eee;
  120. border-radius: 4px;
  121. padding: 1px 6px;
  122. border-color: #444;
  123. border-width: 1px;
  124. -webkit-box-shadow: 1px 1px #444;
  125. box-shadow: 1px 1px #444;
  126. font-size: 120%;
  127. font-family: arial, Helvetica, sans-serif;
  128. cursor: pointer;
  129. }
  130. kbd:hover {
  131. background-color: #ddd;
  132. box-shadow: 0.5px 0.5px;
  133. -webkit-box-shadow: 0.5px 0.5px;
  134. }
  135. #infoint li {
  136. padding-bottom: 10px;
  137. }
  138. .radio-btn-icon-no {
  139. color: rgba(255, 255, 255, 0);
  140. }
  141. .btn.radiobtn {
  142. text-align: left;
  143. }
  144. #control2 .state label,
  145. #infobuttoncontainer .state label
  146. {
  147. width: 0px;
  148. }
  149. "
  150. attribhtml <- '
  151. <a href="http://leafletjs.com"
  152. title="A JS library for interactive maps">Leaflet</a> | <a
  153. href="http://datafinder.stats.govt.nz/data/category/census/2018/commuter-view/"
  154. title="Source data">
  155. StatsNZ</a> | <a href="http://petras.space/" title="Hire me!">
  156. Petra Lamborn</a> (<a href="https://github.com/PetraOleum/commute"
  157. title="Source code">Source</a>)
  158. '
  159. infotext <- div(class="overflowable", id="infoint", tabindex="2",
  160. h3("How did Kiwis commute in 2018?"),
  161. p("This tool maps the 2018 census",
  162. a(href=
  163. "https://datafinder.stats.govt.nz/data/category/census/2018/commuter-view/",
  164. title="Datafinder link",
  165. "commuter data"),
  166. "to help visualise transport ",
  167. "connections. It is ", a(href="http://petras.space", title="Hire me!",
  168. "Petra Lamborn's"),
  169. " entry for the ", em("There and Back Again"),
  170. a(href=
  171. "https://www.stats.govt.nz/2018-census/there-and-back-
  172. again-data-visualisation-competition", title="June-July 2020",
  173. "data visualisation competition",
  174. .noWS = "after"),
  175. HTML(". The employment portion of the dataset captures employed persons ",
  176. "15 years or older who gave an employment address or location ",
  177. "in the 2018 census.",
  178. "The education dataset counts people in education 15 years or older who ",
  179. "gave an education location in the 2018 census, ",
  180. "including older highschoolers and ",
  181. "university students but not e.g. primary school students.")),
  182. p("The source code for this project can be found on GitHub",
  183. a(href="https://github.com/PetraOleum/commute",
  184. title="Github link",
  185. "here", .noWS = "after"), "."),
  186. h4("The data"),
  187. p("The 2018 New Zealand Census of Population and Dwellings",
  188. a(href=paste0("https://cdm20045.contentdm.oclc.org/digital/",
  189. "collection/p20045coll2/id/713/rec/3"),
  190. title="pdf of paper version of the individual questionnaire",
  191. "questionnaire"),
  192. "asked individuals for primary locations of employment and education ",
  193. "and their usual method of transportation. Stats NZ has",
  194. a(href=
  195. "https://datafinder.stats.govt.nz/data/category/census/2018/commuter-view/",
  196. title="Datafinder link",
  197. "released data"),
  198. "aggregated at the level of",
  199. a(href=paste0(
  200. "http://archive.stats.govt.nz/methods/classifications-and-standards/",
  201. "classification-related-stats-standards/geographic-areas/pg4.aspx#gsc.tab=0"),
  202. title="Definition of statistical areas, 2018",
  203. "Statistical Area 2"), "(SA2). ",
  204. "SA2 boundaries typically enclose areas with a population of a few ",
  205. "thousand, corresponding approximately to urban suburbs and rural towns. ",
  206. "The shapes of these areas have been heavily simplified in this map ",
  207. "to reduce bandwidth and memory usage. ",
  208. "The original boundaries can be viewed and downloaded",
  209. a(href=
  210. "https://datafinder.stats.govt.nz/layer/92212-statistical-area-2-2018-generalised/",
  211. title="Shapefiles avaliable on datafinder",
  212. "from the Stats NZ datafinder website", .noWS = "after"), "."),
  213. h4("Using this tool"),
  214. p("The options avaliable allow ",
  215. "you to select the employment or education datasets. ",
  216. "You may also choose to visualise the people who commute from ",
  217. "or to each area, and select between showing numbers of people or ",
  218. "their primary mode of transportation. \"Primary\" is calculated by ",
  219. "FPP rules: it means the most common, not the majority."),
  220. p("Select an area by clicking on it; deselect by clicking it again ",
  221. "or clicking the sea. When an area is selected the map is ",
  222. "coloured according to the people who commute to or from that area ",
  223. "(including the people who commute within the area). When no area is ",
  224. "selected, colouring is according to commutes to or from all ",
  225. "localities. Hover over areas for a summary (on a tablet, hold press)."),
  226. p("At rest the map is coloured by the most common type of transportation ",
  227. "used by people commuting to employment from each area."),
  228. h4("Keyboard shortcuts"),
  229. shiny::tags$ul(id="shortcutlist",
  230. shiny::tags$li(shiny::tags$kbd("I"), ": show/hide this info page"),
  231. shiny::tags$li(shiny::tags$kbd("M"), ": focus map"),
  232. shiny::tags$ul(
  233. shiny::tags$li(shiny::tags$kbd("+"), shiny::tags$kbd("-"),
  234. ": zoom map"),
  235. shiny::tags$li(shiny::tags$kbd(HTML("&larr;")),
  236. shiny::tags$kbd(HTML("&uarr;")),
  237. shiny::tags$kbd(HTML("&rarr;")),
  238. shiny::tags$kbd(HTML("&darr;")),
  239. ": move map")
  240. ),
  241. shiny::tags$li(shiny::tags$kbd("R"), ": reset map position"),
  242. shiny::tags$li(shiny::tags$kbd("S"), ": search map"),
  243. shiny::tags$li(shiny::tags$kbd("L"), ": show/hide options panel"),
  244. shiny::tags$li(shiny::tags$kbd("P"), ": show employment data"),
  245. shiny::tags$li(shiny::tags$kbd("D"), ": show education data"),
  246. shiny::tags$li(shiny::tags$kbd("F"), ": show people commuting from localities"),
  247. shiny::tags$li(shiny::tags$kbd("T"), ": show people commuting to localities"),
  248. shiny::tags$li(shiny::tags$kbd("O"), ": colour by most common commute type"),
  249. shiny::tags$li(shiny::tags$kbd("U"), ": colour by number of commuters")
  250. ),
  251. h4("FAQ"),
  252. shiny::tags$blockquote("Why are so many areas marked as 'works at ",
  253. "home'?"),
  254. p("Working from home includes working from your kitchen table, ",
  255. "but also farming. Anyone who is employed but does not commute ",
  256. "is included in this category."),
  257. shiny::tags$blockquote("Why is every number divisible by three?"),
  258. p("To ensure anonymity and the confidentiality of your census data, ",
  259. "Statistics New Zealand employs a technique called ",
  260. em(a(href=paste0(
  261. "http://archive.stats.govt.nz/about_us/legisln-policies-protocols/",
  262. "confidentiality-of-info-supplied-to-snz/safeguarding-confidentiality.aspx"),
  263. title="A method of preserving confidentiality and anonymity",
  264. "random rounding", .noWS = "after"), .noWS = "after"), ". ",
  265. "This method rounds all values to a multiple of three, but one-third of ",
  266. "the time rounds to the second nearest multiple, rather than the closest. ",
  267. "Additionally, rounded values less than six are censored."),
  268. p("Note that this also means totals do not always add up."),
  269. shiny::tags$blockquote("In some views there are areas that are greyed ",
  270. "out when looking at transport type, but not ",
  271. "when looking at numbers of people. How does ",
  272. "that work?"),
  273. p("As mentioned above some low values are censored to avoid providing ",
  274. "potentially identifiable information. However it is possible for the ",
  275. "total number of people to be large enough to escape censoring while ",
  276. "all transport", em("type"), "numbers are too small and so no most ",
  277. "common type can be determined."),
  278. shiny::tags$blockquote("Does anyone commute to (or from?) the Chatham Islands?"),
  279. p("No, but some people commute within it. Of 249 people commuting to ",
  280. "employment, 105 travel by private car, 24 by company car, 18 walk, 12 ",
  281. "are passengers in cars driven by other people, and 93 work at home. ",
  282. "Of 84 people commuting to education, 39 take a schoolbus, 9 walk, 9 are ",
  283. "passengers in a car, and 15 are educated at home."),
  284. div(class="scrollbuffer")
  285. )
  286. keyboardjs <- tags$head(tags$script(HTML("
  287. $(function(){
  288. $(document).keyup(function(e) {
  289. var active = document.activeElement
  290. if (active.id == 'searchtext9') return;
  291. switch(e.key) {
  292. case 'p':
  293. case 'P':
  294. document.getElementsByName('radioeduemp')[0].click();
  295. Shiny.onInputChange('radioeduemp', 'Employment')
  296. break;
  297. case 'd':
  298. case 'D':
  299. document.getElementsByName('radioeduemp')[1].click();
  300. Shiny.onInputChange('radioeduemp', 'Education')
  301. break;
  302. case 'f':
  303. case 'F':
  304. document.getElementsByName('radioinout')[0].click();
  305. Shiny.onInputChange('radioinout', 'res')
  306. break;
  307. case 't':
  308. case 'T':
  309. document.getElementsByName('radioinout')[1].click();
  310. Shiny.onInputChange('radioinout', 'work')
  311. break;
  312. case 'o':
  313. case 'O':
  314. document.getElementsByName('radiocolour')[0].click();
  315. Shiny.onInputChange('radiocolour', 'type')
  316. break;
  317. case 'u':
  318. case 'U':
  319. document.getElementsByName('radiocolour')[1].click();
  320. Shiny.onInputChange('radiocolour', 'number')
  321. break;
  322. case 'i':
  323. case 'I':
  324. shinyjs.click('mapinfobutton')
  325. break;
  326. case 'm':
  327. case 'M':
  328. document.getElementById('map').focus()
  329. break;
  330. case 's':
  331. case 'S':
  332. var evObj = document.createEvent('Events');
  333. evObj.initEvent('click', true, false);
  334. document.getElementsByClassName('search-button')[0].dispatchEvent(evObj);
  335. break;
  336. case 'l':
  337. case 'L':
  338. document.getElementById('controlswitch').click();
  339. break;
  340. case 'r':
  341. case 'R':
  342. document.getElementsByClassName('easy-button-button')[0].click()
  343. break;
  344. default:
  345. break;
  346. }
  347. });
  348. })
  349. ")))