╔══════════════════════════════════════════════════════════════╗
║ ____ _ _ _ ____ _ ║
║ / ___| _ __ __ _| |_(_) __ _| | | _ \ __ _| |_ __ _ ║
║ \___ \| '_ \ / _` | __| |/ _` | | | | | |/ _` | __/ _` | ║
║ ___) | |_) | (_| | |_| | (_| | | | |_| | (_| | || (_| | ║
║ |____/| .__/ \__,_|\__|_|\__,_|_| |____/ \__,_|\__\__,_| ║
║ |_| Analysis with Python ║
╚══════════════════════════════════════════════════════════════╝
A hands-on journey through modern geospatial computing — from coordinates to insights
| # | Module | Key Libraries | What you'll build | Difficulty |
|---|---|---|---|---|
| 01 | Basic GIS Functionalities | GeoPandas, Matplotlib, Fiona | Load shapefiles, reproject CRS, plot choropleth maps | ⭐ |
| 02 | Geocoding Addresses | GeoAdmin API, GeoPandas, Folium | Batch-geocode a CSV of Swiss addresses to coordinates | ⭐⭐ |
| 03 | Nearest Neighbor Analysis | scikit-learn, BallTree, GeoPandas | Find the closest supermarket to every apartment | ⭐⭐ |
| 04 | Catchment Area Analysis | OpenRouteService, Folium | Generate drive-time isochrones around retail stores | ⭐⭐⭐ |
| 05 | GWR Building Data | Pandas, GeoPandas, SQLAlchemy | Query & visualise Switzerland's full building register | ⭐⭐ |
| 06 | Raster Data | Rasterio, NumPy, Matplotlib | Read, clip, and analyse raster grids band by band | ⭐⭐⭐ |
| 07 | Tripadvisor NLP → Map | spaCy, Folium, WordCloud | Extract place names from reviews and map them | ⭐⭐⭐ |
| 08 | QGIS / PyQGIS | PyQGIS, GADM, QgsProject | Script a styled choropleth map with zero GUI interaction | ⭐⭐⭐⭐ |
| 09 | Flood Simulator | Leaflet.js, HTML5 Canvas, AWS Terrain Tiles | Interactive web app simulating flood levels for Swiss cities | ⭐⭐⭐ |
| 10 | Urban Activity Analysis | Streamlit, Pandas, scikit-learn, Altair | Explore Zurich mobility counts and cluster temporal activity profiles | ⭐⭐⭐⭐ |
| 11 | Geomarketing Simulator (MCI) | Streamlit, Plotly, NumPy | Simulate supermarket choice probabilities and competitive trade areas | ⭐⭐⭐⭐ |
| 12 | Graph NN Spatial Clustering | NumPy, scikit-learn, Flask | Train a GCN autoencoder and map geodemographic municipality clusters | ⭐⭐⭐⭐⭐ |
- Fork this repository
- Open it in GitHub Codespaces — the environment is fully pre-configured
Note: Module 04 requires a free OpenRouteService API token. Save it to
04_Python_CatchmentArea_Analysis/ors_token.txt.
Covers the fundamental building blocks of GIS in Python: reading/writing spatial formats (GeoJSON, Shapefile, KML), coordinate reference systems (CRS), geometry operations, and static map rendering.
You'll learn:
- Loading spatial files with
GeoPandas - Reprojecting between CRS (e.g. WGS84 ↔ Swiss LV95)
- Creating choropleth maps with
Leaflet
Geocoding converts human-readable addresses into geographic coordinates (latitude/longitude). This module uses the Swiss GeoAdmin API to batch-process address lists and visualise results on an interactive map.
You'll learn:
- Calling a GeoAdmin REST geocoding API from Python
- Handling missing/ambiguous geocoding results
- Plotting geocoded points on an interactive
Foliummap
For every apartment, find the closest supermarket — efficiently, at scale.
You'll learn:
- Measuring distances between point datasets
- Finding the nearest match for each feature
- Enriching a GeoDataFrame with the results
Uses the OpenRouteService routing engine to generate isochrones (drive/walk-time polygons) around locations. Essential for retail site selection, accessibility studies, and urban planning.
You'll learn:
- Calling the ORS Isochrones API
- Visualising overlapping catchment zones with Folium
- Comparing walking vs. driving catchments
The Gebäude- und Wohnungsregister (GWR) is a federal register of all buildings in Switzerland. This module covers loading, filtering, and visualising this large dataset to extract insights about the built environment.
You'll learn:
- Working with large tabular spatial datasets
- Translating German attribute codes (GKAT) to readable labels
- Creating statistical summaries with spatial context
| GKAT Code | Building Category |
|---|---|
| 1010 | Residential building (1–2 flats) |
| 1020 | Residential building (3+ flats) |
| 1060 | Commercial / industrial |
| 1080 | Special use |
Raster data encodes the world as a grid of cells (elevation models, satellite imagery, land-use maps). This module covers reading, clipping, band math, and visualising raster datasets.
You'll learn:
- Opening rasters with
rasterioand inspecting metadata - Clipping rasters to a vector mask
- Band arithmetic and histogram analysis
Pixel grid (DEM example):
┌───┬───┬───┬───┐
│412│389│401│445│ ← elevation values (meters)
├───┼───┼───┼───┤
│378│355│367│420│
├───┼───┼───┼───┤
│340│312│328│390│
└───┴───┴───┴───┘
Applies Named Entity Recognition (NER) to Tripadvisor review text to extract place names, then maps them using GIS tools. Combines NLP and spatial analysis to uncover location patterns hidden in unstructured text.
You'll learn:
- Running spaCy NER to extract
GPE/LOCentities - Geocoding extracted place names
- Building heatmaps and word clouds from spatial mentions
⚠️ Requires a local QGIS installation to open the generated.qgzoutput file.
Runs headless (no QGIS GUI needed) via the PyQGIS API. A single script downloads Swiss canton boundaries, enriches the features, applies a categorised colour renderer by language region, and saves a ready-to-open .qgz project file.
You'll learn:
- Running PyQGIS headless (no QGIS Desktop required to execute)
- Loading and enriching vector layers programmatically
- Applying a categorised renderer and saving a
.qgzproject
Language regions of Switzerland
────────────────────────────────
🟦 German (17 cantons)
🟥 French/Romandy ( 4 cantons)
🟩 Italian/Ticino ( 1 canton )
🟪 Bilingual DE/FR ( 3 cantons)
🟧 DE/RM/IT mix ( 1 canton )
A client-side web application that simulates rising flood levels over Swiss cities using a freely available digital elevation model (DEM). No backend or API key required.
How it works:
The app loads AWS Terrain Tiles — a free, global elevation dataset. Each tile encodes height as an RGB value:
elevation [m] = (R × 256 + G + B/256) − 32768
A custom Leaflet GridLayer decodes each tile into a Float32Array elevation cache. On every slider change, pixels where elevation ≤ river_level + flood_rise are coloured blue (depth-dependent intensity), and pixels within 0.5 m above the flood line are highlighted amber as a risk zone — all without re-fetching any tiles.
Features:
- 25 largest Swiss cities selectable via dropdown (all municipalities > ~26 000 inhabitants)
- Water rise slider: 0 – 25 m above the reference river/lake level
- Animated flood rise (▶ Animieren button)
- Depth-dependent colouring: shallow = light blue, deep = dark blue
- Risk zone (< 0.5 m above flood line) shown in amber
- ESRI World Imagery aerial photo as background
- Elevation cache per tile — slider moves are instant after first load
How to start and stop:
# cd into app folder
cd /workspaces/spatial_data_analysis/09_JS_Flood_Simulator
# Start
python -m http.server 8080
# Stop
pkill -f "http.server 8080"Then open http://localhost:8080 in your browser. In GitHub Codespaces: go to the Ports tab → port 8080 → click the globe icon.
| City reference levels used | |
|---|---|
| River / lake level | Base elevation for flood calculation |
| Slider 0 m | No flood overlay (river visible in aerial photo) |
| Slider > 0 m | Flood simulation starts |
First, make sure the upstream has been added and the origin's URL is set.
# In the VS Code Terminal type ...
git remote -v
# The output should look like (YOUR-USERNAME should be your user name on GitHub) ...
# origin git@github.com:YOUR-USERNAME/spatial_data_analysis.git (fetch)
# origin git@github.com:YOUR-USERNAME/spatial_data_analysis.git (push)
# upstream https://github.com/mario-gellrich-zhaw/spatial_data_analysis.git (fetch)
# upstream https://github.com/mario-gellrich-zhaw/spatial_data_analysis.git (push)
# If this is not set correctly, type (replace YOUR-USERNAME with your user name on GitHub) ...
git remote add upstream https://github.com/mario-gellrich-zhaw/spatial_data_analysis.git
git remote set-url origin https://github.com/YOUR-USERNAME/spatial_data_analysis.gitTo sync your fork (origin) and GitHub Codespaces environment with the upstream repository, you need to regularly pull the latest course materials. We recommend doing this before starting each week's exercises.
Before syncing — check your current status:
git statusIf you have uncommitted changes, either commit them or stash them:
# Option A: Commit your changes
git add .
git commit -m "Your commit message"
git push origin main
# Option B: Temporarily stash your changes
git stashRecommended: Merge upstream changes (preserves your work)
This is the safest approach as it preserves your local commits and modifications:
git fetch upstream
git checkout main
git merge upstream/main
git push origin mainNote: If merge conflicts occur, VS Code will help you resolve them using the Merge Editor (see "Solving merge conflicts" section below).
Advanced: Clean reset to upstream (discards local changes)
WARNING: This option will overwrite all your local changes on the main branch. Only use this if you want a completely clean copy of upstream, or your local changes are accidentally broken and you want to start fresh.
git fetch upstream
git checkout main
git reset --hard upstream/main
git push origin main --forceAlternative: Use rebase (for advanced users)
If you want a cleaner commit history without merge commits:
git fetch upstream
git checkout main
git rebase upstream/main
git push origin main --force-with-leaseBest practice: Sync at the beginning of each week to ensure you have the latest materials before starting new exercises.
Later in the course you will modify the Python code provided on GitHub. When you modify Python code, merge conflicts may occur — this is when two or more changes conflict with each other. This usually happens when multiple people are working on the same project and they try to merge their changes into a common codebase.
In VS Code, you can use the Merge Editor to solve merge conflicts.
The following video explains how this works: https://www.youtube.com/watch?v=KuB6hYoLozw
Built for the classroom · Open source · Pull requests welcome