
Visualizing geospatial data
It's very hard, if not impossible, to understand geospatial data unless it is turned into a visual form—that is, until it is rendered as an image of some sort. Converting geospatial data into images requires a suitable toolkit. While there are several such toolkits available, we will look at one in particular: Mapnik.
Mapnik
Mapnik is a freely-available library for building mapping applications. Mapnik takes geospatial data from a PostGIS database, shapefile, or any other format supported by GDAL/OGR, and turns it into clearly-rendered, good-looking images.
There are a lot of complex issues involved in rendering images well, and Mapnik does a good job of allowing the application developer to control the rendering process. Rules control which features should appear on the map, while "symbolizers" control the visual appearance of these features.
Mapnik allows developers to create XML stylesheets that control the map-creation process. Just as with CSS stylesheets, Mapnik's stylesheets allow you complete control over the way geospatial data is rendered. Alternatively, you can create the various styles by hand.
Mapnik itself is written in C++, though bindings are included that allow access to almost all of the Mapnik functionality via Python. Because these bindings are included in the main code base rather than being added by a third-party developer, support for Python is built right into Mapnik. This makes Python eminently suited to developing Mapnik-based applications.
Mapnik is heavily used by OpenStreetMap (http://openstreetmap.org) and EveryBlock (http://everyblock.com), among others. Since the output of Mapnik is simply an image, it is easy to include Mapnik as part of a web-based application, or you can display the output directly in a window as part of a desktop-based application. Mapnik works equally well on desktop and web platforms.
Note
Note that for this book, we will be using Mapnik version 2.2. At the time of writing this, Mapnik version 3.0 has just been released, but there are no prebuilt installers available. This makes installing the newer version of Mapnik difficult, so we have continued to use Mapnik 2. If you do use Mapnik 3, your code should still work as it is fully backward-compatible with Mapnik 2.
Installing Mapnik
Mapnik runs on all major operating systems, including MS Windows, Mac OS X, and Linux. The main Mapnik web site can be found at http://mapnik.org.
Note
Unfortunately, at this time, there is no Mapnik installer for MS Windows that supports Python 3. For this reason, if you are using MS Windows, you will need to use Python 2.7 to use Mapnik. It is hoped that someone will build an installer for Mapnik that supports Python 3, but in the meantime, if you are using MS Windows, your only choice is to go back to using Python 2.
To install Mapnik onto your computer, follow these instructions:
- For MS Windows, you will need to use Python version 2.7. You can download the 32-bit Windows package for Mapnik from the Mapnik web site's download page. From there, follow the installation instructions provided.
- For Mac OS X, a binary installer that includes support for Python 3.3 is available from the Mapnik site. Simply download the
mapnik-osx-v2.2.0.dmg
file, double-click on it to open the disk image, and then run the installer. Once this has been done, follow the instructions in theREADME.txt
file to update your system so that your Python 3.3 installation can find the Mapnik binaries. - For Linux machines, you can try installing Mapnik using
pip
, the Python package manager:pip install mapnik
Note
Mapnik has recently been updated to work with
pip
, as described in the blog entry at http://mapnik.org/news/python-bindings. If this does not work, you can use your favorite package manager to install Mapnik or even try compiling Mapnik from source.
Once you have installed Mapnik, you can check that your installation is working by opening up the Python shell and typing the following:
import mapnik print(mapnik.mapnik_version())
The result should be an integer representing Mapnik's version number. For example, 200200
corresponds to Mapnik version 2.2.
If an error occurs, you may need to change your Python settings so that the Mapnik Python bindings can find the underlying Mapnik library. For example, you may need to edit your PYTHONPATH
environment variable so that Mapnik can be found.
Understanding Mapnik
When using Mapnik, the main object you are dealing with is called a Map. This diagram shows the parts of a Map object:

When creating a Map object, you tell it:
- The overall Width and Height of the map, in pixels
- The Spatial Reference to use for the map
- The Background Color to draw behind the contents of the map
You then define one or more Layers, which hold the map's contents. Each layer has:
- A Name.
- A Datasource object defining where to get the data for this layer. The data source can be a reference to a database, or it can be a shapefile or some other GDAL/OGR data source.
- A Spatial Reference to use for this layer. This can be different from the spatial reference used by the map as a whole, if appropriate.
- A list of Styles to apply to this layer. Each style is referred to by name, since the styles are actually defined elsewhere (possibly in an XML stylesheet).
Finally, you define one or more Styles, which tell Mapnik how to draw the various layers. Each Style has a name and of a list of Rules that make up the main part of the style's definition. Each Rule has:
- A minimum scale and maximum scale value (called the scale denominator). The Rule will only apply if the map's scale is within this range.
- A filter expression. The Rule will only apply to those features that match this filter expression.
- A list of Symbolizers. These define how the matching features will be drawn onto the map.
Mapnik implements a number of different types of Symbolizers, including:
- LineSymbolizer: This is used to draw a "stroke" along a line, a linear ring, or around the outside of a polygon.
- LinePatternSymbolizer: This uses the contents of an image file (specified by name) to draw the stroke along a line, a linear ring, or around the outside of a polygon.
- PolygonSymbolizer: This is used to draw the interior of a polygon.
- PolygonPatternSymbolizer: This uses the contents of an image file (again specified by name) to draw the interior of a polygon.
- PointSymbolizer: This uses the contents of an image file (specified by name) to draw a symbol at a point.
- TextSymbolizer: This draws a feature's text. The text to be drawn is taken from one of the feature's attributes, and there are numerous options to control how the text is to be drawn.
- RasterSymbolizer: This is used to draw raster data taken from any GDAL data source.
- ShieldSymbolizer: This draws a textual label and a point together. This is similar to the use of a PointSymbolizer to draw the image and a TextSymbolizer to draw the label, except that it ensures that both the text and the image are drawn together.
- BuildingSymbolizer: This uses a pseudo-3D effect to draw a polygon, to make it appear that the polygon is a three-dimensional building.
- MarkersSymbolizer: This draws blue directional arrows following the direction of polygon and line geometries. This is experimental and is intended to be used to draw one-way streets onto a street map.
When you instantiate a Symbolizer and add it to a style (either directly in code or via an XML stylesheet), you provide a number of parameters that define how the Symbolizer should work. For example, when using a PolygonSymbolizer
, you can specify the fill color, the opacity, and a "gamma" value that helps draw adjacent polygons of the same color without the boundary being shown. For example:
p = mapnik.PolygonSymbolizer(mapnik.Color(127, 127, 0)) p.fill_opacity = 0.8 p.gamma = 0.65
If the Rule that uses this Symbolizer matches one or more polygons, those polygons will be drawn using the given color, opacity, and gamma value.
Different rules can, of course, have different Symbolizers as well as different filter values. For example, you might set up rules that draw countries in different colors depending on their population.
Mapnik example code
The following example program displays a simple world map using Mapnik:
import mapnik symbolizer = mapnik.PolygonSymbolizer( mapnik.Color("darkgreen")) rule = mapnik.Rule() rule.symbols.append(symbolizer) style = mapnik.Style() style.rules.append(rule) layer = mapnik.Layer("mapLayer") layer.datasource = mapnik.Shapefile( file="TM_WORLD_BORDERS-0.3.shp") layer.styles.append("mapStyle") map = mapnik.Map(800, 400) map.background = mapnik.Color("steelblue") map.append_style("mapStyle", style) map.layers.append(layer) map.zoom_all() mapnik.render_to_file(map, "map.png", "png")
Note
This example uses the World Borders Dataset, which you can download from http://thematicmapping.org/downloads/world_borders.php
Notice that this program creates a PolygonSymbolizer
to display the country polygons, and it then attaches the symbolizer to a Mapnik Rule object. The Rule then becomes part of a Mapnik Style object. We then create a Mapnik Layer object, reading the layer's map data from a shapefile data source. Finally, a Mapnik Map object is created, the layer is attached, and the resulting map is rendered to a PNG-format image file:

Mapnik documentation
Unfortunately, Mapnik's web site makes it difficult to find the online documentation. The Mapnik wiki can be found at https://github.com/mapnik/mapnik/wiki and is an excellent source of useful information.
There is a set of Python-specific documentation for Mapnik available at http://mapnik.org/docs, though unfortunately, this documentation is rather sparse and confusing for Python programmers. Because the Python documentation is derived from the C++ documentation and concentrates on describing how the Python bindings are implemented rather than how an end user would work with Mapnik using Python, there are a lot of technical details that aren't relevant to a Python programmer, and it does not have enough Python-specific descriptions to be all that useful.
The best way to get started with Mapnik is to follow the installation instructions and then work your way through the two supplied tutorials. You can then check out the Learning Mapnik page on the Mapnik wiki (https://github.com/mapnik/mapnik/wiki/LearningMapnik)—the notes on these pages are rather brief and cryptic, but there is useful information here if you're willing to dig.
It is worth looking at the Python API documentation, despite its limitations. The main page lists the various classes available and a number of useful functions, many of which are documented. The classes themselves list the methods and properties (attributes) you can access, and even though many of these lack Python-specific documentation, you can generally guess what they do.
Note
Chapter 7, Using Python and Mapnik to Generate Maps, includes a detailed description of Mapnik; you may find this useful in lieu of any other Python-based documentation.