Python library to download DTM data from various providers.
Project description
Quick Start • Overview • What is a DTM? • Supported DTM providers • Licensing and Data Usage • Contributing
Quick Start
Install the package using pip:
pip install pydtmdl
Then, you can use it in your Python scripts:
from pydtmdl import DTMProvider
# Prepare coordinates of the center point and size (in meters).
coords = 45.285460396731374, 20.237491178279715 # Center point of the region of interest.
size = 2048 # Size of the region in meters (2048x2048 m).
# Get the best provider for the given coordinates.
best_provider = DTMProvider.get_best(coords)
print(f"Best provider: {best_provider.name()}")
# Create an instance of the provider with the given coordinates and size.
provider = best_provider(coords, size=size)
# Get the DTM data as a numpy array.
np_data = provider.image
Overview
pydtmdl is a Python library designed to provide access to Digital Terrain Models (DTMs) from various providers. It supports multiple providers, each with its own resolution and data format. The library allows users to easily retrieve DTM data for specific geographic coordinates and sizes.
Note, that some providers may require additional settings, such as API keys or selection of a specific dataset. More details can be found in the demo script and in the providers source code.
The library will retrieve all the required tiles, merge them, window them and return the result as a numpy array. If additional processing is required, such as normalization or resizing, it can be done using OpenCV or other libraries (example code is provided in the demo script).
What is a DTM?
First of all, it's important to understand what a DTM is.
There are two main types of elevation models: Digital Terrain Model (DTM) and Digital Surface Model (DSM). The DTM represents the bare earth surface without any objects like buildings or vegetation. The DSM, on the other hand, represents the earth's surface including all objects.
The library is focused on the DTM data and the DSM sources are not supported and will not be added in the future. The reason for this is that the DTM data is more suitable for terrain generation in games, as it provides a more accurate representation of the earth's surface without any objects.
Supported DTM providers
In addition to SRTM 30m, which provides global coverage, the map above highlights all countries and/or regions where higher resolution coverage is provided by one of the DTM providers.
| Provider Name | Resolution | Developer |
|---|---|---|
| 🌎 SRTM30 | 30 meters | iwatkot |
| 🌎 ArcticDEM | 2 meters | kbrandwijk |
| 🌎 REMA Antarctica | 2 meters | kbrandwijk |
| 🇺🇸 USGS | 1-90 meters | ZenJakey |
| 🏴 England | 1 meter | kbrandwijk |
| 🏴 Scotland | 0.25-1 meter | kbrandwijk |
| 🏴 Wales | 1 meter | garnwenshared |
| 🇩🇪 Hessen, Germany | 1 meter | kbrandwijk |
| 🇩🇪 Niedersachsen, Germany | 1 meter | kbrandwijk |
| 🇩🇪 Bayern, Germany | 1 meter | H4rdB4se |
| 🇩🇪 Nordrhein-Westfalen, Germany | 1 meter | kbrandwijk |
| 🇩🇪 Mecklenburg-Vorpommern, Germany | 1-25 meter | kbrandwijk |
| 🇩🇪 Baden-Württemberg, Germany | 1 meter | kbrandwijk |
| 🇩🇪 Sachsen-Anhalt, Germany | 1 meter | kbrandwijk |
| 🇩🇪 Thüringen, Germany | 1 meter | H4rdB4se |
| 🇨🇦 Canada | 1 meter | kbrandwijk |
| 🇧🇪 Flanders, Belgium | 1 meter | kbrandwijk |
| 🇫🇷 France | 1 meter | kbrandwijk |
| 🇮🇹 Italy | 10 meter | kbrandwijk |
| 🇳🇴 Norway | 1 meter | kbrandwijk |
| 🇪🇸 Spain | 5 meter | kbrandwijk |
| 🇫🇮 Finland | 2 meter | kbrandwijk |
| 🇩🇰 Denmark | 0.4 meter | kbrandwijk |
| 🇸🇪 Sweden | 1 meter | GustavPersson |
| 🇨🇭 Switzerland | 0.5-2 meter | kbrandwijk |
| 🇨🇿 Czech Republic | 5 meter | kbrandwijk |
| 🇨🇿 Czech Republic | 2 meter | VidhosticeSDK |
| 🇱🇹 Lithuania | 1 meter | Tox3 |
Licensing and Data Usage
⚠️ Important: This library provides access to DTM data from various third-party providers. PyDTMDL does not own, host, or distribute this data. Each DTM provider has its own licensing terms and usage restrictions.
It is your responsibility to:
- Check the license and terms of use for each DTM provider you use
- Ensure compliance with the provider's licensing requirements
- Verify that your use case (commercial, research, personal, etc.) is permitted
- Provide proper attribution when required by the data provider
- Respect any usage limits or restrictions imposed by the provider
The library itself is licensed under the GNU Affero General Public License v3 (AGPL-3.0), but this does not grant you any rights to the DTM data accessed through the library. The data licenses are separate and must be obtained directly from the respective providers.
By using this library, you acknowledge that you are solely responsible for ensuring compliance with all applicable data licenses and terms of use.
For information about data licensing from specific providers, please refer to their official websites and documentation.
Contributing
Contributions are welcome! If you want to add your own DTM provider, please follow this guide.
You can also contribute by reporting issues, suggesting improvements, or helping with documentation.
What a DTM provider does?
A DTM provider is a service that provides elevation data for a given location. While there's plenty of DTM providers available, only the ones that provide a free and open access to their data can be used in this library.
The base provider class, DTMProvider, handles all the heavy lifting: merging tiles, reprojecting to EPSG:4326, and extracting the region of interest. Individual DTM providers only need to implement the download_tiles() method to fetch the raw data.
The process for generating elevation data is:
- Download all DTM tiles for the desired map area (implemented by each DTM provider)
- Merge multiple tiles if necessary (handled by base class)
- Reproject to EPSG:4326 if needed (handled by base class)
- Extract the map area from the tile (handled by base class)
Provider Types
There are three main approaches to implementing a DTM provider:
- Custom implementation - Inherit from
DTMProviderdirectly for unique APIs - WCS-based - Inherit from both
WCSProviderandDTMProviderfor OGC WCS services - WMS-based - Inherit from both
WMSProviderandDTMProviderfor OGC WMS services
Example 1: Custom Provider (SRTM)
➡️ Existing providers can be found in the pydtmdl/providers/ folder.
Step 1: Define the provider metadata.
from pydtmdl.base.dtm import DTMProvider
class SRTM30Provider(DTMProvider):
"""Provider of Shuttle Radar Topography Mission (SRTM) 30m data."""
_code = "srtm30"
_name = "SRTM 30 m"
_region = "Global"
_icon = "🌎"
_resolution = 30.0
_url = "https://elevation-tiles-prod.s3.amazonaws.com/skadi/{latitude_band}/{tile_name}.hgt.gz"
Step 2 (optional): Define custom settings if your provider requires authentication or configuration.
from pydtmdl.base.dtm import DTMProviderSettings
class SwedenProviderSettings(DTMProviderSettings):
"""Settings for the Sweden provider."""
username: str = ""
password: str = ""
class SwedenProvider(DTMProvider):
_settings = SwedenProviderSettings
_instructions = "ℹ️ This provider requires username and password..."
Access settings in your code:
username = self.user_settings.username
password = self.user_settings.password
Step 3: Implement the download_tiles() method.
def download_tiles(self) -> list[str]:
"""Download SRTM tiles."""
north, south, east, west = self.get_bbox()
tiles = []
for pair in [(north, east), (south, west), (south, east), (north, west)]:
tile_parameters = self.get_tile_parameters(*pair)
tile_name = tile_parameters["tile_name"]
tile_path = os.path.join(self.hgt_directory, f"{tile_name}.hgt")
if not os.path.isfile(tile_path):
# Download and decompress tile
compressed_path = os.path.join(self.gz_directory, f"{tile_name}.hgt.gz")
if not self.download_tile(compressed_path, **tile_parameters):
raise FileNotFoundError(f"Tile {tile_name} not found.")
# ... decompress logic ...
tiles.append(tile_path)
return list(set(tiles))
Example 2: WCS Provider (England)
For WCS-based providers, inherit from both WCSProvider and DTMProvider. The base class handles coordinate transformation automatically using the transform_bbox() utility from pydtmdl/utils.py.
from pydtmdl.base.dtm import DTMProvider
from pydtmdl.base.wcs import WCSProvider
class England1MProvider(WCSProvider, DTMProvider):
"""Provider of England data."""
_code = "england1m"
_name = "England DGM1"
_region = "UK"
_icon = "🏴"
_resolution = 1.0
_extents = [(55.877, 49.851, 2.084, -7.105)]
_url = "https://environment.data.gov.uk/geoservices/datasets/.../wcs"
_wcs_version = "2.0.1"
_source_crs = "EPSG:27700" # British National Grid
_tile_size = 1000
def get_wcs_parameters(self, tile):
return {
"identifier": ["dataset_id"],
"subsets": [("E", str(tile[1]), str(tile[3])), ("N", str(tile[0]), str(tile[2]))],
"format": "tiff",
}
The WCSProvider base class automatically:
- Transforms your bbox from EPSG:4326 to
_source_crs - Tiles the area based on
_tile_size - Downloads each tile using your
get_wcs_parameters()method - Returns the list of downloaded files
Example 3: Custom API with Authentication (Sweden)
For providers with custom APIs requiring authentication:
class SwedenProvider(DTMProvider):
_settings = SwedenProviderSettings # Define custom settings
def download_tiles(self):
"""Download tiles from STAC API."""
download_urls = self.get_download_urls()
return self.download_tif_files(download_urls, self.shared_tiff_path)
def _get_auth_headers(self) -> dict[str, str]:
"""Generate auth headers from user settings."""
credentials = f"{self.user_settings.username}:{self.user_settings.password}"
encoded = base64.b64encode(credentials.encode()).decode()
return {"Authorization": f"Basic {encoded}"}
def get_download_urls(self) -> list[str]:
"""Query STAC API for tile URLs within bbox."""
bbox = self.get_bbox()
# ... API logic using self._get_auth_headers() ...
return urls
Key Helper Methods
The base DTMProvider class provides several useful methods:
get_bbox()- Returns(north, south, east, west)in EPSG:4326download_tif_files(urls, output_path)- Downloads and caches GeoTIFF filesunzip_img_from_tif(file_name, output_path)- Extracts .img or .tif from zip files_tile_directory- Temporary directory for your provider's tiles
For coordinate transformation, use the utility function from pydtmdl/utils.py:
from pydtmdl.utils import transform_bbox
bbox = self.get_bbox()
transformed_bbox = transform_bbox(bbox, "EPSG:25832")
Requirements
- Providers must be free and openly accessible
- If authentication is required, users must provide their own credentials via settings
- The
download_tiles()method must return a list of file paths to GeoTIFF files - All tiles should contain valid elevation data readable by
rasterio
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydtmdl-0.0.8.tar.gz.
File metadata
- Download URL: pydtmdl-0.0.8.tar.gz
- Upload date:
- Size: 46.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
beab3281334cbd4f2ab1614426971e4dd09ffd0bc9d0610089d003b7aab2e350
|
|
| MD5 |
4ed7ac85213b3d3d9131e2447ae44cfe
|
|
| BLAKE2b-256 |
92ea95c8088f46504e6110d858a3130327b900b4f83e215bd79020bba084f864
|
File details
Details for the file pydtmdl-0.0.8-py3-none-any.whl.
File metadata
- Download URL: pydtmdl-0.0.8-py3-none-any.whl
- Upload date:
- Size: 57.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
847560fd6f6bdc681962a991c4488bf6011766ad8b3d800771fedba1f78e52ef
|
|
| MD5 |
e287e28c608a29e893e5fe26746cf632
|
|
| BLAKE2b-256 |
3d40a599527b40c05cba0fbca0eda144af90d21c5dfd257790d402f90351db04
|