Alexander Dunkel, TU Dresden; Institute of Cartography
TL;DR This notebook illustrates the process for rendering of tag maps shapefiles in Mapnik. This notebook can be run with the jupyter docker for cartography (docker tag jupyterlab:mapnik
), which contains the stable Mapnik installation and Python bindings, but must be accessed through the system Python installation (/usr/bin/python3
), not the conda environment.
The source files for this notebook are available in https://gitlab.vgiscience.de/ad/tagmaps-mapnik-jupyter.
Import dependencies
import sys
import math
import fiona
import rasterio
import numpy as np
import contextily as cx
import mapclassify as mc
import libpysal as lps
from IPython import display
from contextily import Place
from typing import Tuple, Optional
from rasterio.plot import show as rioshow
from pathlib import Path
from esda.getisord import G_Local
from shapely.geometry import shape
We are using a number of helper functions from py/modules/tools.py
to classify values.
module_path = str(Path.cwd().parents[0] / "py")
if module_path not in sys.path:
sys.path.append(module_path)
from modules import tools
%load_ext autoreload
%autoreload 2
Test Mapnik bindings
!/usr/bin/python3 -c "import mapnik;print(mapnik.__file__)"
Global Parameters
Some parameters are used throughout this notebook. Adjust to your needs.
INPUT: Path = Path.cwd().parents[0] / "input" # define path to input and working directory (shapefiles, stylesheets etc.)
OUTPUT: Path = Path.cwd().parents[0] / "output" # define path to output directory (map, notebook html etc.)
TMP: Path = INPUT / "intermediate"
MAP_X: int = 2500 # x dimensions of the final map, in pixels
MAP_Y: int = 1400 # y dimensions of the final map, in pixels
for folder in [OUTPUT, TMP]:
if not folder.exists():
folder.mkdir()
input/shapefiles
, created using TagMapsallTagCluster.shp
)allLocationCluster.shp
)input/tagmap_style.xml
, containing the style information for how the data should be renderedinput/tagmap_xml.py
, using Mapnik Python bindings to process data and generate the mapThe mapnik renderer can be accessed through Python bindings, available in the system python installation. Below, we use a python script that provides specific instructions to render a map in Mapnik.
%%time
!cd {INPUT} && /usr/bin/python3 tagmap_xml.py
Load the generated image to jupyter
display.Image(f"{OUTPUT}/tagmap_style.png")
Contextily allows to plot existing basemaps in Python.
berlin = Place("Berlin", source=cx.providers.Esri.WorldImagery)
ax = berlin.plot()
It also provides options to store results as geotiff, see the docs.
filename = f"{OUTPUT}/berlin_carto.tif"
img, ext = cx.bounds2raster(
berlin.w, berlin.s, berlin.e, berlin.n,
filename, source=cx.providers.CartoDB.PositronNoLabels,
ll=True)
with rasterio.open(filename) as r:
rioshow(r)
Get the basemap for our tagmaps TUD Campus area. Also add zoom
parameter, to get a higher level of detail.
zoom = 17
bg_name = f"{INPUT}/bg/tudcampus_carto_{zoom}.tif"
if not Path(bg_name).exists():
img, ext = cx.bounds2raster(
13.71216, 51.0218707395, 13.749046, 51.0340579,
bg_name, source=cx.providers.CartoDB.PositronNoLabels,
ll=True, zoom=zoom)
Below, use mapnik-cli
to use map generation with parameters.
stylesheet = "tagmap_bg_style.xml"
output_name = "tagmap_bg_style.png"
%%time
!/usr/bin/python3 -m mapnik_cli \
--stylesheet_name {stylesheet} \
--output_name {output_name} \
--map_dimensiony_x {MAP_X} \
--map_dimensiony_y {MAP_Y} \
--input_path {INPUT} \
--output_path {OUTPUT}
display.Image(f'{OUTPUT}/{output_name}')