<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/how-to-make-a-global-map-in-r-step-by-step/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://sharpsightlabs.com/blog/map-talent-competitiveness/"> r-bloggers – SHARP SIGHT LABS</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/join-newsletter-rapid-mastery/"><br>
<img sizes="(max-width: 1568px) 100vw, 1568px" alt="" class="wp-image-3048" src="https://i1.wp.com/sharpsightlabs.com/wp-content/uploads/2017/02/talent-competitiveness_top-10.png?resize=456%2C259" data-recalc-dims="1"><br>
</a></p>
<p>In the last several blog posts at Sharp Sight, I’ve created <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/map-unemployment-nov-2016/">several</a> <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/map-geospatial-data-usa-rivers/">different</a> <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/human-capital-map/">maps</a>.</p>
<p>Maps are great for practicing data visualization. First of all, there’s a lot of data available on places like Wikipedia that you can map. </p>
<p>Moreover, creating maps typically requires several essential skills in combination. Specifically, you commonly need to be able to retrieve the data (e.g., scrape it), mold it into shape, perform a join, and visualize it. Because creating maps requires several skills from data manipulation and data visualization, creating them will be great practice for you. </p>
<p>And if that’s not enough, a good map just looks great. They’re visually compelling.</p>
<p>With that in mind, I want to walk you through the logic of building one step by step. </p>
<p>In the last several blog posts about maps, I gave <em>some</em> detail about how to create them, but in this post, I want to give a little more detail about the logic.</p>
<p>I want you to understand the <em>thinking</em> behind the code. This post will show you how to make a map, and explain the R code that creates it.</p>
<p>Ok, let’s get to it.</p>
<h1>Install packages</h1>
<p>First, we’ll just install the packages we’re going to use. Pretty straightforward.</p>
<pre class="wp-code-highlight">
#=================
# INSTALL PACKAGES
#=================
library(tidyverse)
library(rvest)
library(magrittr)
library(ggmap)
library(stringr)
</pre>
<h1>Scrape data from website</h1>
<p>The data that we’re going to plot exists as a table on a website. </p>
<p>The data is a list of the top 10 countries with the highest ‘talent competitiveness’ (i.e., the countries that are most attractive to talented workers). The data was created as part of an analysis by the business school, INSEAD.</p>
<p>If you go to the webpage that summarizes the talent competitiveness <a href="https://www.insead.edu/news/2017-global-talent-competitiveness-index-davos">report</a>, you’ll find the following table:</p>
<p><b>Global Talent Competitiveness Index 2017 Rankings: Top Ten</b><br>
<img sizes="(max-width: 1900px) 100vw, 1900px" alt="" class="wp-image-3050" src="https://i0.wp.com/sharpsightlabs.com/wp-content/uploads/2017/02/talent_competitiveness_table.png?resize=456%2C134" data-recalc-dims="1"></p>
<p>This is the data we’re after, and we have to scrape it and pull it into R.</p>
<p>To do this, we need to use a few tools from the  package. </p>
<p>First, we’ll use  to connect the the URL where the data lives (i.e., connect to the webpage).</p>
<p>Next, you’ll see that we use the magrittr pipe . We’re using the pipe operator to chain together a set of other web scraping functions. Specifically, you’ll see that we’re using  and . Essentially, we’re using these in combination to extract the <em>table</em> that contains the data and parse it into a dataframe.</p>
<pre class="wp-code-highlight">
#============
# SCRAPE DATA
#============

html.global_talent &lt;- read_html(&quot;https://www.insead.edu/news/2017-global-talent-competitiveness-index-davos&quot;)

df.global_talent_RAW &lt;- html.global_talent %>%
                          html_nodes(&quot;table&quot;) %>%
                          extract2(1) %>%
                          html_table()

</pre>
<h1>Data manipulation: split and recombine into long-form dataframe</h1>
<p>If you inspect the data, you’ll notice that the ranks are split up between two columns. The country names are also split between two columns. </p>
<pre class="wp-code-highlight">
print(df.global_talent_RAW)

# X1              X2  X3          X4
#  1     Switzerland   6   Australia
#  2       Singapore   7  Luxembourg
#  3  United Kingdom   8     Denmark
#  4   United States   9     Finland
#  5          Sweden  10      Norway
</pre>
<p>This is an improper structure for the data, so we need to restructure it. Specifically, we need all of the ranks in one column and all of the countries in another column.</p>
<p>To do this we’re going to split  into two parts:  and . Then we’ll take those two parts and stack them up on top of each other, such that all of the ranks are in one column, and the country names are in another column.</p>
<p>To split the data, we’ll just <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/dplyr-intro-data-manipulation-with-r/">use  to select the specific columns</a> we want in  and  respectively.</p>
<p>Notice that we also rename the columns using :</p>
<pre class="wp-code-highlight">
#=============================================
# SPLIT INTO 2 DATA FRAMES
# - the data are split into 4 columns, whereas
#   we want all of the data in columns
#=============================================

df.global_talent_1 &lt;- df.global_talent_RAW %>% select(X1, X2) %>% rename(rank = X1, country = X2)
df.global_talent_2 &lt;- df.global_talent_RAW %>% select(X3, X4) %>% rename(rank = X3, country = X4)

</pre>
<p>After splitting them, we’ll recombine them with :</p>
<pre class="wp-code-highlight">
#===========
# RECOMBINE
#===========

df.global_talent &lt;- rbind(df.global_talent_1, df.global_talent_2)


# INSPECT
glimpse(df.global_talent)
print(df.global_talent)

</pre>
<h1>Data manipulation: trim excess whitespace</h1>
<p>Now, we’ll do some simple string manipulation to modify the country names.</p>
<p>Specifically, if you use  and look at the data, you’ll see that the country names have leading spaces. </p>
<pre class="wp-code-highlight">
glimpse(df.global_talent)

# Observations: 10
# Variables: 2
# $ rank    &lt;chr> &quot; 1&quot;, &quot; 2&quot;, &quot; 3&quot;, &quot; 4&quot;, &quot; 5&quot;, &quot; 6&quot;, &quot; 7&quot;, &quot; 8&quot;, &quot; 9&quot;, &quot; 10&quot;
# $ country &lt;chr> &quot; Switzerland&quot;, &quot; Singapore&quot;, &quot; United Kingdom&quot;, &quot; United States&quot;, &quot; Sw...
</pre>
<p>We need to remove these.</p>
<p>To do so, we’ll use  from the  package.</p>
<pre class="wp-code-highlight">
#==========================
# STRIP LEADING WHITE SPACE
#==========================

df.global_talent &lt;- df.global_talent %>% mutate(country = str_trim(country)
                                                ,rank = str_trim(rank)
                                                )

</pre>
<p>Notice that we’re doing this inside of , which allows us to <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/dplyr-intro-data-manipulation-with-r/">modify a variable inside of a data frame</a>. Essentially, we’re taking the dataset  and piping it into . Then inside of , we’re calling  to do the real work of stripping off the excess whitespace.</p>
<p>Now if we print out the data, it looks good.</p>
<pre class="wp-code-highlight">
# INSPECT
print(df.global_talent)

#   rank         country
#     1     Switzerland
#     2       Singapore
#     3  United Kingdom
#     4   United States
#     5          Sweden
#     6       Australia
#     7      Luxembourg
#     8         Denmark
#     9         Finland
#    10          Norway
</pre>
<p>All of the ranks are in one column, and the country names are in another column.</p>
<h1>Get world map</h1>
<p>Next, we’re going to get a map of the world.</p>
<p>This is very straightforward. To do this, we’ll use .</p>
<pre class="wp-code-highlight">
#==============
# GET WORLD MAP
#==============

map.world &lt;- map_data(&quot;world&quot;)

</pre>
<h1>Recode country names</h1>
<p>The next thing we need to do is join the global talent data,  (which we want to map), to the map itself, . </p>
<p>To do this, we need to use a <em>join</em> operation. However, to join these two separate datasets together, we’ll need the country names to be exactly the same. The problem, is that the country names are <em>not</em> all exactly the same in the two different datasets. </p>
<p>For the time being, I’ll set aside how to detect these dissimilarities between country names. Suffice it to say, the country names in  do not all exactly match the country names in .</p>
<p>That being the case, we’ll need to recode the names that don’t match. Specifically, out of the 10 countries in , 2 don’t match the names in :  and .</p>
<p>We’ll recode them with :</p>
<pre class="wp-code-highlight">
#===========================================
# RECODE NAMES
# - Two names in the 'global talent' data
#   are not the same as the names in the 
#   map
# - We need to re-name these so they match
# - If they don't match, we won't be able to 
#   join the datasets
#===========================================

# INSPECT
as.factor(df.global_talent$country) %>% levels()

# RECODE NAMES
df.global_talent$country &lt;- recode(df.global_talent$country
                                  ,'United States' = 'USA'
                                  ,'United Kingdom' = 'UK'
                                  )

</pre>
<p>This is fairly straightforward. The  function operates like all of the other  functions. The first argument inside of  is the item we want to change (). Then we have a set of name-pairs, with the old name on the left hand side (i.e., ) and the new name on the right hand side (i.e., ).</p>
<p>If we take a quick look after executing this, you’ll see that  and  were successfully recoded to  and :</p>
<pre class="wp-code-highlight">
# INSPECT
print(df.global_talent)

#   rank     country
#     1 Switzerland
#     2   Singapore
#     3          UK
#     4         USA
#     5      Sweden
#     6   Australia
#     7  Luxembourg
#     8     Denmark
#     9     Finland
#    10      Norway
</pre>
<h1>Join 2 datasets together</h1>
<p>Next, we’ll join together  and .</p>
<pre class="wp-code-highlight">
#================================
# JOIN
# - join the 'global talent' data 
#   to the world map
#================================

# LEFT JOIN
map.world_joined &lt;- left_join(map.world, df.global_talent, by = c('region' = 'country'))

</pre>
<p>If you’re familiar with joins, this is fairly straightforward. Of course, if you don’t use joins often, this might not make sense.</p>
<p>Essentially, we’re using  to join these together. Explaining how joins work is beyond the scope of this blog post, but I’ll quickly explain how this works.</p>
<p>Take a look at the dataset . It contains the data to create a world map.</p>
<pre class="wp-code-highlight">
head(map.world)
</pre>
<p>It contains essentially all of the countries of the world, as well as information that’s required to plot those countries as polygons. That being the case, it contains information on over 100 countries.</p>
<p>On the other hand, , only contains 10 countries.</p>
<p>The objective right now is to join them together, trying to “join” the two datasets by looking for a match on the country name.</p>
<p>If the join operation finds a match, then great. It’s a match, and it will combine the records from the two different datasets. </p>
<p>But what if there’s not a match? For example, “Brazil” is in , but it’s <em>not</em> in . What happens then?</p>
<p>How these cases of “match” and “no match” are handled is the critical feature of different join types. </p>
<p>In the case of a “left join” we’ll keep everything in the “left hand” dataset. Which is the “left hand” dataset? Don’t overthink it. It’s the dataset that’s syntactically on the left in the following line of code:</p>
<p>.</p>
<p>That is,  is the “left hand” dataset. </p>
<p>In a left join, the operation will keep <em>everything</em> in the left hand dataset, <em>even if there’s not a match</em>. Moreover, when there <strong>is</strong> a match, it will attach the data in the “right hand” dataset.</p>
<p>This is important, because we want to plot all of the countries in the world (so we need to keep everything in ). This is why we’re using .</p>
<h1>Create “flag” to highlight specific countries</h1>
<p>Even though we’re going to plot the entire world map, the point of this map is to highlight the top ten countries with the highest talent competitiveness. That being the case, we need a way to distinguish those countries in the newly merged data.</p>
<p>There are a few ways to do this, but we’ll do it by using  to create a “flag” variable called .</p>
<p>Basically, if  is null, we’ll set the flag to “F” (i.e. ‘false’) and otherwise we’ll set  to “T”.</p>
<pre class="wp-code-highlight">
#===================================================
# CREATE FLAG
# - in the map, we're going to highlight
#   the countries with high 'talent competitiveness'
# - Here, we'll create a flag that will
#   indicate whether or not we want to 
#   &quot;fill in&quot; a particular country 
#   on the map
#===================================================

map.world_joined &lt;- map.world_joined %>% mutate(fill_flg = ifelse(is.na(rank),F,T))
head(map.world_joined)
</pre>
<p>This will give us an indicator variable that we can use to highlight the countries with high talent competitiveness.</p>
<h1>Create point locations for Singapore and Luxembourg</h1>
<p>One last thing before we plot the map.</p>
<p>Two of the countries with high talent competitiveness, Singapore and Luxembourg, are very small. This makes them quite difficult to see on a map.</p>
<p>To make them more visible, we’re going to <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/how-to-create-a-scatterplot-in-r/">plot them as points</a>.</p>
<p>To do this, we need to <em>create</em> a separate dataset that contains the latitude and longitude data for the center of these countries.</p>
<p>We’ll simply create a new dataset  that contains the country names. Then we’ll use  to get the latitude and longitude information.</p>
<p>Finally, we’ll use  to attach the lat/long data to .</p>
<pre class="wp-code-highlight">
#=======================================================
# CREATE POINT LOCATIONS FOR SINGAPORE AND LUXEMBOURG
# - Luxembourg and Singapore are countries with
#   high 'talent competitiveness'
# - But, they are both small on the map, and hard to see
# - We'll create points for each of these countries
#   so they are easier to see on the map
#=======================================================

df.country_points &lt;- data.frame(country = c(&quot;Singapore&quot;,&quot;Luxembourg&quot;),stringsAsFactors = F)
glimpse(df.country_points)

#--------
# GEOCODE
#--------

geocode.country_points &lt;- geocode(df.country_points$country)

df.country_points &lt;- cbind(df.country_points,geocode.country_points)

# INSPECT
print(df.country_points)

#    country        lon       lat
#  Singapore 103.819836  1.352083
# Luxembourg   6.129583 49.815273

</pre>
<p>When we finally inspect the data, we see that this dataset now has the names of those two countries, and the lat/long data that we need in order to plot them as points.</p>
<h1>Plot the map using </h1>
<p>Here we go. Everything is ready. We can plot.</p>
<pre class="wp-code-highlight">
#=======
# MAP
#=======

ggplot() +
  geom_polygon(data = map.world_joined, aes(x = long, y = lat, group = group, fill = fill_flg)) +
  geom_point(data = df.country_points, aes(x = lon, y = lat), color = &quot;#e60000&quot;) +
  scale_fill_manual(values = c(&quot;#CCCCCC&quot;,&quot;#e60000&quot;)) +
  labs(title = 'Countries with highest &quot;talent competitiveness&quot;'
       ,subtitle = &quot;source: INSEAD, https://www.insead.edu/news/2017-global-talent-competitiveness-index-davos&quot;) +
  theme(text = element_text(family = &quot;Gill Sans&quot;, color = &quot;#FFFFFF&quot;)
        ,panel.background = element_rect(fill = &quot;#444444&quot;)
        ,plot.background = element_rect(fill = &quot;#444444&quot;)
        ,panel.grid = element_blank()
        ,plot.title = element_text(size = 30)
        ,plot.subtitle = element_text(size = 10)
        ,axis.text = element_blank()
        ,axis.title = element_blank()
        ,axis.ticks = element_blank()
        ,legend.position = &quot;none&quot;
        )

</pre>
<p>Here’s what the ggplot code produces:</p>
<p><a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/join-newsletter-rapid-mastery/"><br>
<img sizes="(max-width: 1568px) 100vw, 1568px" alt="" class="wp-image-3048" src="https://i1.wp.com/sharpsightlabs.com/wp-content/uploads/2017/02/talent-competitiveness_top-10.png?resize=456%2C259" data-recalc-dims="1"><br>
</a></p>
<p>Let’s break this down a little.</p>
<p>You’ll notice that we’re plotting the whole world map. We’re able to do this because we used the  above, and kept all of our countries.</p>
<p>Now take a look at the highlighted countries. These are the 10 countries in the data that we scraped. How did we highlight them? We used the “flag” variable that we created, , and mapped it to the  aesthetic. You’ll see a few lines later that we use .  is specifying that we want to color a country grey (i.e., ) if , and red () if . Do you get the logic now? We created the flag specifically so we could do this. We mapped the flag to the fill aesthetic, and then used  to control the exact colors.</p>
<p>One more thing to point out. We used 2 <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/r-package-think-about-visualization/">distinct layers</a> in this map: the country map (given by , but then a separate layer of points given by . And what are the points that we’ve plotted? The locations of Singapore and Luxembourg. Earlier in this tutorial, we created that separate dataset with Singapore and Luxembourg, and this is why. We wanted to plot those 2 countries as points (because they are otherwise too small to really see on the map).</p>
<h1>To do this, you mostly just need the foundations</h1>
<p>Loyal <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/">Sharp Sight</a> readers and talented data scientists will know the drill: learn the foundations.</p>
<ul>
<li></li>
<li> tools, especially 
<li>a few tools from base R like , , </li>
<li>a few tools from </li>
</ul>
<p>If you’re a beginner, the full code in this blog post might look complicated, but you need to realize that there are only a couple dozen core tools that we’re using here. That’s it. </p>
<p>That’s why I strongly recommend that you master the foundations first. If you can master a few dozen critical, high-frequency tools, a whole world of possibilities will open up. I repeat: if you want to master data science, master the basics.</p>
<h1>Sign up to learn data science</h1>
<p>People who know data science will have massive opportunities in the age of big data.</p>
<p><a href="http://sharpsightlabs.com/join-newsletter-rapid-mastery/"><strong>Sign up now</strong></a> to get our free <em>Data Science Crash Course</em>, where you’ll learn:</p>
<ul>
<li>a step-by-step data science learning plan </li>
<li>the 1 programming language you need to learn </li>
<li>3 essential data visualizations</li>
<li>how to do data manipulation in R</li>
<li>how to get started with machine learning</li>
<li>and more …</li>
</ul>
<p><a href="http://sharpsightlabs.com/join-newsletter-rapid-mastery/">
<p><strong>SIGN UP NOW</strong></p>
<p></p></a>
<p>The post <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/blog/map-talent-competitiveness/">How to make a global map in R, step by step</a> appeared first on <a target="_blank" rel="nofollow" href="http://sharpsightlabs.com/">SHARP SIGHT LABS</a>.</p>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://sharpsightlabs.com/blog/map-talent-competitiveness/"> r-bloggers – SHARP SIGHT LABS</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/XACxHAFhdVk"></a></div>