How to Build a Choropleth Map From Scratch?

    What do you need?

  • An editor (I'm on Sublime, & use Mac OS)
  • QGIS (how to install, below)

Whether for your data journalism project or for a client as a front-end developer, choropleth maps are in vogue, and can be a great way to facilitate an understanding of geospatial insight.

Originating form the Greek word χώρο, which refers to area/region and πλήθος meaning multitude, choropleth maps are thematic maps in which areas are shaded or patterned in proportion to the measurement of the statistical variable being displayed on the map, such as population density or per-capita income. Thank you Wikipedia.

Now to the real deal and to the question, how can you do one from scratch? We want one for the web, and it should be interactive too. When you hover over, we want to be given additional information in a control box. Also, we want an appealing legend (a categorisation what the colour grouping refers to), which we desire to customise.

Please note: While some tutorials (and there are a bunch of) start with the assumption that you already have a Geojson file at hand, this receipt really starts from zero, and is therefor also much longer. Yet, I would assume that you could run through it in less than 20 minutes.


This is what we build


1. Download and Install QGIS

Go to QGIS, and install the latest version (which is currently QGIS 2.10 ,'Pisa' released on 26.06.2015).

You will need to click through to KyngChaos QGIS download page. Here you need to install three different programs:

These are the basic requirements, feel free to add the optional installs too.


2. Start the Project with a Shapefile

First, have a deep think what you actually want to do. For this tutorial, we desire to create a simple map of Germany, and visualise for each Bundesland the unemployment rate for June and July (Germany is a federal republic consisting of sixteen federal states, called Bundesländer, or Länder). It comes close to a standard data journalism project, which you might find it in any modern newsroom. The hope is that you can take any data or any location in the world and produce your own choropleth map from the following receipt.

First we need a shape file of Germany. Via a simple Google search you can find alink to Arcgis's open source file repository. Shapefile under the file ending .shp, a format which developed and regulated by Esri as an open specification for data interoperability among Esri and other GIS software products, we download the entire file to our computer.


3. Start with QGIS

Once the file is dowloaded, and we completed the installation for QGIS, we run QGIS for the first time. Then we import the shapeless into QGIS by highlighting the files in the unzipped file we downloaded earlier (all the files with an .shp ending) and drag them into the little window on the left inside of the QGIS program.

You should now see 4 files appearing. For this map, we only need vg2500_bld, which is the map with polygons for all the Bundesländer. You can delete the other ones if you want.


4. Prepare your data for each Bundesland

Now we come to the interesting parts: the data. Go to either to Bundesagentur für Arbeitor Wikipedia. Scrape the data by highlighting, copy and pasting, or use a scraper such as Kimono or others will do well too. For simple scraping stuff, I like the simplicity of Kimono and its UI. You can also use R or Google Sheets to save your data as a .csv file (make sure that all cells are correctly format, as integers/numbers, and that you don't miss to replace the "," for ".").

Alternatively, simply download the cvs file which I prepared in Google Sheets.

If you want to change your data format in the professional way, feel free to check out this GIS.StackExchange Q&A too.


5. Import CSV file into QGIS

Once you have the CSV file in the right format, import it into your QGIS program by clicking on the little semicolon symbol, or click the dropdown "Layer"--> "Add layer"-->"Add delimited text layer..." Browse and find your cvs file from above. Make sure you check "CSV". Also check "First record has field names". Finally check the box for "No Geometry (attribute only table)". Click Ok, and see you CSV file appearing as a QGIS data table, above the map file in QGIS.


6. Join Layers

Right-click on your vg2500_bld file, and select "Properties". It will open up the window Layer Properties, select "Joins" in the menu on your right (if this isnt already selected), and click on the little green plus sign to add a new joined.

Select your data for the field "join layer" (depending on how you named your csv data when you imported it, in my case it is called "test5"),

For Join Fields, select GEN. Select GEN again for "Target field". GEN is the name of the BundesLänder, which is the common column where we will merge our data. Make sure you enable "Cache join layer in virtual memory". For the field, "Choose which fields are joined", click the fields unemployedJuly, percentJuly, unemployedJune, and percentJune.


7. Add Data

To check whether you were successful in merging the data, click OK twice and go back to your map screen in QGIS. Click then "layer"-->"Open Attribute Table" in your QGIS menu (vg2500_bld highlighted). Volia! You should see 4 additional columns on the very right containing your data from the cvs file, and merged with the shape file data (after the column "SHAPE_AREA").


Character Encoding

One problem still exists. As the character encoding for words that include "ü", ä, and ö are wrongly encoded/represented in the shp file data, we weren't successful in merging several rows.

A simple trick is to change the character encoding. If you right-click again on the vg2500_bld file in QGIS, click "properties", and select "General" on the menu on the right in the window. Click the drop-down for "data source encoding", and select ISO-8859-1 (then click apply). Now, when you go back and check with your "Open Attribute Table" (access it in the QGIS menu via layer"-->"Open Attribute Table), you should be able to see that all fields where successfully merged and all Bundesländer have the correct spelling (more on the topic here).


8. Create your GEO-Json File

We want to create an interactive map for the web, so we need to save the file as a GeoJson file. Right click on vg2500_bld file and select "save as". Select a name for it, and click OK. Now you have another Germany map added to your QGIS selection (mine is called germany4.geojson).


9. HTML/Javascript

Now that you have your geojson file, you want to start a new folder somewhere, and start a fresh index.html file. Create a subfolder (I called it lib), and save your geojson file in the lib folder.

There is a wonderful tutorial on how to create an interactive map with leaflet and Mapbox. We will reuse some of the code and use our geojson file and data for it. Here is how:

Open index.html and your geojson files in your favourite editor.

Leaflet Tutorial

10. Change Geo Json File to Allow Access from Javascript

In order to be able to access your geojson file, you need to add a variable to the GeoJson file. Add "var germany = {" to the very beginning of it, allowing you to access it in Javascript, like shown in the screenshot. Also, click on the very bottom right, to view the geojson file in JSON format.


11. Files & Map View

Now that your data is ready to be used, you will set up your index.html file. Include your geojson file with the right path (remember, you one might be different) via "<script type="text/javascript" src="./lib/germany4.geojson"></script>". Set up your header (with some css styling for the map) and prepare of the body tag. In the CSS style section we will set the style of .into for our tooltip to the following CSS, allowing our tooltip in the corner to have a fancy style: .info { line-height: 1; font-weight: bold; padding: 20px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 2px; } Add the CDN links for Leaflet's javascript and css: link rel="stylesheet" href="" /> script src=""> /script>


12. HTML & Javascript

Next, will add the map by including a div element with the id of map. Set up an extra javascript section tag, which we will fill in the next section.

We first have to set our view in our map variable. To find the right middle of Germany, we will go on Google Maps and search Germany. Hard-click somewhere in the centre of Germany, and you will see a small window popping up, telling you the longitude and latitude of that place (which, for my case is Wartburgkreis. We use the latitude and longitude in our javascript setview function, allowing us to get a nice centred view for the map in leaflet.


13. Mapbox ID

For the L.tileLayer part, set up a free account at Mapbox. You need to start a new project. There are many more options to change your mapping, but we will only change the Base-map to "dark" via clicking on Style (you can do a whole lot of other things with your MapBox map). Next, click on save the map, and copy your Map ID to your clipboard. Take your ID into your HTML file and paste it into where it says "yourMapBoxID" of the "L.tileLayer" part.

L.tileLayer(''yourMapBoxID'/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6IjZjNmRjNzk3ZmE2MTcwOTEwMGY0MzU3YjUzOWFmNWZhIn0.Y8bhBaUMqFiPrDRW9hieoQ', {
						            maxZoom: 18,
						            id: 'mapbox.light'

Next, set up the information when the use hovers over the polygons.


14. Get Colouring of the Polygons Depending On the Rate of Unemployment

For the colouring, you need to set up the function "getColor(d)" and define the different distributions. To help you to find the right html colour range encoding for your choropleth heat-map, go to ColorBrewer2 and click on "diverging". Here you can select the number of data classes (in my case, I had 8 classes). I copy the # marked encoded colour tags into my Javascript section for the different buckets I set up. Important is that you set the "" path (depending which header names you chose in QGIS) in your style function, for fillColor: getColor.


15. Connect GeoJson File Variable, Add Sources and Define Your Legend

Set your sources attributions in the "map.attributionControl". In the "var legend", set your legend into the bottom right corner. Define the "grades" and the value intervals you already setup, in the "function getColor(d)". For more info on the javascript parts, there is another tutorial explaining more in detail how the leaflet.js work together with Mapbox for an interactive choropleth map.

Download Data & file


For more tutorials on building maps,
you may want to also check the following links


Case study for US
interactive choropleth map


Create an Interactive Map
Using Javascript and HTML5 Canvas


Create a Choropleth Map in D3.js
and Leaflet.js




Use python's folium package for
mapping together with leaflet.js


Mike Bostock's Let’s Make a Map
(in d3.js) tutorial


Interactive and Multivariate
Choropleth Maps with D3

Stack Overflow

Stack Overflow: Trouble with Choropleth Map
& Leaflet