clms-aoi
A lightweight Python library and CLI for extracting and summarising Copernicus Land Monitoring Service (CLMS) data for any area of interest, via Sentinel Hub's Statistical API.
Point it at a boundary file, pick a product and year, and get back a pandas DataFrame, a CSV, and/or a bar chart — no hand-rolled Sentinel Hub request boilerplate required.
Status: early (
0.1.0). The Python API is the primary interface today; the CLI currently covers config/auth/AOI validation only (see CLI usage).
Who is this for?
Land use analysts, GIS practitioners, students, NGOs, and small consultancies who want quick AOI-level summaries without setting up a full geospatial processing pipeline.
Supported products
| Product | Description | Available years | Status |
|---|---|---|---|
| Dynamic Land Cover | Annual global land cover classification (tree cover, cropland, grassland, built-up, water, etc.) | 2018–2024 | Available via Python API (LandCover) |
| Forest Type (FTY) | Broadleaved vs. coniferous forest classification | 2018, 2021, 2024 | Available via Python API (ForestType) |
| Tree Cover Density (TCD) | Pan-European canopy cover as a percentage (0–100) | 2018, 2021, 2024 | In progress — fetch/visualise only, not yet exposed as a public class |
| CLC+ Backbone (LULUCF instance) | 27-class pan-European land use classification | 2018, 2021–2023 | In progress — fetch/visualise only, not yet exposed as a public class |
Grasslands is not currently implemented.
Installation
For users:
pip install clms-aoi
For devs:
- Clone the repository
- Change directory into the cloned folder
cd clms-aoi
- Create a virtual environment and activate it
python3 -m venv clms_aoi_env && source clms_aoi_env/bin/activate
- Do an editable install which means edits to the source code keep working without reinstalling
pip install -e .
- To run tests for this project
pip install pytest
and run:
pytest
Configuration
Create a YAML config file with your Sentinel Hub credentials (get these from the Copernicus Data Space Ecosystem):
sentinelhub:
client_id: "your-client-id"
client_secret: "your-client-secret"
Credentials can also be supplied via the CLMS_SH_CLIENT_ID / CLMS_SH_CLIENT_SECRET environment variables instead of (or as a fallback for) the YAML file.
Never commit a config file containing real credentials. Keep your local config out of version control (it's covered by .gitignore by default) — a config file with a placeholder/example only should be committed, if any.
CLI usage
The CLI currently covers configuration and AOI validation. Product analysis (land cover, forest type, etc.) is available through the Python API below.
# Validate a config file's structure
clms-aoi validate-config config/config.yaml
# Check Sentinel Hub credentials are valid
clms-aoi check-auth --config config/config.yaml
# Validate an AOI boundary file (.geojson or .gpkg)
clms-aoi check-aoi --aoi tests/data/test_aoi.geojson
clms-aoi check-aoi --aoi tests/data/test_aoi.gpkg
# Run with verbose (debug) logging
clms-aoi -v check-aoi --aoi tests/data/test_aoi.geojson
# Errors are reported cleanly instead of raising a traceback
clms-aoi check-aoi --aoi missing.geojson
Options
| Option | Description |
|---|---|
--verbose, -v |
Enable debug logging output. Global flag, placed before the subcommand. |
--aoi |
Path to a GeoJSON or GeoPackage file (check-aoi). Multi-feature inputs are merged into a single geometry. |
--config |
Path to the YAML config file (check-auth). Defaults to config.yaml in the current directory. |
Python API
You can call the library directly from notebooks or pipelines:
from clms_aoi import LandCover, ForestType
lc = LandCover(config_path="config.yaml")
# Single year
result = lc.analyse(aoi="boundary.geojson", year=2020)
# Multiple years
result = lc.analyse(aoi="boundary.geojson", years=[2018, 2021, 2024])
result.to_csv("landcover.csv")
result.to_chart("landcover.jpg")
# Access the underlying DataFrame directly
result.data
# Fetch and display the color-mapped map for a single year
lc.visualize(aoi="boundary.geojson", year=2020)
ForestType has the same shape:
from clms_aoi import ForestType
ft = ForestType(config_path="config.yaml")
result = ft.analyse(aoi="boundary.geojson", years=[2018, 2021, 2024])
result.to_csv("forest_type.csv").to_chart("forest_type.jpg")
Pass exactly one of year= (a single int) or years= (a list/range of ints) to analyse().
Outputs
CSV / DataFrame
result.data is a tidy pandas.DataFrame with columns for class name, pixel count, percentage of the AOI, and area in hectares. When multiple years are requested, a year column is added and all years are included in a single table. result.to_csv(path) writes that table to the path you give it.
Chart (JPG)
result.to_chart(path) renders a bar chart of area per class. When multiple years are requested, the chart groups bars by class with one bar per year so trends are visible at a glance.
Dependencies
sentinelhub— authenticated Statistical API requestsgeopandas,shapely,pyproj— AOI handling and reprojectionnumpy— raster array summarisationmatplotlib— chart and map renderingpandas— tabular outputclick— CLIrequests— Sentinel Hub OAuth token requestsPyYAML— config parsing
Limitations and known constraints
- CLI analysis commands not yet available.
land-cover/forest-type-style CLI subcommands are planned but not implemented; use the Python API in the meantime. - Only two products are fully wired up. Dynamic Land Cover and Forest Type are exposed as
LandCover/ForestType. Tree Cover Density and CLC+ Backbone exist in the codebase but aren't yet exposed as public classes. - No Grasslands product.
- No change detection. The library reports values per year but does not compute transition matrices or gain/loss statistics between years.
- No map outputs to disk.
visualize()returns/plots an image array; it does not currently save clipped raster maps to a file for you. - AOI size. Sentinel Hub has request size and pixel count limits; very large AOIs may hit them.
Quick start
Install the package and add your Sentinel Hub credentials to a config file, then run:
from clms_aoi import LandCover
lc = LandCover(config_path="config.yaml")
result = lc.analyse(aoi="./my-boundary.geojson", year=2022)
result.to_csv("./results/land-cover-2022.csv")
result.to_chart("./results/land-cover-2022.jpg")
You'll find a CSV table and a bar chart in ./results/, ready to share.
Metadata
Release files for clms-aoi 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| clms_aoi-0.1.1.tar.gz | 24.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| clms_aoi-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.5 kB
Release files / clms_aoi-0.1.1.tar.gz
| Download URL | clms_aoi-0.1.1.tar.gz |
|---|---|
| Size | 24.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4a8b412ca7728d78b258acdd597e598b51ce19cc760df16083ed6ba79dc33a6a
|
|
BLAKE2b-256 checksum How to use checksums |
3e0d9835e0e1032fe1413bfdb903041cd826ee948c37ae0bb9e8c1f6eef4428a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.
Transparency logRelease files / clms_aoi-0.1.1-py3-none-any.whl
| Download URL | clms_aoi-0.1.1-py3-none-any.whl |
|---|---|
| Size | 25.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
599a257df30c3e889f635c59060e0d751c30d25327726a4451f3fbb298e73a3e
|
|
BLAKE2b-256 checksum How to use checksums |
b115acffff8c46cb6c3b3ec2129563d20fe7b7218d34a9355f153e2e1ea2ba0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 17, 2026.
Transparency log