User:Moresby/Understanding Mapnik/Using filters to represent data

From OpenStreetMap Wiki
Jump to navigation Jump to search
Understanding Mapnik
A Mapnik tutorial
Starting with Python
Using XML and CSS
CartoCSS and PostGIS
050-filters.png - towns, cities, roads and motorways marked according to size

So far we have plotted all features on a map in the same way: all points are drawn the same, or all roads are drawn the same. Maps often use different styles of drawing to represent different categories of features: points marking towns can be different colours or sizes depending on population, say, or roads can be different widths depending on their importance. The data files we have been using have some very basic categorisations of the towns and roads, and here we use those labels to affect the way they are represented on the map, using Mapnik filters.

#!/usr/bin/python

# Load the Python mapnik libraries.
import mapnik

# Create a new map.
m = mapnik.Map(480, 320)

# Set the background colour.
m.background = mapnik.Color('ghostwhite')

# Create a stroke object for railways.
stroke_rail = mapnik.Stroke()
stroke_rail.color = mapnik.Color('black')
stroke_rail.dasharray = [ (6, 2) ]
stroke_rail.width = 2

# Create point and line symbolizers.
point_symbolizer_city = mapnik.PointSymbolizer(mapnik.PathExpression('circle_red_16x16.png'))
point_symbolizer_town = mapnik.PointSymbolizer(mapnik.PathExpression('circle_red_8x8.png'))
line_symbolizer_rail = mapnik.LineSymbolizer(stroke_rail)
line_symbolizer_road = mapnik.LineSymbolizer()
line_symbolizer_mainroad = mapnik.LineSymbolizer(mapnik.Color('black'), 2)
line_symbolizer_motorway = mapnik.LineSymbolizer(mapnik.Color('lightblue'), 4)

# Create new rules and add the symbolizers.
r_city = mapnik.Rule()
r_city.symbols.append(point_symbolizer_city)
r_city.filter = mapnik.Filter('[type] = "city"')

r_town = mapnik.Rule()
r_town.symbols.append(point_symbolizer_town)
r_town.filter = mapnik.Filter('[type] = "town"')

r_rail = mapnik.Rule()
r_rail.symbols.append(line_symbolizer_rail)
r_rail.filter = mapnik.Filter('[type] = "rail"')

r_road = mapnik.Rule()
r_road.symbols.append(line_symbolizer_road)
r_road.filter = mapnik.Filter('[type] = "road"')

r_mainroad = mapnik.Rule()
r_mainroad.symbols.append(line_symbolizer_mainroad)
r_mainroad.filter = mapnik.Filter('[type] = "mainroad"')

r_motorway = mapnik.Rule()
r_motorway.symbols.append(line_symbolizer_motorway)
r_motorway.filter = mapnik.Filter('[type] = "motorway"')

# Create new styles and add the rules.
s_point = mapnik.Style()
s_point.rules.append(r_town)
s_point.rules.append(r_city)

s_line = mapnik.Style()
s_line.rules.append(r_rail)
s_line.rules.append(r_road)
s_line.rules.append(r_mainroad)
s_line.rules.append(r_motorway)

# Add the styles to the map.
m.append_style('point_style', s_point)
m.append_style('line_style', s_line)

# Specify our data sources.
ds_point = mapnik.CSV(file='data-places.csv')
ds_line = mapnik.CSV(file='data-roads.csv')

# Create new layers for the map, add the data sources and styles to
#   those layers.
l_point = mapnik.Layer('point_layer')
l_point.datasource = ds_point
l_point.styles.append('point_style')
l_line = mapnik.Layer('line_layer')
l_line.datasource = ds_line
l_line.styles.append('line_style')

# Add the layers to the map. We want the points to appear in front of the
#   lines, so we add the line layer first.
m.layers.append(l_line)
m.layers.append(l_point)

# Zoom to the part of the map we are interested in.
m.zoom_to_box(mapnik.Box2d(0, 0, 480, 320))

# Save the map as a PNG image.
mapnik.render_to_file(m, '050-filters.png', 'png')

Save this program in a file called 050-filters.py and run it by typing:

python 050-filters.py

You should see no error messages, and you should see a new file in your working directory called 050-filters.png. This is a new map image, and should be a light-coloured rectangle 480 pixels wide by 320 pixels high, with towns, cities and varieties of roads separately shown, as shown above.