

{"id":3028,"date":"2014-09-20T10:49:55","date_gmt":"2014-09-20T15:49:55","guid":{"rendered":"http:\/\/rud.is\/b\/?p=3028"},"modified":"2018-03-07T16:44:24","modified_gmt":"2018-03-07T21:44:24","slug":"chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot","status":"publish","type":"post","link":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/","title":{"rendered":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial)"},"content":{"rendered":"<p>The BBC did a pretty good job [live tracking the Scotland secession vote](http:\/\/www.bbc.com\/news\/events\/scotland-decides\/results), but I really didn&#8217;t like the color scheme they chose and decided to use the final tally site as the basis for another tutorial using the tools from the Hadleyverse and taking advantage of the fact that newer `gdal` libraries can read in [TopoJSON](https:\/\/github.com\/mbostock\/topojson)\/GeoJSON files, meaning we can use _most_ of the maps the D3-ers create\/use right in R.<\/p>\n<p>We&#8217;ll need a few R packages to help us get, clean, format and chart the data:<\/p>\n<pre lang=\"rsplus\">library(rvest)\r\nlibrary(dplyr)\r\nlibrary(httr) # >0.5\r\nlibrary(tidyr)\r\nlibrary(gpclib)\r\nlibrary(rgeos)\r\nlibrary(sp)\r\nlibrary(maptools)\r\nlibrary(rgdal) # needs gdal > 1.11.0\r\nlibrary(ggplot2)\r\nlibrary(reshape2)\r\nlibrary(gridExtra)<\/pre>\n<p>The new `rvest` package makes it super-fun (and easy) to get data out of web pages (as I&#8217;ve [mentioned on the sister blog](http:\/\/datadrivensecurity.info\/blog\/posts\/2014\/Sep\/migrating-to-rvest\/)), but said data is still web page data, usually geared towards making things render well in a browser, and we end up having to clean up the extracted fields to get useful data. Since we usually want a data frame from the extraction, an `rvest` idiom I&#8217;ve been playing with involves bundling the element extraction &#038; cleanup code into one function and then using that to build the columns:<\/p>\n<pre lang=\"rsplus\"># extract data from rvest-ed <div>'s and clean it up a bit\r\n# pass in the rvested HTML object and the CSS selector to extract, also \r\n# indicating whether we want a number or character vector returned\r\n\r\nextractAndCleanup <- function(data, selector, make_numeric=FALSE) {\r\n  x <- data %>% html_nodes(selector) %>% html_text()\r\n  x <- gsub(\"^[[:punct:][:space:]]*|[[:punct:][:space:]]*$\", \"\", x)\r\n  if (make_numeric) x <- as.numeric(gsub(\"[,[:space:]]*\", \"\", x))\r\n  x\r\n}\r\n\r\nbbc_vote <- html(\"http:\/\/www.bbc.com\/news\/events\/scotland-decides\/results\")\r\n\r\nsecede <- data.frame(\r\n  council=bbc_vote %>% extractAndCleanup(\".body-row__cell--council\"),\r\n  electorate=bbc_vote %>% extractAndCleanup(\".body-row__cell--electorate\", TRUE),\r\n  yes=bbc_vote %>% extractAndCleanup(\".body-row__cell--yes\", TRUE),\r\n  no=bbc_vote %>% extractAndCleanup(\".body-row__cell--no\", TRUE),\r\n  stringsAsFactors=FALSE)<\/pre>\n<p>We can then compute whether the vote tally was to secede or not and assign a color in the event we choose to use base graphics for plotting (we won&#8217;t for this tutorial). I chose a muted version of the Union Jack red and the official Scottish blue for this exercise.<\/p>\n<pre lang=\"rsplus\">secede <- secede %>% mutate(gone=yes>no,\r\n                            color=ifelse(gone, \"#0065BD\", \"#CF142B77\"))<\/pre>\n<p>Getting the map from the BBC site is just as simple. An inspection of the site in any decent browser with a &#8220;Developer&#8221; mode lets us see the elements being downloaded. For the BBC map, it reads the data from: `http:\/\/static.bbci.co.uk\/news\/1.49.0-1192\/js\/data\/maps\/l\/scotland-elections.js` which is a TopoJSON object wrapped in two lines of extra javascript code. We&#8217;ll grab that file, clean it up and read the map into R using `httr`&#8217;s new-ish ability to save to a data file:<\/p>\n<pre lang=\"rsplus\">GET(\"http:\/\/static.bbci.co.uk\/news\/1.49.0-1192\/js\/data\/maps\/l\/scotland-elections.js\",\r\n    write_disk(\"data\/scotland.json\"), progress())\r\ntmp <- readLines(\"data\/scotland.json\")\r\ndir.create(\"data\")\r\nwriteLines(tmp[2], \"data\/scotland.json\")\r\n\r\nmap <- readOGR(\"data\/scotland.json\", \"scotland-elections\")\r\n<\/pre>\n<p>We'll want to work with the map using Council names, so we need to ensure the names from the extracted `div` elements match what's in the TopoJSON file:<\/p>\n<pre lang=\"rsplus\">secede$council %in% map@data$name\r\n\r\n##  [1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE\r\n## [13] FALSE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE\r\n## [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE<\/pre>\n<p>It looks like we'll need to clean the names up a bit, but thankfully the names aren't too far off:<\/p>\n<pre lang=\"rsplus\">secede$council <- gsub(\"&#038;\", \"and\", secede$council)\r\nsecede[secede$council==\"Edinburgh\",]$council = \"City of Edinburgh\"\r\nsecede[secede$council==\"Glasgow\",]$council = \"Glasgow City\"\r\nsecede[secede$council==\"Comhairle nan Eilean Siar\",]$council = \"Na h-Eileanan an Iar\"\r\n<\/pre>\n<p>If we were using base graphics for plotting, we'd also have to ensure the data was in the right order:<\/p>\n<pre lang=\"rsplus\">secede$council <- factor(secede$council, map@data$name, ordered=TRUE)\r\nsecede <- secede %>% arrange(council)<\/pre>\n<p>We're going to use `ggplot` for the mapping portion, but the normal `fortify` process didn't work on this TopoJSON file (some polygon errors emerged), so we'll take another route and do the data Council name\u2194id mapping after the `fortify` call and merge the rest of our data into the map data frame:<\/p>\n<pre lang=\"rsplus\">map_df <- fortify(map)\r\n\r\n# manually associate the map id's with the Council names and vote data\r\ncouncils <- data.frame(id=0:(length(map@data$name)-1),\r\n                       council=as.character(map@data$name))\r\nmap_df <- merge(map_df, councils, by=\"id\")\r\nmap_df <- merge(map_df, secede, by=\"council\")<\/pre>\n<p>Now we can generate the choropleth:<\/p>\n<pre lang=\"rsplus\">gg <- ggplot()\r\ngg <- gg + geom_map(data=map_df, map=map_df,\r\n                    aes(map_id=id, x=long, y=lat, group=group, fill=color),\r\n                    color=\"white\", size=0.25)\r\ngg <- gg + scale_fill_manual(values=rev(unique(secede$color)),\r\n                             labels=c(\"Yes\", \"No\"), name=\"Secede?\")\r\ngg <- gg + xlim(extendrange(r=range(coordinates(map)[,1]), f=0.15))\r\ngg <- gg + ylim(extendrange(r=range(coordinates(map)[,2]), f=0.07))\r\ngg <- gg + coord_map()\r\ngg <- gg + labs(x=\"\", y=\"\")\r\ngg <- gg + theme_bw()\r\ngg <- gg + theme(panel.grid=element_blank())\r\ngg <- gg + theme(legend.position=\"none\")\r\ngg <- gg + theme(panel.border=element_blank())\r\ngg <- gg + theme(axis.ticks=element_blank())\r\ngg <- gg + theme(axis.text=element_blank())<\/pre>\n<p><center><img decoding=\"async\" src=\"https:\/\/rud.is\/dl\/justthemap.svg\"\/><\/center><\/p>\n<p>A choropleth is all well-and-good, but\u2014since we have the data\u2013let's add the bar chart to complete the presentation. We'll combine some `dplyr` and `tidyr` calls to melt and subset our data frame:<\/p>\n<pre lang=\"rsplus\">secede_m <- secede %>%\r\n  gather(variable, value, -council) %>%\r\n  filter(variable %in% c(\"yes\", \"no\")) %>%\r\n  mutate(value=as.numeric(value))<\/pre>\n<p>For this exercise, we'll plot the 100% stacked bars in order of the \"No\" votes, and we'll pre-process this ordering to make the `ggplot` code easier on the eyes. We start by merging some data back into our melted data frame so we can build the sorted factor by the \"No\" value column and then make sure the Councils will be in that order:<\/p>\n<pre lang=\"rsplus\">secede_m <- merge(secede_m, secede, by=\"council\")\r\nsecede_m$variable <- factor(secede_m$variable,\r\n                            levels=c(\"yes\", \"no\"), ordered=TRUE)\r\nsecede_m <- secede_m %>% arrange(no, variable)\r\nsecede_m$council <- factor(secede_m$council,\r\n                           unique(secede_m$council), ordered=TRUE)<\/pre>\n<p>Finally, we can create the 100% stacked bar plot and combine it with the choropleth to build the final product:<\/p>\n<pre lang=\"rsplus\">gg1 <- ggplot(secede_m, aes(x=council, y=value, fill=factor(variable)))\r\ngg1 <- gg1 + geom_bar(stat=\"identity\", position=\"fill\")\r\ngg1 <- gg1 + scale_fill_manual(values=rev(unique(secede$color)),\r\n                             labels=c(\"Yes\", \"No\"), name=\"Secede?\")\r\ngg1 <- gg1 + geom_hline(yintercept=0.50, color=\"gray80\")\r\ngg1 <- gg1 + geom_text(aes(label=percent(yes\/100)), y=0.08, color=\"white\", size=3)\r\ngg1 <- gg1 + geom_text(aes(label=percent(no\/100)), y=0.92, color=\"white\", size=3)\r\ngg1 <- gg1 + coord_flip()\r\ngg1 <- gg1 + labs(x=\"\", y=\"\")\r\ngg1 <- gg1 + theme_bw()\r\ngg1 <- gg1 + theme(panel.grid=element_blank())\r\ngg1 <- gg1 + theme(legend.position=\"top\")\r\ngg1 <- gg1 + theme(panel.border=element_blank())\r\ngg1 <- gg1 + theme(axis.ticks=element_blank())\r\ngg1 <- gg1 + theme(axis.text.x=element_blank())\r\n\r\nvote <- arrangeGrob(gg1, gg, ncol=2,\r\n                     main=textGrob(\"Scotland Votes\", gp=gpar(fontsize=20)))<\/pre>\n<p><center><a target=\"_blank\" href=\"https:\/\/rud.is\/dl\/scotvote.svg\"><img decoding=\"async\" src=\"https:\/\/rud.is\/dl\/scotvote.svg\"\/><\/a><br \/><span style=\"font-size:9px\">(Click for larger version)<\/span><\/center><\/p>\n<p>I've bundled this code up into it's own [github repo](https:\/\/github.com\/hrbrmstr\/secede-2014). The full project example has a few extra features as<\/p>\n<p>- it shows how to save the resultant data frame to an R data file (in case the BBC nukes the site)<br \/>\n- also saves the cleaned-up JSON (getting minimal Scotland shapefiles is tricky so this one's a keeper even with the polygon errors)<br \/>\n- wraps all that in `if` statements so future analysis\/vis can work with or without the live data being available.<\/p>\n<p>Hadley really has to stop making R so fun to work with :-)<\/p>\n<p><b>UPDATE<\/b><\/p>\n<p>Based on a comment by Paul Drake suggesting that the BBC choropleth (and, hence, my direct clone of it) could be made more informative by showing the vote difference. Since it's just changing two lines of code, here it is in-situ vs creating a new post.<\/p>\n<pre lang=\"rsplus\">gg <- gg + geom_map(data=map_df, map=map_df,\r\n                    aes(map_id=id, x=long, y=lat, group=group, fill=yes-no),\r\n                    color=\"white\", size=0.25)\r\ngg <- gg + scale_fill_gradient(low=\"#CF142B\", high=\"#0065BD\", \r\n                               name=\"Secede?\\n(vote margin)\", guide=\"legend\")<\/pre>\n<p><center><a href=\"https:\/\/rud.is\/dl\/votegradient.svg\"><img decoding=\"async\" src=\"https:\/\/rud.is\/dl\/votegradient.svg\"\/><\/a><\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The BBC did a pretty good job [live tracking the Scotland secession vote](http:\/\/www.bbc.com\/news\/events\/scotland-decides\/results), but I really didn&#8217;t like the color scheme they chose and decided to use the final tally site as the basis for another tutorial using the tools from the Hadleyverse and taking advantage of the fact that newer `gdal` libraries can read [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[24,666,678,673,674,706,91],"tags":[810],"class_list":["post-3028","post","type-post","status-publish","format-standard","hentry","category-charts-graphs","category-d3","category-data-visualization","category-datavis-2","category-dataviz","category-maps","category-r","tag-post"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial) - rud.is<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial) - rud.is\" \/>\n<meta property=\"og:description\" content=\"The BBC did a pretty good job [live tracking the Scotland secession vote](http:\/\/www.bbc.com\/news\/events\/scotland-decides\/results), but I really didn&#8217;t like the color scheme they chose and decided to use the final tally site as the basis for another tutorial using the tools from the Hadleyverse and taking advantage of the fact that newer `gdal` libraries can read [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\" \/>\n<meta property=\"og:site_name\" content=\"rud.is\" \/>\n<meta property=\"article:published_time\" content=\"2014-09-20T15:49:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-03-07T21:44:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/rud.is\/dl\/justthemap.svg\" \/>\n<meta name=\"author\" content=\"hrbrmstr\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"hrbrmstr\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\"},\"author\":{\"name\":\"hrbrmstr\",\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"headline\":\"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial)\",\"datePublished\":\"2014-09-20T15:49:55+00:00\",\"dateModified\":\"2018-03-07T21:44:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\"},\"wordCount\":776,\"commentCount\":15,\"publisher\":{\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"image\":{\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/rud.is\/dl\/justthemap.svg\",\"keywords\":[\"post\"],\"articleSection\":[\"Charts &amp; Graphs\",\"d3\",\"Data Visualization\",\"DataVis\",\"DataViz\",\"maps\",\"R\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\",\"url\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\",\"name\":\"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial) - rud.is\",\"isPartOf\":{\"@id\":\"https:\/\/rud.is\/b\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/rud.is\/dl\/justthemap.svg\",\"datePublished\":\"2014-09-20T15:49:55+00:00\",\"dateModified\":\"2018-03-07T21:44:24+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage\",\"url\":\"https:\/\/rud.is\/dl\/justthemap.svg\",\"contentUrl\":\"https:\/\/rud.is\/dl\/justthemap.svg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/rud.is\/b\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/rud.is\/b\/#website\",\"url\":\"https:\/\/rud.is\/b\/\",\"name\":\"rud.is\",\"description\":\"&quot;In God we trust. All others must bring data&quot;\",\"publisher\":{\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/rud.is\/b\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\",\"name\":\"hrbrmstr\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"url\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"width\":460,\"height\":460,\"caption\":\"hrbrmstr\"},\"logo\":{\"@id\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\"},\"description\":\"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7\",\"sameAs\":[\"http:\/\/rud.is\"],\"url\":\"https:\/\/rud.is\/b\/author\/hrbrmstr\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial) - rud.is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/","og_locale":"en_US","og_type":"article","og_title":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial) - rud.is","og_description":"The BBC did a pretty good job [live tracking the Scotland secession vote](http:\/\/www.bbc.com\/news\/events\/scotland-decides\/results), but I really didn&#8217;t like the color scheme they chose and decided to use the final tally site as the basis for another tutorial using the tools from the Hadleyverse and taking advantage of the fact that newer `gdal` libraries can read [&hellip;]","og_url":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/","og_site_name":"rud.is","article_published_time":"2014-09-20T15:49:55+00:00","article_modified_time":"2018-03-07T21:44:24+00:00","og_image":[{"url":"https:\/\/rud.is\/dl\/justthemap.svg","type":"","width":"","height":""}],"author":"hrbrmstr","twitter_card":"summary_large_image","twitter_misc":{"Written by":"hrbrmstr","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#article","isPartOf":{"@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/"},"author":{"name":"hrbrmstr","@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"headline":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial)","datePublished":"2014-09-20T15:49:55+00:00","dateModified":"2018-03-07T21:44:24+00:00","mainEntityOfPage":{"@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/"},"wordCount":776,"commentCount":15,"publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"image":{"@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage"},"thumbnailUrl":"https:\/\/rud.is\/dl\/justthemap.svg","keywords":["post"],"articleSection":["Charts &amp; Graphs","d3","Data Visualization","DataVis","DataViz","maps","R"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/","url":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/","name":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial) - rud.is","isPartOf":{"@id":"https:\/\/rud.is\/b\/#website"},"primaryImageOfPage":{"@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage"},"image":{"@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage"},"thumbnailUrl":"https:\/\/rud.is\/dl\/justthemap.svg","datePublished":"2014-09-20T15:49:55+00:00","dateModified":"2018-03-07T21:44:24+00:00","breadcrumb":{"@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#primaryimage","url":"https:\/\/rud.is\/dl\/justthemap.svg","contentUrl":"https:\/\/rud.is\/dl\/justthemap.svg"},{"@type":"BreadcrumbList","@id":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/rud.is\/b\/"},{"@type":"ListItem","position":2,"name":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial)"}]},{"@type":"WebSite","@id":"https:\/\/rud.is\/b\/#website","url":"https:\/\/rud.is\/b\/","name":"rud.is","description":"&quot;In God we trust. All others must bring data&quot;","publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/rud.is\/b\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886","name":"hrbrmstr","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","width":460,"height":460,"caption":"hrbrmstr"},"logo":{"@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1"},"description":"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7","sameAs":["http:\/\/rud.is"],"url":"https:\/\/rud.is\/b\/author\/hrbrmstr\/"}]}},"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p23idr-MQ","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":3413,"url":"https:\/\/rud.is\/b\/2015\/05\/15\/u-s-drought-monitoring-with-hexbin-state-maps-in-r\/","url_meta":{"origin":3028,"position":0},"title":"U.S. Drought Monitoring With Hexbin State Maps in R","author":"hrbrmstr","date":"2015-05-15","format":false,"excerpt":"On the news, today, of the early stages of drought hitting the U.S. northeast states I decided to springboard off of yesterday's post and show a more practical use of hexbin state maps than the built-in (and still purpose unknown to me) \"bees\" data. The U.S. Drought Monitor site supplies\u2026","rel":"","context":"In &quot;cartography&quot;","block_context":{"text":"cartography","link":"https:\/\/rud.is\/b\/category\/cartography\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3278,"url":"https:\/\/rud.is\/b\/2015\/02\/15\/introducing-the-streamgraph-htmlwidget-r-pacakge\/","url_meta":{"origin":3028,"position":1},"title":"Introducing the streamgraph htmlwidget R Package","author":"hrbrmstr","date":"2015-02-15","format":false,"excerpt":"We were looking for a different type of visualization for a project at work this past week and my thoughts immediately gravitated towards [streamgraphs](http:\/\/www.leebyron.com\/else\/streamgraph\/). The TLDR on streamgraphs is they they are generalized versions of stacked area graphs with free baselines across the x axis. They are somewhat [controversial](http:\/\/www.visualisingdata.com\/index.php\/2010\/08\/making-sense-of-streamgraphs\/) but\u2026","rel":"","context":"In &quot;d3&quot;","block_context":{"text":"d3","link":"https:\/\/rud.is\/b\/category\/d3\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3498,"url":"https:\/\/rud.is\/b\/2015\/07\/09\/faceted-world-population-by-income-choropleths-in-ggplot\/","url_meta":{"origin":3028,"position":2},"title":"Faceted &#8220;World Population by Income&#8221; Choropleths in ggplot","author":"hrbrmstr","date":"2015-07-09","format":false,"excerpt":"Poynter did a nice interactive piece on world population by income (i.e. \"How Many Live on How Much, and Where\"). I'm always on the lookout for optimized shapefiles and clean data (I'm teaching a data science certificate program starting this Fall) and the speed of the site load and the\u2026","rel":"","context":"In &quot;cartography&quot;","block_context":{"text":"cartography","link":"https:\/\/rud.is\/b\/category\/cartography\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3455,"url":"https:\/\/rud.is\/b\/2015\/06\/07\/animated-us-hexbin-map-of-the-avian-flu-outbreak\/","url_meta":{"origin":3028,"position":3},"title":"Animated US Hexbin Map of the Avian Flu Outbreak","author":"hrbrmstr","date":"2015-06-07","format":false,"excerpt":"The recent announcement of the [start of egg rationing in the U.S.](http:\/\/www.washingtonpost.com\/blogs\/wonkblog\/wp\/2015\/06\/05\/the-largest-grocer-in-the-texas-is-now-rationing-eggs\/) made me curious enough about the avian flu outbreak to try to dig into the numbers a bit. I finally stumbled upon a [USDA site](http:\/\/www.aphis.usda.gov\/wps\/portal\/aphis\/ourfocus\/animalhealth\/sa_animal_disease_information\/sa_avian_health\/sa_detections_by_states\/ct_ai_pacific_flyway\/!ut\/p\/a1\/lVPBkqIwEP2WOexpCxMBAY-oo6Kybo01q3JJNSGB1GCgSNTi7zcwe3CnZnQ3h1Sl-3X369cdlKADSiRcRA5aVBLK7p14ZLVd2sMJtqPFbvyMox-_5nGw8Z3t0jWAowHgL06I_47friOvi3_Bk-VsiHcO2qMEJVTqWhfoCHUhFKGV1ExqUoq0gab9hhWQ6twQXtGz6l8gxQlKUjAodXFryYRioBgRklfNqW_i3X0RIG_xGdOMdm5F0pYoDZqZ1FQTEKQGKrighJftFdqOX01Fho7c9iiAzS3HG6WWm2HbSnmAzYXxyA3AG1L-R487Df-TntNFuHT9jVHQDWwczUywP44xjrxH8b2eDzL0gHsj-1Bk8TwxReabn_56ZeP1CB0NSf9LFmMX7f5TtdXDtmYoib9z5YadQnYTT-PcVABdWN2s0eHuDry7b3agN3y2A-jw6Q4YfnlZpeZD7Ke3REKZOoEh0jDOGtYMikppdLher4OzymCQVxdUn15PgdMK6-0lwM7obR9ayTx_evoNPxBrVg!!\/?1dmy&urile=wcm:path:\/APHIS_Content_Library\/SA_Our_Focus\/SA_Animal_Health\/SA_Animal_Disease_Information\/SA_Avian_Health\/SA_Detections_by_States\/) that had an embedded HTML table of flock outbreak statistics by state, county\u2026","rel":"","context":"In &quot;cartography&quot;","block_context":{"text":"cartography","link":"https:\/\/rud.is\/b\/category\/cartography\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4335,"url":"https:\/\/rud.is\/b\/2016\/04\/13\/52vis-week-3-waste-not-want-not\/","url_meta":{"origin":3028,"position":4},"title":"52Vis Week #3 &#8211; Waste Not, Want Not","author":"hrbrmstr","date":"2016-04-13","format":false,"excerpt":"The Wall Street Journal did a project piece [a while back](http:\/\/projects.wsj.com\/waste-lands\/) in the _\"Waste Lands: America's Forgotten Nuclear Legacy\"_. They dug through [Department of Energy](http:\/\/www.lm.doe.gov\/default.aspx?id=2602) and [CDC](http:\/\/www.cdc.gov\/niosh\/ocas\/ocasawe.html) data to provide an overview of the lingering residue of this toxic time in America's past (somehow, I have to believe the fracking\u2026","rel":"","context":"In &quot;52vis&quot;","block_context":{"text":"52vis","link":"https:\/\/rud.is\/b\/category\/52vis\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/04\/waste.png?fit=1200%2C983&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/04\/waste.png?fit=1200%2C983&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/04\/waste.png?fit=1200%2C983&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/04\/waste.png?fit=1200%2C983&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/04\/waste.png?fit=1200%2C983&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":3141,"url":"https:\/\/rud.is\/b\/2014\/11\/27\/power-outage-impact-choropleths-in-5-steps-in-r-featuring-rvest-rstudio-projects\/","url_meta":{"origin":3028,"position":5},"title":"Power Outage Impact Choropleths In 5 Steps in R (featuring rvest &#038; RStudio &#8220;Projects&#8221;)","author":"hrbrmstr","date":"2014-11-27","format":false,"excerpt":"I and @awpiii were trading news about the power outages in Maine & New Hampshire last night and he tweeted the link to the @PSNH [Outage Map](http:\/\/www.psnh.com\/outage\/). As if the Bing Maps tiles weren't bad enough, the use of a categorical color scale instead of a sequential one[[1](http:\/\/earthobservatory.nasa.gov\/blogs\/elegantfigures\/2011\/05\/20\/qualitative-vs-sequential-color-scales\/)] caused sufficient\u2026","rel":"","context":"In &quot;Charts &amp; Graphs&quot;","block_context":{"text":"Charts &amp; Graphs","link":"https:\/\/rud.is\/b\/category\/charts-graphs\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/3028","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/comments?post=3028"}],"version-history":[{"count":0,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/3028\/revisions"}],"wp:attachment":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media?parent=3028"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/categories?post=3028"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/tags?post=3028"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}