Skip to main content

License: GPL v3 Python Versions Platform Streamlit App Open In Colab

DEM-Shadows

Generate high-resolution terrain shadow rasters and animations from DEM GeoTIFFs.


Table of Contents


Overview

dem-shadows is a lightweight Python toolchain for:

  • Merging DEM tiles
  • Converting DEMs to metric projected CRS
  • Computing per-timestamp shadow rasters using the insolation package
  • Auto-detecting latitude, longitude, and timezone from DEM extent
  • Rendering animated GIFs of shadow progression
  • Rendering cumulative “shadow exposure maps"

The goal is to provide easy, reproducible, and open-source shadow modelling for any DEM.


Features

✔ Merge DEM tiles automatically
✔ Auto lat/lon from DEM center
✔ Auto timezone inference via tzfpy
✔ Robust shadow modeling (insolation sunvector + doshade)
✔ Zero-dependency GIF animation (Pillow only)
✔ Transparent or white-background output modes
✔ Cumulative exposure computation
✔ Optional Streamlit GUI
✔ Fully cross-platform (Windows / Linux / macOS)


Installation

Clone & install locally

git clone https://github.com/marcop11/dem-shadows.git
cd dem-shadows
pip install -e .

Requirements

Automatically installed:

  • rasterio
  • numpy
  • pandas
  • Pillow
  • tqdm
  • astral
  • insolation>=0.1.9
  • tzfpy

Optional:

pip install streamlit

Project Structure

dem-shadows/
│
├── app/
│   └── streamlit_app.py
│
├── examples/
│   └── dem.tif              # Example DEM for README & demos
│
├── img/
│   ├── app.png
│   ├── icon.svg
│   ├── logo.svg
│   ├── zh_example_sh.png
│   ├── zh_example_dtm.png
│   ├── zh_example_ortho.png
│   ├── zh_example_sh_cum.png
│   └── zh_example_animate.gif
│
├── notebooks/
│   └── try_it_yourself.ipynb
│
├── src/
│   └── dem_shadows/
│       ├── shadows.py       # DEM → shadows
│       ├── animate.py       # GIF generation
│       ├── analysis.py      # Cumulative shadows
│       ├── preprocess.py
│       ├── utils.py
│       ├── schedule.py
│       ├── config.py
│       └── __init__.py
│
├── tests/
│   └── test_basic.py
│
├── README.md
├── pyproject.toml
└── requirements.txt

Quick Start

1. Generate Shadows

Generate a single shadow at 11:55 on March 8th 2025 — automatically detects lat/lon + timezone:

dem-shadows-generate ^
  --dem-dir "examples" ^
  --out-dir "out" ^
  --auto-latlon ^
  --auto-timezone ^
  --start 2025-03-08 ^
  --end 2025-03-08 ^
  --only-time 11:55

Minimal example for a whole day shadow generation hourly on March 8th 2025 — automatically detects lat/lon + timezone:

dem-shadows-generate ^
  --dem-dir "examples" ^
  --out-dir "shadows_day" ^
  --auto-latlon ^
  --auto-timezone ^
  --start 2025-03-08 ^
  --end 2025-03-08

Resulting output (example):

shadows_day/
│
├── shadow_20250308T070000_EuropeZurich.tif
├── shadow_20250308T080000_EuropeZurich.tif
├── shadow_20250308T090000_EuropeZurich.tif
├── ...
└── schedule.csv

Each GeoTIFF contains:

  • 0 = shadow
  • 1 = sunlit
  • 255 = nodata


2. Animate Shadows

Create a GIF from the folder:

dem-shadows-animate ^
  --shadow-folder "shadows_day" ^
  --out-gif "shadows_day.gif"

Example GIF (included in repo):

Shadows of Zürich on 8th March 2025.


3. Cumulative Shadow Map

dem-shadows-cumulate ^
  --shadow-folder "shadows_day" ^
  --out "shadow_cumulative.tif"

This produces a raster where the value of each pixel equals:

Number of hours of sun per pixel

Example Cumulative Shadows (included in repo):

Cumulative shadows of Zürich on 8th March 2025.


CLI Reference


dem-shadows-generate

usage: dem-shadows-generate [OPTIONS]

Required

--dem PATH                # or --dem-dir PATH (automerge)
--out-dir PATH
--start YYYY-MM-DD
--end   YYYY-MM-DD

Optional

--auto-latlon
--auto-timezone
--lat FLOAT
--lon FLOAT
--timezone "Europe/Zurich"
--step-minutes 60
--only-time HH:MM
--dem-pattern "*.tif"

dem-shadows-animate

usage: dem-shadows-animate [OPTIONS]

Required

--shadow-folder PATH
--out-gif PATH

Optional

--start YYYY-MM-DD
--end YYYY-MM-DD
--hour INT
--minute INT
--duration-ms 250
--sample-stride 1
--target-width 900
--target-height 0
--scale-factor FLOAT
--no-timestamp
--font-path PATH

dem-shadows-cumulate

usage: dem-shadows-cumulate [OPTIONS]
--shadow-folder PATH
--out PATH

Python API example

You can also call the core functionality from Python:

from pathlib import Path
from datetime import date
from dem_shadows import LocationConfig, ShadowConfig, run_shadow_batch

dem_path = Path("examples/dem.tif")
out_dir = Path("out")

loc = LocationConfig(latitude=47.38, longitude=8.53, timezone="Europe/Zurich")
cfg = ShadowConfig(
    dem_path=dem_path,
    out_dir=out_dir,
    location=loc,
    start_date=date(2025, 3, 8),
    end_date=date(2025, 3, 8),
    step_minutes=60,
)

run_shadow_batch(cfg)

Examples

Example DEM

Located at:

examples/
├── dem.tif
├── dem_is.tif
└── dem_fr.tif

Example imagery and shadow screenshots

Located at:

img/
├── app.png
├── icon.svg
├── logo.svg
├── zh_example_sh.png
├── zh_example_dtm.png
├── zh_example_ortho.png
├── zh_example_sh_cum.png
└── zh_example_animate.gif

These are referenced inside this README.


Notebooks

Google Colab notebook:

Open In Colab


Testing

Run all tests:

pytest -q

The tests/ folder contains:

tests/
└── test_basic.py

test_basic.py ensures basic imports and config structures work.


Streamlit App

Try the live web interface:

Streamlit App

You can run the GUI with:

streamlit run app/streamlit_app.py

Features:

  • Upload DEM
  • Choose start/end time
  • Generate shadows
  • Preview results
  • Download outputs and GIF

Find more digital elevation or terrain models to try:


Author

Marco Pizzolato – marcop11

Date: 24.11.2025

Version: 0.1.0


License

This project is licensed under GPLv3.

License: GPL v3

Release files for dem-shadows 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dem-shadows 0.1.0
File Size Uploaded
dem_shadows-0.1.0.tar.gz 61.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for dem-shadows 0.1.0
File Interpreter ABI Platform
dem_shadows-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.2 MB

Release files / dem_shadows-0.1.0.tar.gz

Download URL dem_shadows-0.1.0.tar.gz
Size 61.2 MB
Tags Source
SHA-256 checksum
How to use checksums
0d760621a7cbdcffecd7b089ee4d09b6e1af774f3604b5dd3b9c6a869b6c6b4c
BLAKE2b-256 checksum
How to use checksums
42154efd409298563405efedaeca84ba5961582d292d2daf115241893c6e1723
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.0

Release files / dem_shadows-0.1.0-py3-none-any.whl

Download URL dem_shadows-0.1.0-py3-none-any.whl
Size 32.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5bdd2dfe105af14a37f41039d3d18e4e49d2c233887cc38a1a5ae19e6726690e
BLAKE2b-256 checksum
How to use checksums
bc2af6b41ed10c3bcb0d4063877753754eedb693010e0282ab95a9f431cdf88e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.0

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page