Docker-based system for generating high-quality topographic map exports of Stockholm as wall art. Two parallel implementations:
- Demo A: WebGL/Vector Tiles (MapLibre + Playwright) - Fast design iteration
- Demo B: Server-side Print Renderer (PostGIS + Mapnik) - Production-quality exports
- Docker & Docker Compose
- 10GB+ disk space for data
# Download and prepare data
docker-compose run --rm prep python3 /app/src/download_osm.py
docker-compose run --rm prep python3 /app/src/clip_osm.py --preset stockholm_core
docker-compose run --rm prep python3 /app/src/download_dem.py --preset stockholm_core --provider local
docker-compose run --rm prep python3 /app/src/generate_hillshade.py --preset stockholm_core
docker-compose run --rm prep python3 /app/src/extract_contours.py --preset stockholm_core
docker-compose run --rm prep /app/scripts/generate_hillshade_tiles.sh stockholm_core
docker-compose run --rm prep /app/scripts/generate_osm_tiles.sh stockholm_core
docker-compose run --rm prep /app/scripts/generate_contour_tiles.sh stockholm_core# Start Demo A stack
docker-compose --profile demoA up -d
# Export via API
curl "http://localhost:8082/render?bbox_preset=stockholm_core&theme=paper&render_mode=print&dpi=150&width_mm=420&height_mm=594" \
--output export_demo_a.png
# Or use web UI at http://localhost:3000# Start Demo B stack
docker-compose --profile demoB up -d
# Import OSM data
docker-compose --profile demoB run --rm demo-b-importer /app/import.sh stockholm_core
# Export via API
curl -X POST "http://localhost:5000/render" \
-H "Content-Type: application/json" \
-d '{
"bbox_preset": "stockholm_core",
"theme": "paper",
"render_mode": "print",
"dpi": 150,
"width_mm": 420,
"height_mm": 594,
"format": "png"
}' \
--output export_demo_b.png
# Or use web UI at http://localhost:3001- Prep Service: Downloads OSM, DEM, generates hillshade and contours
- Demo A: Vector tiles (Planetiler/Tippecanoe) → Martin tileserver → MapLibre webapp → Playwright export
- Demo B: PostGIS (osm2pgsql) → Mapnik renderer → Flask API → PNG/PDF export
/data: Persistent volume for OSM, DEM, terrain, tiles/exports: Persistent volume for exported images
stockholm_core: [17.90, 59.32, 18.08, 59.35] - Central Stockholmstockholm_wide: [17.75, 59.28, 18.25, 59.40] - Greater Stockholm area
- Contours: NEVER render elevation labels (visual rhythm only)
- Print mode: Labels OFF by default (opt-in required)
- Determinism: Demo A (visual stability), Demo B (byte-identical)
- CRS: EPSG:3857 everywhere (Web Mercator)
EU-DEM download automation requires Copernicus API access. For local development, use manual download:
- See
DEM_MANUAL_DOWNLOAD.mdfor detailed instructions - Download EU-DEM tile covering Stockholm
- Reproject to EPSG:3857 using gdalwarp
- Place file at:
/data/dem/manual/stockholm_core_eudem.tif - Run:
docker-compose run --rm prep python3 /app/src/download_dem.py --preset stockholm_core --provider local
Run smoke tests:
chmod +x scripts/*.sh
./scripts/smoke_test.shTest determinism:
./scripts/test_determinism.sh demo-b stockholm_core paper 150 420 594Diagnose issues:
./scripts/diagnose_common_failures.shSee RUNBOOK.md for detailed step-by-step instructions.