User:Moresby/Understanding Mapnik/Adding text to the map

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

Placing text on a map can be a complicated process. Here we look at the basics, putting labels on our places and roads.

#!/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, line and text 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)

text_symbolizer_roads = mapnik.TextSymbolizer()
text_symbolizer_roads.name = '[name]'
text_symbolizer_roads.face_name = 'DejaVu Sans Book'
text_symbolizer_roads.halo_radius = 2
text_symbolizer_roads.label_placement = mapnik.label_placement.line

text_symbolizer_towns = mapnik.TextSymbolizer()
text_symbolizer_towns.name = '[name]'
text_symbolizer_towns.face_name = 'DejaVu Sans Book'
text_symbolizer_towns.halo_radius = 3
text_symbolizer_towns.displacement = (0, 7)

text_symbolizer_cities = mapnik.TextSymbolizer()
text_symbolizer_cities.name = '[name]'
text_symbolizer_cities.face_name = 'DejaVu Sans Book'
text_symbolizer_cities.halo_radius = 3
text_symbolizer_cities.displacement = (0, 11)
text_symbolizer_cities.fill = mapnik.Color('red')
text_symbolizer_cities.text_size = 12

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

r_town = mapnik.Rule()
r_town.symbols.append(point_symbolizer_town)
r_town.symbols.append(text_symbolizer_towns)
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.symbols.append(text_symbolizer_roads)
r_road.filter = mapnik.Filter('[type] = "road"')

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

r_motorway = mapnik.Rule()
r_motorway.symbols.append(line_symbolizer_motorway)
r_motorway.symbols.append(text_symbolizer_roads)
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, '060-text.png', 'png')

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

python 060-text.py

You should see no error messages, and you should see a new file in your working directory called 060-text.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 roads labelled with text, as shown above.

References