Menu Search
Jump to the content X X
Smashing Conf San Francisco

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf San Francisco, dedicated to smart front-end techniques and design patterns.

A Guide To Building SVG Maps From Natural Earth Data

Interactive maps are a fantastic way to present geographic data to your visitors. Libraries like Google Maps and Open Street Maps are a popular choice to do this and they excel at visualizing street-level data. However, for small-scale maps, SVG maps are often a better option. They are lightweight, fully customizable and are not encumbered by any licensing restrictions.

It’s possible to find a number of SVG maps released under permissible licenses in the Wikimedia Commons. Unfortunately, it’s likely that you will eventually find these options lacking. The map you need may not exist, may be out of date (as borders change), or may not be well-formatted for web use. This article will explain how to create your own SVG maps using Natural Earth data and open source tools. You will then be able to create SVG maps of any area of the world, using any projection, at any resolution. As an illustration, we will create an SVG world map.

The process will require us to:

  • Download geographic data from Natural Earth data
  • View and edit the geographic data using QGIS
  • Convert the geographic data into SVG using Kartograph.py

Getting The Geographic Data Link

To start, we need geographic data for country borders. This data is available from Natural Earth1. Natural Earth is built by volunteers and supported by the North American Cartographic Information Society. It specializes in small-scale maps that are well-suited for the web. This means the maps will look great at the country or province level, but aren’t of a high enough resolution to show the neighborhoods of a city. Natural Earth releases its maps into the public domain.

To see all maps available for download, view the Natural Earth downloads page2.

Many borders in the world are hotly contested. Natural Earth’s policy is to draw borders based on who controls the situation on the ground. We will be primarily working off of a small-scale cultural map, which contains all 247 countries in the world, and has boundary lakes removed. You can download it as a zip file (186KB)3.

The data you download is stored in the shapefile4 (.shp) format. Shapefile is an open standard geospatial vector data format created by Esri. The shapefile is accompanied by complementary files with the following extensions: .dbf, .prj and .shx. Together, these files contain the vector geometry, attributes (name, id, etc.) and geospatial information for each country. For simplicity, when people refer to a shapefile, they are really referring to this group of files.

Viewing The Geographic Data Link

To see the data we just downloaded, we need to use GIS5 (geographic information systems) software. QGIS is open source GIS software. It runs on Linux, Mac OS X and Windows. Download it from QGIS.6 This tutorial will be using QGIS 2.8.2 Wien.

After you have installed QGIS, open the QGIS Desktop application. QGIS is a powerful program that can work with many types of geographic data. Because of this, it can be quite intimidating. We’ll only be using a small fraction of its functionality and can ignore much of what QGIS offers. For example, since we aren’t working with any raster images (like satellite photography), we can ignore tools related to raster images.

To get started, we’ll add our shapefile as a vector layer to our project.

  • Select Layer → Add Layer → Add Vector Layer (from the menu bar)
  • Browse to and open ne_110m_admin_0_countries_lakes.shp
  • The map should appear in the window (it may be a different color for you)
World map7
The world map vector layer. (View large version8)

Notice that ne_110m_admin_0_countries_lakes.shp has been added to the Layers dialog.

Layers dialog
The new layer.

Layers in QGIS are similar to layers you find in photo editing software like Photoshop or GIMP. You must select a layer before you can work on it. As you go through this tutorial, if you find a tool isn’t working properly, you have likely neglected to select the current layer.

It’s also possible to hide layers from view by unchecking the box. This allows you to add multiple shapefiles to your project and view them individually.

After adding a vector layer, it’s a good idea to save your work: Project → Save

Each country contains a list of attributes. You can view these attributes in a table: Layer → Open Attribute Table

Attribute table9
The country attribute table. (View large version10)

The Natural Earth data contains a wealth of information about each country. We’ll be using two-letter ISO codes11 to uniquely identify countries. These are stored in the iso_a2 variable. We’ll also use the country name (name) to label countries in our SVG file. Feel free to explore the table to get a sense of the data. When you’re done, close the table.

Editing The Geographic Data Link

(You can skip this section if you are happy with the Natural Earth data defaults.)

It’s possible to edit the individual geographic shapes using QGIS. You will probably not need to redraw borders, but you may want to split a country into parts.

Each shape in our shapefile is referred to as a feature in QGIS. To select a feature, choose: View → Select → Select Feature(s)
and then click on your target. The entire feature should turn yellow. For example, this is what France looks like when you click on it:

France selected12
France is selected and highlighted. (View large version13)

Notice that France includes French Guiana in South America. This is because French Guiana is an overseas département and region of France (French Guiana on Wikipedia14). Nonetheless, French Guiana has its own unique ISO code and, for many applications, it makes sense to display it as a separate entity.

Splitting France into two separate entities is a straightforward process, but it requires a number of steps:

  1. Install the Digitizing Tools QGIS Plugin:
    • Plugins → Manage and Install Plugins
    • Search for Digitizing Tools
    • Select Digitizing Tools
    • Install Plugin
  2. Display editing tools in the toolbar: View → Toolbars → Advanced Digitizing; and View → Toolbars → Digitizing Tools
  3. Put the map in edit mode: Layer → Toggle Editing
  4. Select France: View → Select → Select Feature(s)
  5. Click on France in the map view
  6. Choose Split selected multi-part features to single part from the toolbar.
    05-split-opt

    This will split all parts of France into separate entities.

  7. Put France back together:
    • Select both the mainland of France and the island of Corsica. To select multiple features, hold down Ctrl (Cmd on Mac).
    • Merge the mainland of France and the island Corsica (Edit → Merge Selected Features) – you will be alerted that the feature attributes will also be merged. Click OK.
  8. Edit French Guiana’s attributes:
    • View → Identify Features
    • Click on French Guiana. This will bring up the attributes for French Guiana. It currently has the attributes for France. We need to replace these with attributes for French Guiana. Click on the Edit feature form icon as shown in the screenshot. Replace the ISO code with “GF” and the name with “French Guiana”.
    Replacing attributes15
    Replacing French Guiana’s attributes. (View large version16)
  9. Save your changes: Layer → Save Layer Edits

That’s all! French Guiana is now its own feature and we’ve given it unique attributes. To learn more about editing, check out the QGIS documentation17.

Creating SVG Files With Kartograph.py Link

Kartograph.py18 is a lightweight Python library that will convert our shapefile into a web-friendly SVG file. It was created by New York Times graphics editor Gregor Aisch19 and is available under an AGPL license.

To install Kartograph.py, follow these installation instructions20. This process will require you to install a number of dependencies. If you’re not ready to commit to so many installations, you can install Kartograph.py in a virtual machine. Or, you can just download the SVG output shown as images in this article. This tutorial was created using Kartograph.py installed in Ubuntu 14.04 LTS.

Kartograph is a command line program that requires a JSON configuration file. Name this file config.json and place it in the same directory as the shapefile. This file must contain a layers property with a dictionary of the layers we want to convert and the location of each layer’s shapefile. To convert ne_110m_admin_0_countries_lakes.shp we can use the following config.json:

{
  "layers": {
    "countries": {
      "src": "ne_110m_admin_0_countries_lakes.shp"
    }
  }
}

Then execute the following Kartograph command in the console:

kartograph config.json -o world_basic.svg

Kartograph will create world_basic.svg in the current directory. If you open this file in a modern browser, you will see a map of the world.

See the Pen gaOXNv21 by Smashing Magazine (@smashingmag2622) on CodePen2723.

SVG world map.

Changing The Map Projection Link

You may notice that this map looks somewhat different from the map in QGIS. There are a number of different ways to project our three-dimensional Earth into two-dimensional space. By default, Kartograph uses the Robinson projection, an aesthetically pleasing projection commonly used for world maps. However, you may prefer to work with the Mercator projection (used by Google Maps) which projects latitude and longitude as straight lines. To do so, add a proj object after the layers object in the config.json file:

"proj": {
  "id":"mercator"
}

Reducing The File Size Link

Often, the SVG file you create may be too large to be practical for web use. Kartograph includes the Visvalingam-Whyatt simplification algorithm24. This tool makes it possible to dramatically reduce the size of a file with only subtle visual changes to country borders. Our file is already quite small (231KB), but we can simplify it further by adding a simplify property to the end of the countries property:

"simplify": 1

The higher the value of simplify, the more country borders will be simplified and the smaller the file will become.

Filtering Out Features Link

By default, the map will include all the features present in the shapefile. You may, however, want to exclude certain features from the SVG file. For example, we may wish to remove Antarctica since it is of less relevance to our task. Kartograph includes a filter tool that makes it possible to filter features based on their attributes. We can exclude Antarctica using its ISO code. To do this, add a filter property to the countries layer:

"filter": ["iso_a2", "not in", ["AQ"]],

Saving Data Within The SVG File Link

Finally, we want our SVG map to include data attributes with each country’s ISO code and name. This will allow us to identify SVG elements in the browser. To do this, add an attributes property to the countries layer:

"attributes": {
  "id": "iso_a2", 
  "name": "name"
},

Putting It All Together Link

After making these changes, config.json will consist of the following:

{
  "layers": {
    "countries": { 
      "src": "ne_110m_admin_0_countries_lakes.shp",
      "filter": ["iso_a2", "not in", ["AQ"]],
      "attributes": {
        "id": "iso_a2",
        "name": "name"
      },
      "simplify": "1"
    }
  },
  "proj": {
    "id": "mercator"
  }
}

Execute the same Kartograph command as before (with an updated file name):

kartograph config.json -o world.svg

Kartograph will create a new map world.svg that is smaller and looks quite different:

See the Pen LpYOob25 by Smashing Magazine (@smashingmag2622) on CodePen2723.

The new SVG world map.

If you open this file in a text editor, you will see that each <path> now includes identifying data in the following form:

data-id="US" data-name="United States" id="US"

This introduction only scratches the surface of what is possible with Kartograph. You can use multiple layers, join features together, and frame the map using latitude and longitude. You can learn about these options and more in the Kartograph.py documentation28.

Adding The SVG Map To A Website Link

Now that you’ve created an SVG map, you’ll probably want to customize it and add it to your website. Modern browsers support SVG natively so you can add an SVG image to your webpage just like you would add any other image:

<img src="world.svg" alt="World Map">

However, embedding the map this way makes it difficult to style the map and make it interactive. A simple way to apply CSS and JavaScript to the map is to first embed the SVG file inline. Simply open world.svg in a text editor, copy the entire <svg> element, and paste it directly into your webpage.

The <svg> element contains a separate <path> for every country. To style the map, simply apply CSS to all <path> elements. Use the fill and stroke properties to style each country’s color and border respectively. For example, we can make all countries light gray and add a hover effect:

 path {fill: lightgray; stroke: white;}
 path:hover {fill: gray;}

Similarly, we can use JavaScript to define event handlers. The following snippet will alert each country’s name with a click:

<script>
 // <![CDATA[
  var countryElements = document.getElementById('countries').childNodes;
  var countryCount = countryElements.length;
  for (var i = 0; i < countryCount; i++) {
   countryElements[i].onclick = function() {
    alert('You clicked on ' + this.getAttribute('data-name'));
   }
  }
 // ]]>
</script> 

This should be placed after the inline <svg> element and right before the closing <body> tag. Your full HTML file should look like the example provided in this Gist29.

Open this file in a browser, and you should see an interactive map of the world.

Interactive map30

Hopefully, this simple example illustrates how you can easily manipulate your SVG map with JavaScript and CSS. For more advanced interactions, such as animating SVG paths, check out an SVG JavaScript library like Snap.js31.

Conclusion Link

Interactive maps can be intimidating, but they don’t have to be a black box. You can create your own custom SVG maps with open data and software. In no time at all, you will have enhanced your website with a beautiful, fully customizable, interactive map.

(ml, ds, og)

Footnotes Link

  1. 1 http://www.naturalearthdata.com/
  2. 2 http://www.naturalearthdata.com/downloads/
  3. 3 http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries_lakes.zip
  4. 4 http://en.wikipedia.org/wiki/Shapefile
  5. 5 http://en.wikipedia.org/wiki/Geographic_information_system
  6. 6 http://www.qgis.org/en/site/index.html
  7. 7 https://www.smashingmagazine.com/wp-content/uploads/2015/07/01-world-opt.png
  8. 8 https://www.smashingmagazine.com/wp-content/uploads/2015/07/01-world-opt.png
  9. 9 https://www.smashingmagazine.com/wp-content/uploads/2015/07/03-table-opt.png
  10. 10 https://www.smashingmagazine.com/wp-content/uploads/2015/07/03-table-opt.png
  11. 11 http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
  12. 12 https://www.smashingmagazine.com/wp-content/uploads/2015/07/04-france-opt.png
  13. 13 https://www.smashingmagazine.com/wp-content/uploads/2015/07/04-france-opt.png
  14. 14 http://en.wikipedia.org/wiki/French_Guiana
  15. 15 https://www.smashingmagazine.com/wp-content/uploads/2015/07/06-table-opt.png
  16. 16 https://www.smashingmagazine.com/wp-content/uploads/2015/07/06-table-opt.png
  17. 17 http://docs.qgis.org/testing/en/docs/user_manual/working_with_vector/editing_geometry_attributes.html
  18. 18 http://kartograph.org/about/kartograph.py/
  19. 19 http://driven-by-data.net/
  20. 20 http://kartograph.org/docs/kartograph.py/#installing-kartograph-py
  21. 21 'http://codepen.io/smashingmag/pen/gaOXNv/'
  22. 22 'http://codepen.io/smashingmag'
  23. 23 'http://codepen.io'
  24. 24 http://bost.ocks.org/mike/simplify/
  25. 25 'http://codepen.io/smashingmag/pen/LpYOob/'
  26. 26 'http://codepen.io/smashingmag'
  27. 27 'http://codepen.io'
  28. 28 http://kartograph.org/docs/kartograph.py/
  29. 29 https://gist.github.com/youderian/fbff53fe18b13116adf5
  30. 30 https://www.smashingmagazine.com/wp-content/uploads/2015/07/09-interactive-world-opt.png
  31. 31 http://snapsvg.io/

↑ Back to top Tweet itShare on Facebook

Advertisement

Chris Youderian is a web developer living in Cincinnati, Ohio. He is the founder of SimpleMaps, an interactive map library and customization tool. He loves the web and enjoys creating things with JavaScript and Python.

  1. 1

    Thanks for the article! May be that can help somebody. https://github.com/SmartTeleMax/ru-svg-map/blob/master/README.md
    Here you can find SVG maps of Russia and the world from kremlin.ru
    “This package contains JavaScript for generation of intercative SVG maps. Main features are:

    Generation of SVG according to given set of path coordinates
    Downgrading to VML for IE, common interface for styles manipulation in SVG and VML (setColor, setStroke, setOpacity)
    Support of map resizing (by buttons and by mouse wheel) and dragging
    Support of touch events: resize and drag gestures, element click emulation
    Included inner shadow style for elements
    Support of fitting to selected element
    Native browser events can be attached to SVG/VML nodes without any troubles
    The package contains:

    vector.js: universal framework-independent core, providing basic SVG manipulation methods
    map-jquery.js and map-mootools.js: two example implementations of the map based to vector.js working with two popular frameworks. They can be hacked and customized.
    path packs for maps of Russia and the world. Paths are verified by %institutename% as corresponding official recognized by Russian Federation state borders”

    0
  2. 3

    great article! thanks for sharing

    0
  3. 4

    Great article; followed it up until: “Split selected multi-part features to single part” which for the life of me doesn’t seem to be in the toolbars. Wondering if I missed a step or if there is a plug-in, or other setting missing from the article explaining how to get this icon to appear in the “Advanced Digitizing” toolbar.

    Also tried to play with some of the other tools; but no matter what, seems I cannot turn off some lines that were drawn. (Undo not available and “Cancel Selected Edits” doesn’t seem to remove the lines… perhaps a software bug?)

    My results:
    http://imgur.com/QWGbmnU

    0
    • 5

      Update:
      The Digitizing Tools plugin needs to be installed. I have updated the tutorial to reflect this. I’m very sorry for this mistake. I upgraded QGIS while writing the tutorial and mistakenly thought the plugin features had been integrated into the new version, when really the plugin was saved across installations.

      To get rid of those line edits, try exiting “Edit Mode”:
      Layer → Toggle Editing
      and then discarding changes.

      1
  4. 6

    Are there any alternatives to Kartograph.py? Trying to install the dependencies is a headache.

    0
  5. 8

    Your event handling code is pretty inefficient. It would be better as:

    var elCountries = document.getElementById(‘countries’);
    countries.addEventListener(‘click’, function (evt) {
    var countryName = evt.target.getAttribute(‘data-name’);
    if (countryName) {
    alert(‘You clicked on ‘ + countryName);
    }
    }, false);

    There’s no need to add an event listener to all 177 countries.

    1
  6. 9

    Thanks for the article!

    An important addition would be an article about how to draw on this map, e.g. if I have a location with its coordinates, how do I use JS to convert it into the same projection and draw a circle on the map to reflect this point.

    All the best,

    Michael.

    -1
    • 10

      Good suggestion! This is possible using Kartograph.js (a companion to Kartograph.py). Or, you could manually write a projection function in JavaScript and use a library like Raphael.js or Snap.js to draw on the map.

      0
  7. 11

    You might also take a look at DataMaps – https://datamaps.github.io

    It utilizes D3 and has a rich set of tools since it leverages topojson. There are numerous examples and it allows adding dots (bubbles) to the map using lat/long and has a full event model. You can create an interactive map very quickly.

    0

↑ Back to top