Introduction
The focus of this project will be exploring the imparting of global population and climate information using freely accessible data from different government and research agency websites by guiding students through the steps of building an interactive web page map. This web application displays population and climate information interchangeably on a global scale while also having a temporal component for the climate data. There is a lot of difficulty in determining what is relevant and significant when trying to find and understand climate data so the goal of the web application is to effectively communicate information to a common user. The resulting web map will show shifts in historical and future predicted climate change trends based on climate classification removing the requirement of a scientific background to make sense of the meteorological implications. Laypeople will be able to discern noticeable changes in distinct climate zones across the globe as well as country populations with use of a commonly recognizable user-interface.

data collection
Two different datasets are required for the web application, the first being country polygon data with populations and secondly, climate data. Natural Earth provides free vector and raster map data at 1:10m, 1:50m, and 1:110m scales, for this project 1:10m country boundaries shapefile with 2017 population estimates for 247 countries. World maps of Köppen-Geiger classification observed and projected shifts from 1901 to 2100 are available for download as shapefiles thanks to Climate Change and Infectious Diseases Group. Save all the shapefiles in individual folders (name these appropriately) that then get compressed into zip files (one for country data, eight for climate data). No data preparation or processing is required.

Getting Started with Mapbox Studio
upload the data and create a map style
- Sign up for a free Mapbox account and proceed to Mapbox Studio
- Choose Tilesets from the top bar and select “New tileset” later on we’ll use Mapbox GL to render these vector tiles (‘GL’ comes from “OpenGL” – the industrystandard open graphics library API for vector graphics)
- Upload a zip folder containing the shapefile and all associated ancillary files
- Repeat for all nine shapefiles
- Next, go to Studio and to start styling a new web map select “More options” then “Start blank”
- Name your map style in the top left corner
- Add a new layer choosing your country vector tileset as the data source (you will see the layer highlighted on the x-ray map)
- Edit the name to “Countries” (this layer name will be important in the code) then toggle Style to display the data styling panel in style mode
- For colour, choose to style across data range on the POP_EST attribute and edit the rate of change from linear to step
- You’ll need to add 10 stops at the following population values: 0: #9E95EF, 5000000: #8084E9, 10000000: #717CE6, 25000000: #6274E4, 50000000: #536CE1, 75000000: #4463DE, 100000000: #355BDC, 200000000: #2653D9, 1379302771: #0843D4 you can choose your own colour ramp but make sure you write down the hex number for each layer’s colour because you will need them in your code later
- Change the 1px stroke to white (this is the border colour)
- Add all eight climate layers and rename them to their respective years i.e. “1901-1925”
- Select all eight layers and beside the add new layer button click the folder icon to group the layers and rename the group to “climates” (all eight layers should be
highlighted in the group and thus these next changes will apply to them all at once) - Click on the folder to toggle the Style panel, choose to style across data range of
GRIDCODE and edit the rate of change to exponential base of 1 - You’ll need 9 stops at the following values with the associated colours: 11: #C8FDA5, 14 :#1C920C, 21 :#F97B7B, 27 :#8F0404, 31 :#FCE4A1, 39 :#FE9501, 52: #62B5FD, 61: #B5B0B0, 62: #EBEAEA
- Add 3 Mapbox Streets v7 layers: water, country_label, and admin to finish off the map style to look like the above images
- For now, move the climate layers group below all the other layers and hide it using the small eye icon (arrange the other layers in an appropriate order) we’ll create the population layer in the web map first then move on to the climate layer
- Click “Publish” and go back to your Mapbox Studio page, you should see your new style map in the list
Getting Started with Mapbox GL JS
create a web page for your map and add interactivity with javascript
- Click “Share & use” beside your style map and toggle “Use” in the popup
- Copy your web example HTML code and paste it into a new document in a text editor (I like to use Sublime), save it as “index.html” and change the title to something like “Global Climate & Population Web Map”
if you look at these lines, you’ll see how we’ll link to the Mapbox GL JS library we talked about earlier:<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.49.0/mapboxgl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.49.0/mapboxgl.css' rel='stylesheet' />
this next line of javascript creates the map object that represents the map on your web page (javascript code lives between the script tags):const map = new mapboxgl.Map({…});
- Create another new document and save it as “climate-pop.css” we’ll add our own custom css styling for the webpage to this file
- Below the Mapbox links, add the link:
<link rel="stylesheet" href=“climate-pop.css”> - In the css file, add the following to set the font and spacing styling for the page:
body {
margin: 0;
padding: 0;
font-family: 'Helvetica Neue', Helvetica, Arial, Sans-serif;
}
h1 {
font-size: 1.25rem;
line-height: 1.875rem;
}
h2 {
margin: 0.625rem;
font-size: 1.25rem;
}
h3 {
margin: 0.625rem;
font-size: 1em;
}
p {
font-size: 0.875rem;
margin: 0.625rem;
text-align: left;
}
a {
text-decoration: none;
color: #2dc4b2;
}
- To position the map
divon the page add the following css:
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
- Below the map container
div, add an info box and a legend for the population layer:
<div class='map-overlay' id='info'><h2>Global Population</h2>
<div id='pd'><p><i>(hover over a country)</i></p></div></div>
<div class='map-overlay legend' id='legend'>
<h4>Population in Millions</h4>
</div>
- To set the map overlay display:
.map-overlay {
position: absolute;
bottom: 0;
right: 0;
background: rgba(255, 255, 255, 0.8);
margin-right: 1.25rem;
font-family: Arial, sans-serif;
overflow: auto;
border-radius: 0.1875rem;
}
- And the info box and legend styling:
#info {
top: 0;
height: 6.25rem;
margin-top: 1.25rem;
width: 15.63rem;
}
#legend {
padding: 0.625rem;
box-shadow: 0 0.0625rem 0.125rem rgba(0, 0, 0, 0.1);
line-height: 18px;
height: 200px;
margin-bottom: 40px;
width: 6.25rem;
}
.legend h4 {
margin: 0 0 0.625rem;
}
.legend-key {
display: inline-block;
border-radius: 20%;
width: 0.625rem;
height: 0.625rem;
margin-right: 0.3125rem;
}
- In order to make sure the rest of the javascript code in the script tag (check out the line with
mapboxgl.accessTokenand beyond) can execute, it needs to live in acallback functionthat is executed when the map is finished loading. Add the following lines before thescriptclosing tag (anything written after//is a comment i.e. not executed by the browser):
map.on('load', function() {
// the rest of the code will go in here
});
- All of the following javascript code must be within the curly brackets of the above
callback functionto work - Now you’ll need to create lists for the population stops you created in your country layer style to use for the legend. A list within square brackets is called an
array, and here we are saving thearrays by assigning them to named variables (vars) that we can reference later:
// country styling based on population in millions
var layers = ['0-5', '5-10', '10-25', '25-50', '50-75', '75-100', '100-200', '200-1,000', '1,000+'];
var colors = ['#9E95EF', '#8084E9', '#717CE6', '#6274E4', '#536CE1', '#4463DE', '#355BDC', '#2653D9', '#0843D4'];
- The following code makes use of a common useful code control flow statement, a
forloop. Essentially, we are iterating over thearrays and creating a new legend element for each stop based on the layer name and assigning its colour:
// add country population legend
for (i = 0; i < layers.length; i++) {
var layer = layers[i];
var color = colors[i];
var item = document.createElement('div');
var key = document.createElement('span');
key.className = 'legend-key';
key.style.backgroundColor = color;
var value = document.createElement('span');
value.innerHTML = layer;
item.appendChild(key);
item.appendChild(value);
legend.appendChild(item);
}
- Another common way to control flow is the
if-elsestatement which acts as a way to check for conditions and executing code based on those conditions. We’ll useif-elseto identify which country is at the location of where the cursor is hovering in order to update the info window. When the cursor is hovering over a country (here’s theifcondition), the info window should show the population information for that country (so if condition is true then branch option 1), otherwise it will display the instruction to the user to hover over a country (elsebranch option 2):
// add the global population info window with hover capability
map.on('mousemove', function(e) {
var countries = map.queryRenderedFeatures(e.point, {
layers: ['countries']
});
// update text in UI
if (countries.length > 0) {
// branch option 1
var population = (countries[0].properties.POP_EST/1000000).toFixed(3);
document.getElementById('pd').innerHTML = '<h3><strong>' + countries[0].properties.NAME_LONG + '</strong></h3><p><strong><em>' + population + '</strong> million people</em></p>';
} else {
// branch option 2
document.getElementById('pd').innerHTML = '<p><i>(hover over a country)</i></p>';
}
});
- When you double click the index file you should see the below map open in your browser with the info box, legend and hover functionality that you added:

More Javascript Functionality
- Now we are going to add the climate data layers to our web page. Go back to your map style in Mapbox Studio and click the eye icon to show the climate layers group
- Add the following to both the map-overlay info and legend
divs right after theirid: hidden='true' - Next, we’ll need an
arrayto store our individual year layer names:
// year ranges for each climate layer (match layer name)
var years = ['1901-1925', '1926-1950', '1951-1975', '1976-2000', '2001-2025', '2026-2050', '2051-2075', '2076-2100'];
- We’ll start off by iterating through the climate layers and hiding them so that we only see the first layer by using a
map functionto set the visibility property (you should now see the climate layer in your web page):
// hide all year layers except for the first
for (var i = 1; i < years.length; i++) {
map.setLayoutProperty(years[i], 'visibility', 'none');
}
- Create another legend for the climate data below the map overlay
divs, this time we’ll be adding some more functionality to the legend so we’ll distinguish it by giving it theid“console” (you’ll notice the hyperlinks for the data sources were added):
<div id='console'>
<h1>Climate Change</h1>
<p>Data: <a href='http://koeppen-geiger.vu-wien.ac.at/shifts.htm'>World Maps of Köppen-Geiger Classification</a> Observed and Projected Shifts and <a href='https://www.naturalearthdata.com/downloads/10m-cultural-vectors/10m-admin-0-countries/'>Country Boundaries and 2016 Populations</a></p>
</div>
- Position the information console with the following css:
#console {
position: absolute;
width: 15rem;
margin: 0.625rem;
padding: 0.625rem 1.25rem;
background: rgba(255, 255, 255, 0.8);
}
- You’ll need to add information to communicate what the climate data colours mean. To do this, begin by creating a new
divwith classsessioninside theconsole div:
<div class='session' id='classification'>
<h2>Classification</h2>
<div class='row colors'></div>
<div class='row labels'>
<div class='label'>EQUATORIAL</div>
<div class='label'style='margin-left: 0.375rem; margin-right: -0.5rem;'>ARID</div>
<div class='label'>WARM TEMPERATE</div>
<div class='label' style='margin-left: 0.75rem; margin-right: -0.375rem;'>BOREAL</div>
<div class='label'>POLAR</div>
</div>
</div>
- And add the
sessionstyling to the css file:
.session {
margin-bottom: 1.25rem;
}
.session h2 {
font-size: 1em;
margin: 0.625rem 0.625rem 0.625rem 0;
}
.row {
height: 0.75rem;
width: 100%;
}
.label {
width: 18%;
font-size: 0.5rem;
font-weight: 500;
display: inline-block;
text-align: center;
}
/* climate classification colors */
.colors {
background: linear-gradient(to right, #c8fda5, #1c920c, #f97b7b, #8f0404, #fce4a1, #fe9501, #2a50f8, #62b5fd, #b5b0b0, #ebeaea);
margin-bottom: 0.3125rem;
}
- Now we want to be able to show the different year layers and we’ll do this by adding an interactive time slider to the web page. Add another
session divgiving it the “slidebar”idbelow the first:
<div class='session' id='sliderbar'>
<h2>Year: <label id='active-year'>1901-2100</label></h2>
<input id='slider' class='row' type='range' min='0' max='7' step='1' value='0' />
</div>
- Now we’ll go back to our javascript to add the functionality of the slider to display the different climate year layers one at a time. Use another event listener (
input) similar to the mouse hover function:
document.getElementById('slider').addEventListener('input', function(e) {
// get the current position of the slider (the index corresponds to a year in the array we defined earlier)
var index = parseInt(e.target.value);
// update the map
var selectedLayer = years[index];
e.preventDefault();
e.stopPropagation();
// get the current visibility of the layer
var visibility = map.getLayoutProperty(selectedLayer, 'visibility');
// another if-else control flow statement!
if (visibility === 'visible') {
// branch option 1
map.setLayoutProperty(selectedLayer, 'visibility', 'none');
} else {
// branch option 2
map.setLayoutProperty(selectedLayer, 'visibility', 'visible');
}
// update “Year: ” text in the UI
document.getElementById('active-year').innerText = years[index];
});
- So now you can see the temporal climate data, but what about the population layer? Next you’ll add a toggle to switch between the two datasets to show the corresponding layers and their respective legends. Create another
session divin theconsole divbelow theslider div, theinputtype we’ll use is called a “radio button”:
<div class='session' style='display: inline-flex;'>
<h2>Show</h2>
<div class='row' id='filters'>
<input id='climate-map' type='radio' name='toggle' value='climate-map' checked='checked'>
<label for='climate-map' style='margin-right: 10px;'>Climate</label>
<input id='pop-map' type='radio' name='toggle' value='pop-map'>
<label for='pop-map'>Population</label>
</div>
</div>
- Add the radio button information css:
#filters {
display: inline-flex;
margin: 0.625rem 0.625rem 0.625rem 0;
}
- Like the previous session
divs, you need to add some javascript code to make the buttons actually do something. The listener function waits for a radio buttonchangeeventto fire:
document.getElementById('filters').addEventListener('change', function(e) {
var infoBox = document.getElementById('info');
var selectedMap = e.target.value;
// use an if-else statement here to check which radio button option was clicked
if (selectedMap === 'climate-map') {
// show the climate classification legend
document.getElementById('classification').hidden = false;
sliderbar.hidden = false;
map.setLayoutProperty(years[0], 'visibility', 'visible');
// use a for-loop to hide each climate layer but the first
for (var i = 1; i < years.length; i++) {
map.setLayoutProperty(years[i], 'visibility', 'none');
}
// hide the population legend
legend.hidden = true;
infoBox.hidden = true;
} else {
// hide the climate classification legend
document.getElementById('classification').hidden = true;
sliderbar.hidden = true;
// hide each climate layer to reveal the population layer below
for (var i = 0; i < years.length; i++) {
map.setLayoutProperty(years[i], 'visibility', 'none');
}
// show the population legend
legend.hidden = false;
infoBox.hidden = false;
}
});
- And voila! You’re done!

Going Beyond
Try out some more Mapbox GL JS examples to add even more functionality and interactions to your webpage by exploring the API webpage. Here are some suggestions:
- Display map navigation controls
- Add a details popup
- Add “fly to” functionality
- Add a video
- Show coordinates of the mouse pointer
- Make the web page view fullscreen on load
- Add a “geocoder” to search for a specific country