Skip to content

Getting started

1. Install

pip install ispra-idrogeo            # downloads, API, the idrogeo command
pip install "ispra-idrogeo[geo]"     # + GeoDataFrames and GeoParquet (geopandas, pyarrow)
pip install "ispra-idrogeo[warehouse]"  # + a local DuckDB copy, offline and in SQL

Python 3.12 or newer. No account and no API key: IdroGEO open data is public.

2. Download your first layer

import asyncio

from ispra_idrogeo import IdroGEO, opendata


async def main() -> None:
    async with IdroGEO() as idrogeo:
        folder = await idrogeo.fetch(opendata("frane_piff", "molise"))
        print(folder)  # ~/.cache/ispra-idrogeo/frane_piff_molise_opendata
        print(sorted(p.name for p in folder.iterdir()))
        # ['frane_piff_opendataPoint.cst', '….dbf', '….prj', '….shp', '….shx']


asyncio.run(main())

That's it: a shapefile with the 23,949 landslides mapped in Molise, one point each. Run it again and it costs one 304 Not Modified.

3. Look at it

With pip install "ispra-idrogeo[geo]" matplotlib:

from ispra_idrogeo.geo import add_labels, read

labels = await idrogeo.code_labels(["tipo_movim"])  # inside the `async with` above
landslides = add_labels(read(folder), labels)  # the folder from step 2
print(landslides.crs)  # EPSG:32632 (WGS 84 / UTM 32N)
print(landslides["tipo_movim_label"].value_counts().head(3))
# slow earth flow                   9168
# complex                           7606
# rotational/translational slide    4279

landslides.plot(column="tipo_movim_label", markersize=1, legend=True, figsize=(10, 8))
landslides.to_parquet("molise.parquet")  # GeoParquet, for DuckDB, QGIS, BigQuery…

Each point carries the landslide's IFFI id (id_frana), its type of movement (tipo_movim, nome_tipo), and the region, province, municipality and river basin district it falls in.

3b. Or from the command line

idrogeo fetch frane_piff --area molise              # prints the unpacked folder
idrogeo summary pir comuni 72006 | jq .popidp2_p    # 1.278
idrogeo municipalities --max-age-days 30 > comuni.jsonl
idrogeo municipalities --region 16 > puglia.jsonl     # only Puglia's 257
idrogeo landslides --since 2026-11-01T00:00:00Z --select '*' > changed.jsonl
idrogeo landslides --municipality 65135             # Sarno's 53 landslides
idrogeo sites --filter stato_monitoraggio=eq.1 --select uid,point
idrogeo labels tipo_movimento --lang it
idrogeo hazard 40.829 14.617                        # P4, Sarno, 12.3°

Downloads print the path they wrote, with a progress bar on stderr when it is a terminal (--progress / --no-progress to choose); everything else prints JSON, one object per line for lists (JSON Lines), ready for jq, a file or a database loader. idrogeo --help and idrogeo <command> --help list every option. An error prints one line on stderr and exits with status 1.

4. Ask the API

async with IdroGEO() as idrogeo:
    bari = await idrogeo.summary("pir", "comuni", 72006)  # ISTAT code of Bari
    print(bari["nome"], bari["pop_res021"], bari["popidp2_p"])
    # Bari 315948 1.278  → 1.3 % of residents in flood hazard P2