User:Moresby/Understanding Mapnik/Representing map designs in XML

From OpenStreetMap Wiki
Jump to navigation Jump to search
Understanding Mapnik
A Mapnik tutorial
Starting with Python
Using XML and CSS
CartoCSS and PostGIS
140-layers.png - towns and roads on one map

So far each map which we have generated has required its own Python program, requiring objects to be created, modified and joined together to produce the required output. An alternative approach is to use an XML file to represent our map design, and to allow Mapnik to generate the appropriate objects itself. For example, the map we generated earlier as an example of using layers to draw points and lines can be written in XML as follows:

<?xml version='1.0'?>
<Map background-color='ghostwhite'>
  <Style name='line_style'>
    <Rule>
      <LineSymbolizer/>
    </Rule>
  </Style>
  <Style name='point_style'>
    <Rule>
      <PointSymbolizer file='circle_red_16x16.png'/>
    </Rule>
  </Style>
  <Layer name='line_layer'>
    <StyleName>line_style</StyleName>
    <Datasource>
      <Parameter name='file'>data-roads.csv</Parameter>
      <Parameter name='type'>csv</Parameter>
    </Datasource>
  </Layer>
  <Layer name='point_layer'>
    <StyleName>point_style</StyleName>
    <Datasource>
      <Parameter name='file'>data-places.csv</Parameter>
      <Parameter name='type'>csv</Parameter>
    </Datasource>
  </Layer>
</Map>

We still need a program to tell Mapnik to load and process this file, but this can now be very simple:

#!/usr/bin/python

import sys
import mapnik
import re

if len(sys.argv) != 2:
    print "Usage: python generate-map.py <filename>"
    sys.exit(1)

infile = sys.argv[1]
r = re.search(r'([^/]*)\.xml$', infile)
if r:
    outfile = r.group(1) + ".png"
else:
    outfile = infile + ".png"

m = mapnik.Map(480, 320)
mapnik.load_map(m, infile)

m.zoom_to_box(mapnik.Box2d(0, 0, 480, 320))
mapnik.render_to_file(m, outfile, 'png')

Save the XML data in a file called 140-layers.xml and the Python program in a file called generate-map.py and run the following command:

python generate-map.py 140-layers.xml

You should see no error messages, and you should see a new file in your working directory called 140-layers.png. This is a new map image, and should be a light-coloured rectangle 480 pixels wide by 320 pixels high, with a series of red circles interconnected by black lines, as shown above.

A more general-purpose Python program to generate maps from XML files is Nik2img.