Skip to content

Commit 4f244a6

Browse files
authored
Merge pull request mapnik#120 from mapycz/docs
Add "Getting started" tutorial
2 parents 0f046be + 587ed40 commit 4f244a6

3 files changed

Lines changed: 242 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,7 @@ That means you likely have built python-mapnik is linked against a differ python
8181
```
8282

8383
If you still hit a problem create an issue and we'll try to help.
84+
85+
## Tutorials
86+
87+
- [Getting started with Python bindings](docs/getting-started.md)

docs/getting-started.md

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
# Getting started with Python bindings
2+
3+
## Overview
4+
5+
This tutorial will ensure that Mapnik and its Python bindings are properly installed and introduce you to some of the basic programming concepts for Mapnik.
6+
7+
## Step 1: check installation
8+
9+
Make sure you have mapnik installed. You should be able to open a terminal and type:
10+
11+
```sh
12+
mapnik-config -v # should return a version number.
13+
```
14+
15+
Next test the Python bindings. You should be able to open a terminal and type:
16+
17+
```sh
18+
python -c "import mapnik;print mapnik.__file__" # should return the path to the python bindings and no errors
19+
```
20+
21+
If the above does not work (e.g. throws an `ImportError`) then please go back and ensure Mapnik is properly installed.
22+
## Step 2
23+
24+
Now, we need some data to render. Let's use a shapefile of world border polygons from [naturalearthdata.com](http://naturalearthdata.com) ([direct link](http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip)). Unzip the archive in an easily accessible location of your choosing. In *Step 3* we will be referencing the path to this shapefile in Python code, so make sure you know where you put it.
25+
26+
Once unzipped, you should see four files like:
27+
28+
```sh
29+
ne_110m_admin_0_countries.shp
30+
ne_110m_admin_0_countries.shx
31+
ne_110m_admin_0_countries.dbf
32+
ne_110m_admin_0_countries.prj
33+
```
34+
35+
To download and unzip on the command line with the do:
36+
37+
```sh
38+
wget http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip
39+
unzip ne_110m_admin_0_countries.zip
40+
```
41+
42+
## Step 3
43+
44+
Now we're going to program in Python and Mapnik, using sample code and the Python interpreter.
45+
46+
The idea here is not that you have to interact with Mapnik via Python, but that this is a good way to build foundational skills for how Mapnik works.
47+
48+
So, let's begin! Open a Python interpreter simply by typing in your terminal:
49+
50+
```sh
51+
python
52+
```
53+
54+
The code below can be pasted into your interpreter. Ideally paste line by line so you can confirm each step is working. The commented lines (#) should be able to be pasted without trouble, but depending on your interpreter setting may cause errors.
55+
56+
### Import Mapnik
57+
58+
Import the Mapnik Python bindings:
59+
60+
```python
61+
import mapnik
62+
```
63+
64+
### Create a Map
65+
66+
```python
67+
m = mapnik.Map(600,300) # create a map with a given width and height in pixels
68+
# note: m.srs will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
69+
# the 'map.srs' is the target projection of the map and can be whatever you wish
70+
m.background = mapnik.Color('steelblue') # set background colour to 'steelblue'.
71+
```
72+
73+
### Create a Style
74+
75+
Create the Styles which determines how the data is rendered:
76+
77+
```python
78+
s = mapnik.Style() # style object to hold rules
79+
r = mapnik.Rule() # rule object to hold symbolizers
80+
# to fill a polygon we create a PolygonSymbolizer
81+
polygon_symbolizer = mapnik.PolygonSymbolizer()
82+
polygon_symbolizer.fill = mapnik.Color('#f2eff9')
83+
r.symbols.append(polygon_symbolizer) # add the symbolizer to the rule object
84+
85+
# to add outlines to a polygon we create a LineSymbolizer
86+
line_symbolizer = mapnik.LineSymbolizer()
87+
line_symbolizer.stroke = mapnik.Color('rgb(50%,50%,50%)')
88+
line_symbolizer.stroke_width = 0.1
89+
r.symbols.append(line_symbolizer) # add the symbolizer to the rule object
90+
s.rules.append(r) # now add the rule to the style and we're done
91+
```
92+
93+
And add the Style to the Map:
94+
95+
```python
96+
m.append_style('My Style',s) # Styles are given names only as they are applied to the map
97+
```
98+
99+
### Create a Datasource
100+
101+
In *Step 2* above you should have downloaded a sample shapefile of polygons of world countries. We are now going to load that into a `mapnik.Datasource` object in Python.
102+
103+
If your Python interpreter was launched from the same directory as you downloaded the natural earth shapefile to you should be able to use a relative path to create the datasource like:
104+
105+
``` python
106+
ds = mapnik.Shapefile(file='ne_110m_admin_0_countries.shp')
107+
```
108+
109+
Otherwise use an absolute path (exchanging `/Users/dane/Downloads/` for the correct path on your machine):
110+
111+
``` python
112+
ds = mapnik.Shapefile(file='/Users/dane/Downloads/ne_110m_admin_0_countries.shp')
113+
```
114+
115+
Note: optionally (to learn about your data) you can call the `envelope()` function off the datasource object to see the full coordinate bounds of the data:
116+
117+
``` python
118+
>>> ds.envelope()
119+
Box2d(-180.0,-90.0,180.0,83.64513)
120+
```
121+
122+
That shows the minx, miny, maxx, and maxy of the data. Because the above coordinates are between -180 and 180 for the x or longitude values and -90 and 90 for the y or latitude values we know this data is in *geographic* coordinates and uses degrees for units - a pretty good indication this is `WGS84 (aka EPSG:4326)`. This specific shapefile also stores this projection information as a `WKT` string in the `ne_110m_admin_0_countries.prj` file. See the `layer.srs` value below for why this matters.
123+
124+
125+
### Create a Layer
126+
127+
Mapnik Layers are basically containers around datasources, that store useful properties. Lets now create a Layer object and add the datasource to it.
128+
129+
``` python
130+
layer = mapnik.Layer('world') # new layer called 'world' (we could name it anything)
131+
# note: layer.srs will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
132+
```
133+
134+
Note: the 'layer.srs' is the source projection of the Datasource and *must* match the projection of the coordinates of that data or else your map will likely be blank. Mapnik uses [Proj.4](http://trac.osgeo.org/proj/wiki/FAQ) strings to specify the spatial references system. In this case, the default `srs` Mapnik assumes (`+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs`) happens to match the projection of the data. When this is not the case you must set the layer.srs to the correct value (which is beyond the scope of this tutorial).
135+
136+
Now attach the datasource to the layer, and reference:
137+
138+
```python
139+
layer.datasource = ds
140+
```
141+
142+
Lastly, we need to make sure the style we created above (and attached to the map) is also applied to the layer, by its string reference:
143+
144+
```python
145+
layer.styles.append('My Style')
146+
```
147+
148+
### Prepare the Map for rendering
149+
150+
This step is critical. Finally add the layer to the map and zoom to the full extent of the data layer (using `zoom_all` which will calculate the cumulative extent of all layers attached to the map). If you do not zoom the Map to the extent of the layer(s), then the rendered output will be blank.
151+
152+
```python
153+
m.layers.append(layer)
154+
m.zoom_all()
155+
```
156+
157+
### Render your map
158+
159+
Finish up by rendering your map image:
160+
161+
```python
162+
# Write the data to a png image called world.png in the current directory
163+
mapnik.render_to_file(m,'world.png', 'png')
164+
165+
# Exit the Python interpreter
166+
exit() # or ctrl-d
167+
```
168+
169+
Then back in your normal shell type:
170+
171+
```sh
172+
# On a mac
173+
open world.png
174+
# On windows
175+
start world.png
176+
```
177+
178+
Or navigate to your base directory and open `world.png` and the result should look like this:
179+
180+
![The world map](images/world.png)
181+
182+
### Step 4
183+
184+
The next logical step is to run that same code all at once as a Python script from your shell/terminal (rather than pasted into the Python interpreter line-by-line). This way you will be able to modify and experiment with the settings, then simply re-run the script.
185+
186+
So, create a blank text file called `world.py`.
187+
188+
Make it executable:
189+
190+
chmod +x world.py
191+
192+
Then add a line at the top of the script like:
193+
194+
```sh
195+
#!/usr/bin/env python
196+
```
197+
198+
Finally, append the entire text below and save the file.
199+
200+
```python
201+
import mapnik
202+
m = mapnik.Map(600,300)
203+
m.background = mapnik.Color('steelblue')
204+
s = mapnik.Style()
205+
r = mapnik.Rule()
206+
polygon_symbolizer = mapnik.PolygonSymbolizer()
207+
polygon_symbolizer.fill = mapnik.Color('#f2eff9')
208+
r.symbols.append(polygon_symbolizer)
209+
210+
line_symbolizer = mapnik.LineSymbolizer()
211+
line_symbolizer.stroke = mapnik.Color('rgb(50%,50%,50%)')
212+
line_symbolizer.stroke_width = 0.1
213+
214+
r.symbols.append(line_symbolizer)
215+
s.rules.append(r)
216+
m.append_style('My Style',s)
217+
ds = mapnik.Shapefile(file='ne_110m_admin_0_countries.shp')
218+
layer = mapnik.Layer('world')
219+
layer.datasource = ds
220+
layer.styles.append('My Style')
221+
m.layers.append(layer)
222+
m.zoom_all()
223+
mapnik.render_to_file(m,'world.png', 'png')
224+
print "rendered image to 'world.png'"
225+
```
226+
227+
* Don't forget to ensure the correct path to your `ne_110m_admin_0_countries.shp` shapefile.
228+
* Mapnik accepts both the absolute path to your data as well as the relative path (Same goes for the path to where you want to save your file)
229+
230+
Finally run the script with the command:
231+
232+
233+
```sh
234+
./world.py # You must be in the same directory as you saved the script
235+
```
236+
237+
* Note: if you re-run this script it will will re-write over the world.png map.
238+
* Now you can easily open the script in a separate text editor and try changing the dimensions, colors, or datasource (remember to use the correct `srs` if you change the datasource).

docs/images/world.png

44.7 KB
Loading

0 commit comments

Comments
 (0)