rws_waterinfo
A Python wrapper for the Rijkswaterstaat WaterWebservices (ddapi20) API.
Simplifies downloading observation data, forecasts, tidal extremes, chemical concentrations and more from the new WADAR archive.
Documentation: https://st14n.gitlab.io/rws-waterinfo/ · PyPI: https://pypi.org/project/rws-waterinfo/
Key changes vs. the classic WaterWebservices:
- Location codes are unified (e.g.
ameland.nes,hoekvanholland) — no X/Y coordinates needed. ProcesTypedistinguishes measured data (meting), forecasts (verwachting) and astronomical tides (astronomisch). Default ismeting.- All columns from the API are returned without filtering.
- Dict-based request format gives full control over every API parameter.
What's inside / Wat zit erin
| Capability | What | Needs |
|---|---|---|
| Catalog | get_catalog(); a local, versioned CSV copy with load_catalog(), update_catalog(), catalog_info(), filter_catalog() |
base |
| Download | get_data(): list or dict requests, parallel/max_workers, columns=, progress_callback=, normen=, filepath=; failed requests in df.attrs; update_dataframe() |
base (network) |
| Regions | KRW waterlichaam and province per location (assign_regions, region_geojson), filter on them |
base, polygons bundled |
| Norms | Bkl norms bundled; RIVM and KRW-doelen (WKP) fetched on request (update_normen); assign_normen, normtoetsing, the rapportagegrens choice (half/nul/waarde) |
base; optional layers need network once |
| Observation helpers | find_duplicates(), tidal_extremes(), last_failed_requests() |
base |
| Water quality analysis | rws_waterinfo.waterkwaliteit: normtoetsing (JG-MKN/MAC-MKN), trends (Mann-Kendall, Sen's slope), PFAS/PEQ, stofgroepen, correlaties, risico, kaart (GeoJSON), bovenstroom, datakwaliteit, Excel report, charts. NOT VERIFIED - see the disclaimer |
base; charts need plotly, report needs openpyxl (both in [gui]) |
| Command line | rws-waterinfo catalogus / download / normen / waterkwaliteit |
base (.xlsx output needs openpyxl) |
| GUI | rws-waterinfo-gui: filter, map, download, charts, norms, export and a Waterkwaliteit section |
pip install "rws-waterinfo[gui]" |
| Example scripts | example.py, examples/waterkwaliteit_voorbeeld.py (offline sample included) |
in the source distribution / repository |
Install
pip install rws-waterinfo # library: pandas, numpy, requests
pip install "rws-waterinfo[gui]" # plus the optional GUI (Streamlit, Plotly)
Quick start
Snelstart. Install (above), then:
import rws_waterinfo as rw
rw.set_logger("info")
# 1. Full catalog — all locations × parameters, including ProcesTypes
catalog = rw.get_catalog()
catalog.to_csv("catalog.csv", index=False)
# 2. Measured water levels (ProcesType='meting' is the default)
# List format: [compartiment, eenheid, meetapparaat, grootheid, locatie, start, end]
# Use "" to omit optional fields.
params = [
["OW", "", "", "WATHTE", "ameland.nes", "2025-12-01", "2026-01-01"],
]
df = rw.get_data(params, return_df=True, max_workers=10)
# 3. Local CSV catalog with KRW waterlichaam and province per location
catalog = rw.load_catalog() # downloads once, then reads the CSV copy (~0.3 s)
waal = rw.filter_catalog(catalog, krw_waterlichaam="Bovenrijn, Waal", grootheid="WATHTE")
gelderland = rw.filter_catalog(catalog, provincie="Gelderland", zoekterm="debiet")
The same from the command line, and the GUI:
rws-waterinfo download --locatie ameland.nes --grootheid WATHTE --van 2025-12-01 --tot 2025-12-31 --uitvoer ameland.csv
rws-waterinfo-gui # needs pip install "rws-waterinfo[gui]"
Water quality analysis of chemistry (here: the bundled sample of the source
distribution; any get_data() result or its CSV works). Not verified by
Rijkswaterstaat: an aid, not an official assessment - see the
disclaimer.
from rws_waterinfo import waterkwaliteit as wk
analyse = wk.analyse("examples/data/chemie_voorbeeld.csv.gz") # or wk.analyse(df)
analyse.normtoetsing["samenvatting"] # Bkl JG-MKN per year, MAC-MKN per sample
analyse.trends["trends"] # Mann-Kendall + Sen's slope per location and substance
analyse.rapport("waterkwaliteit.xlsx") # every section, explanation and disclaimer (openpyxl)
More: the example scripts.
GUI
pip install "rws-waterinfo[gui]"
rws-waterinfo-gui # or: python -m rws_waterinfo.gui
rws-waterinfo-gui --catalogus D:\data\catalogus --server.port 8600
A Streamlit app on top of the library: filter locations by province,
KRW waterlichaam, compartiment, grootheid or free text, see them on a map,
choose locations, series (one per Parameter_Wat_Omschrijving) and a period,
download with a progress bar, then chart (with hourly/daily/... aggregation)
and export to CSV or Excel. It uses the CSV catalog below, no database.
With "Normen tonen en meenemen" (on by default) the chart shows the
water quality norms as horizontal lines (JG-MKN
dashed, MAC-MKN dotted, drinkwaterinname dash-dot; indicative RIVM norms
lighter, the KRW-doel of the waterlichaam as a shaded "goed" band), the
overview lists the norm values, a table compares each year with the norms,
and the export gets the Norm.* columns. Values below the reporting limit
("<") count as half the limit, zero or as reported (sidebar choice; the
table and export keep the reported values). "Normen vernieuwen (RIVM/WKP)"
downloads the optional norm layers.
After a download with chemistry (CONCTTE/MASSFTE) a Waterkwaliteit section appears, with a not-verified warning at the top: normtoetsing, trends, PFAS/PEQ, map, risk, stofgroepen, correlations (grey diagonal), upstream/downstream comparison and data quality, each with an explanation, plus an Excel report. Its settings (norm layers, indicative norms, refreshing the RIVM stofgroepen and norm layers) are in the sidebar under "Waterkwaliteit"; the reporting-limit choice is shared with the charts.
Command line
rws-waterinfo catalogus --vernieuw # download the catalog
rws-waterinfo catalogus --info
rws-waterinfo catalogus --provincie Zeeland --grootheid CONCTTE --zoek zink --normen --uitvoer zink.xlsx
rws-waterinfo download --locatie lobith.ponton eijsden --parameter Cd Zn --van 2024-01-01 --tot 2024-12-31 \
--uitvoer metalen.csv --normen --rapportagegrens half --toetsing toetsing.xlsx
rws-waterinfo download --uit-csv zink.csv --van 2024-01-01 --tot 2024-12-31 --uitvoer zink_metingen.csv \
--kolommen Code,Tijdstip,Meetwaarde.Waarde_Numeriek,Meetwaarde.Waarde_Limietsymbool
rws-waterinfo normen --parameter Cd PFOS # print the norms
rws-waterinfo normen --vernieuwen --bron rivm wkp # download the optional layers
rws-waterinfo waterkwaliteit --invoer metalen.csv --uitvoer rapport.xlsx
rws-waterinfo waterkwaliteit --locatie lobith.ponton --van 2015-01-01 --tot 2024-12-31 \
--rapportagegrens half --uitvoer rapport.xlsx
rws-waterinfo --help # Dutch help per subcommand
catalogus: update, show (--info) or export (--uitvoer .csv/.xlsx) the CSV catalog, filtered with--provincie,--krw,--locatie,--grootheid,--parameter,--compartiment,--zoek;--normenadds the norm columns (--normen-lagen bkl rivm wkpchooses the layers).download: series chosen by location(s) plus grootheid/parameter/--omschrijving(text inParameter_Wat_Omschrijving), or the rows of a CSV exported bycatalogus(--uit-csv).--rapportagegrens {half,nul,waarde}replaces values below the reporting limit (and addsOnder_rapportagegrens); without it the values stay as reported.--toetsing FILEwrites the yearly comparison with the norms. Exit code 1 when nothing was downloaded.normen: print or export the norm table,--vernieuwenthe optional layers.waterkwaliteit: the water quality analysis of a CSV/parquet (--invoer) or of a download (the same filters asdownload; without a choice of series all chemistry of the locations): prints the not-verified disclaimer, notices and a summary, and with--uitvoer x.xlsxwrites the report.--rapportagegrens,--normen-lagen,--indicatief,--hardheidsklasse;--vernieuwenfirst refreshes the norm layers and the RIVM stofgroepen.
CSV catalog and regions
load_catalog() keeps a copy of the catalog in the user's cache folder
(%LOCALAPPDATA%\rws_waterinfo\catalogus on Windows, ~/.cache/... elsewhere,
or $RWS_WATERINFO_CATALOG_DIR), as three CSV files the way the API delivers
it (locations, AquoMetadata, combinations: ~8 MB instead of ~100 MB for one
wide CSV). It is downloaded again after max_age_days (default 7); when that
fails the stored copy is used. A new download replaces the stored copy in one
step, only once it is complete; an empty catalog, or one with less than half
the stored rows, is not stored (update_catalog(force=True) stores it
anyway). Several processes or app sessions can share the folder: updates wait
for each other, and a damaged copy is downloaded again.
catalog = rw.load_catalog() # same columns as get_catalog() + regions
catalog = rw.load_catalog(refresh=True) # force a fresh download
catalog = rw.load_catalog(categorical=True) # ~20 MB in memory instead of ~500 MB
rw.catalog_info() # downloaded_at, age_days, rows, locations
Every location gets a KRW waterlichaam (the 54 KRW surface water bodies of the Rijkswateren) and a province (Kadaster, including the Waddenzee and IJsselmeer): the polygon it lies in, or the nearest one within 1 km (harbours, beach transects); stations far out at sea get none. The polygons ship with the package; only numpy is used.
| Column | Example |
|---|---|
KRW_Waterlichaam.Code / .Omschrijving / .Afstand_m |
NL93_8 / Bovenrijn, Waal / 0.0 |
Provincie.Code / .Omschrijving / .Afstand_m |
PV25 / Gelderland / 0.0 |
df = rw.assign_regions(any_dataframe_with_Lat_Lon) # e.g. get_catalog() or get_data() output
rw.region_names("krw"), rw.region_names("provincie")
rw.region_geojson("krw") # polygons for your own maps
Water quality norms
import rws_waterinfo as rw
rw.normen(parameter="Cd") # the norm table (long format)
catalog = rw.load_catalog(normen=True) # norm columns per catalog row
df = rw.get_data(params, return_df=True, normen=True)
toetsing = rw.normtoetsing(df, rapportagegrens="half") # per series and year
df_rg = rw.apply_rapportagegrens(df, "half") # values below "<" as half the limit
rw.convert_unit(0.08, "ug/l", "ng/l") # 80.0
assign_normen(df) (and normen=True on get_data, get_data_parallel
and load_catalog) adds, in the series' own unit:
| Column | Meaning |
|---|---|
Norm.JG_MKN, Norm.MAC_MKN |
legally binding annual-mean / maximum standard for the location's water type |
Norm.Biota |
for organism (OE) series, µg/kg wet weight |
Norm.Drinkwater, Norm.Drinkwater_min |
applies at drinking water intake points (_min: a lower bound such as pH 7,0) |
Norm.Indicatief_JG, Norm.Indicatief_MAC |
RIVM, policy-set or indicative (JG-MKN, else MTR; MAC) — optional layer |
Norm.KRW_goed_min, Norm.KRW_goed_max |
the "goed" class of the KRW doel of the location's waterlichaam — optional layer |
Norm.Eenheid, Norm.Watertype, Norm.Laag, Norm.Bron, Norm.Opmerking |
unit, water type, layer(s), source, notes (dissolved/total, hardness, DOC, sum parameters, how a KRW doel is assessed) |
Landoppervlaktewater (rivers, lakes) or andere oppervlaktewateren (transitional
and coastal waters) follows from the location's KRW waterlichaam. A norm is
only applied to the hoedanigheid it names (a dissolved-metal norm not to a
total-metal series). Cadmium depends on the water hardness class: without
hardheidsklasse= the strictest class is used, with a note. A norm of a sum
parameter (e.g. PFOS lineair + vertakt) is shown for its constituents, with a
note. Nothing is downloaded by assign_normen or get_data.
Layers:
- bkl (always, bundled
rws_waterinfo/data/normen.csv): the omgevings- waarden of the Besluit kwaliteit leefomgeving (BWBR0041313) bijlage III (priority substances), IIIa (specific pollutants) and V (drinking water intake), keyed by the Aquo codes RWS uses (Aquo hulplijsten). Built byscripts/build_normen.py; sources and licences inrws_waterinfo/data/NORMEN_BRONNEN.md. Government information, free to reuse. - rivm (optional): RIVM Risico's van stoffen — also policy-set and indicative norms (MTR, ...). Not bundled: RIVM allows non-commercial use with attribution ("Bron: RIVM, Risico's van stoffen"). RIVM rows that repeat a Bkl value are left out; the Bkl row notes whether RIVM agrees.
- wkp (optional): the KRW-doelen per waterlichaam from the Waterkwaliteitsportaal ("Bron: Informatiehuis Water / Waterkwaliteitsportaal") — chloride, fosfor/stikstof totaal, temperature, oxygen saturation, pH and transparency.
rw.update_normen(bronnen=("rivm", "wkp")) downloads the optional layers
into the user cache (default_normen_dir(), or $RWS_WATERINFO_NORMEN_DIR),
at most one request per second (RIVM takes a few minutes). A layer that fails
or looks implausible keeps its previous copy and raises RuntimeError.
rw.normen_info() shows what is cached. Caveat: both sources are
web applications without a documented API; when they change, the update
fails (the cached copy stays usable) until the parser is adapted.
Not included: sediment/soil norms of the Bkl, the generic drinking water
norms for PAH and plant protection products (no single Aquo parameter), and
the KRW assessment statistics (e.g. summer-half-year mean) — normtoetsing
compares yearly means and single values.
Water quality analysis (waterkwaliteit)
NOT VERIFIED - NIET GEVERIFIEERD. The results of
rws_waterinfo.waterkwaliteitare not verified or validated by Rijkswaterstaat. They are an aid, not an official assessment (no official KRW/WFD or BKMW assessment). Check them against the official sources yourself. De uitkomsten zijn niet geverifieerd of gevalideerd door Rijkswaterstaat: een hulpmiddel, geen officieel oordeel (geen officiële KRW- of BKMW-toetsing). Controleer ze zelf aan de officiële bronnen.
Installed with the package, imported only when used (import rws_waterinfo
stays light); numpy and pandas only, plotly for the charts, openpyxl for the
Excel report. A one-time UserWarning repeats the disclaimer;
wk.DISCLAIMER holds the full text (also in the report and the GUI).
import rws_waterinfo as rw
from rws_waterinfo import waterkwaliteit as wk
df = rw.get_data([{"locatie_code": "lobith.ponton", "grootheid_code": "CONCTTE",
"start_date": "2020-01-01", "end_date": "2024-12-31"}], return_df=True)
analyse = wk.analyse(df, rapportagegrens="half") # nothing computed yet
analyse.normtoetsing["samenvatting"] # per location x substance x norm
analyse.normtoetsing["niet_getoetst"] # norm for another fraction or unit
analyse.trends["trends"] # Mann-Kendall + Sen's slope (>= 5 years)
analyse.pfas["samenvatting"] # PFOA-equivalents (RIVM RPF's)
analyse.stofgroepen["overzicht"] # per substance group
analyse.correlatie("lobith.ponton") # Pearson matrix; analyse.correlatie_figuur(...) with grey diagonal
analyse.risico["prioritering"] # substances by exceedances
analyse.kaart["waterlichamen"] # GeoJSON with the exceedance rollup
analyse.bovenstroom # candidate location pairs; analyse.vergelijk(a, b)
analyse.datakwaliteit # duplicates, censoring, quality codes, completeness
analyse.meldingen # e.g. optional sources not downloaded / older than 30 days
analyse.uitleg("trends") # what a section computes (Dutch)
analyse.rapport("waterkwaliteit.xlsx")
- Input:
get_data()output, its CSV, or a parquet/CSV export of the netwerkmonitoring-tool. Only grootheid CONCTTE and MASSFTE is chemistry; placeholder values (>= 999999) and negative concentrations are skipped and counted. - Rapportagegrens (values "<"): in means and medians as half the limit (BKMW, default), 0 or the limit itself; a single value below the limit is always tested against the limit itself. Results that depend on unknown values below the limit are "niet toetsbaar" and do not count in percentages.
- Normtoetsing: the legal Bkl norms of Water quality norms
per series and location (watertype from the KRW waterlichaam): JG-MKN on the
annual mean per location, substance and calendar year, MAC-MKN per sample.
indicatief=Truealso tests against RIVM indicative norms (rivm layer). - Trends: yearly medians, Mann-Kendall test and Sen's slope per year, identical to pymannkendall (without scipy).
- PFAS/PEQ: concentration (ng/l) x RPF summed per water sample; measured
values only, so a lower bound. RPF table bundled
(
rws_waterinfo/data/pfas_rpf.csv, "Bron: RIVM"). - Stofgroepen: derived, not maintained by hand: the RIVM
Risico's van stoffen substance groups
(functional lists such as KRW prioritaire stoffen, chemical groups such as
PFAS and PAK's), linked by CAS number or name, after
wk.update_stofgroepen()(about 2 minutes, at most 1 request per second; non-commercial use, "Bron: RIVM, Risico's van stoffen"); plus fixed rules (element symbols, nutrients, keywords). On the RWS catalog's 832 CONCTTE parameters: 76% classified with the rules alone, 90% with the RIVM groups and the RIVM norm layer. - Performance: one million measurements in about 5 s for all sections (laptop), results cached per section.
Nothing is downloaded automatically; rw.update_normen() and
wk.update_stofgroepen() refresh the optional sources on request and keep
the previous copy when a download fails. Sources: measurements Rijkswaterstaat;
norms Bkl (BWBR0041313), RIVM and Informatiehuis Water / Waterkwaliteitsportaal
when used; substance groups and RPF's RIVM.
Performance and memory
- Downloads run in parallel (
max_workers, default 10); periods are split into requests of at most a year, and further when the API reports too many observations. columns=[...]keeps only the columns you need, per request, as results arrive: the biggest memory saver for large downloads.filepath=...withoutreturn_dfstreams each result to the CSV and keeps nothing in memory (the file always gets all columns;columnsonly applies to the returned DataFrame).progress_callback=lambda done, total: ...reports progress; the console progress is silenced byset_logger("warning").- A request that times out on a long period is split in two; the timeouts are
rws_waterinfo.rws_waterinfo.OBSERVATION_TIMEOUT(default(10, 60)s, connect/read) andCATALOG_TIMEOUT.
df = rw.get_data(params, return_df=True,
columns=["Code", "Tijdstip", "Meetwaarde.Waarde_Numeriek"],
progress_callback=lambda done, total: print(done, "/", total))
Failed requests
A request that fails (HTTP error, timeout, an API Foutmelding) adds no rows
and is logged. Which ones failed:
df = rw.get_data(params, return_df=True)
df.attrs["failed_requests"] # [{"locatie_code": ..., "start_date": ..., "error": ...}, ...]
rw.last_failed_requests() # the same, also after get_data(filepath=...); per thread
Request formats
List format (backwards compatible, 7 items)
params = [
[compartiment_code, eenheid_code, meetapparaat_code,
grootheid_code, locatie_code, start_date, end_date],
]
df = rw.get_data(params, return_df=True)
Dict format (recommended — full API control)
params = [
{
"locatie_code": "ameland.nes", # required
"start_date": "2025-12-01", # required
"end_date": "2026-01-01", # required
# --- optional fields (omit to leave unfiltered) ---
"compartiment_code": "OW",
"eenheid_code": "cm",
"meetapparaat_code": 127,
"grootheid_code": "WATHTE",
"proces_type": "meting", # overrides global default
"parameter_code": None, # e.g. "Cd" for cadmium
"hoedanigheid_code": None,
"typering_code": None,
"waardebewerkingsmethode_code": None,
"groepering_code": None, # e.g. "GETETBRKD2" for tidal extremes
"waardebepalingsmethode_code": None, # e.g. "other:F137" (wind gust, see below)
"biotaxon_code": None, # biology: a BioTaxon code
"kwaliteitswaardecodes": None, # e.g. ["00","10","20","25","30","40"]
"bemonsteringshoogtes": None, # e.g. ["-250"] for 2.5 m depth
"opdrachtgevende_instanties": None, # e.g. ["RIKZ_GOLVEN"]
}
]
df = rw.get_data(params, return_df=True)
Filtering on codes (
parameter_code,hoedanigheid_code,typering_code,waardebewerkingsmethode_code,groepering_code): use the exact code as shown inget_catalog(), including "not applicable" codes such as"NVT"— the RWS data model has no empty value for these fields. Leaving a field asNone(the default) just omits it from the request ("don't filter"), it does not match an empty value. Some catalog entries only differ by one of these codes (e.g. a raw"NVT"series vs. a derived"GEM24H"daily-average series for the same location/parameter) — pass the specific code to select just one.
ProcesType
ProcesType is an extra filter that distinguishes:
| Value | Meaning |
|---|---|
"meting" |
Measured observations (default) |
"verwachting" |
Model forecasts (e.g. expected water levels, 48 h ahead) |
"astronomisch" |
Astronomical tidal predictions (no weather effect) |
None |
No filter — returns all types |
Set it globally for a whole batch:
df = rw.get_data(params, return_df=True, proces_type="verwachting")
Or override it per request using the dict format:
params = [
{"locatie_code": "hoekvanholland", "compartiment_code": "OW",
"grootheid_code": "WATHTE", "start_date": "2025-12-01",
"end_date": "2025-12-08", "proces_type": "meting"},
{"locatie_code": "hoekvanholland", "compartiment_code": "OW",
"grootheid_code": "WATHTE", "start_date": "2025-12-01",
"end_date": "2025-12-08", "proces_type": "verwachting"},
]
df_both = rw.get_data(params, return_df=True)
Examples
Example scripts
example.py: catalog,get_datain both request formats, saving and updating.examples/waterkwaliteit_voorbeeld.py: the whole water quality analysis (normtoetsing and norms, trends, PFAS/PEQ, stofgroepen, correlaties, risico, kaart, bovenstroom, datakwaliteit, charts and report). Runs offline on the bundled sampleexamples/data/chemie_voorbeeld.csv.gz, or on fresh data with--download. Not verified (see the disclaimer above). Seeexamples/README.md.
Tidal extremes (Groepering / mux)
Use groepering_code to request multiplex channel groups. Do not set grootheid_code when using groepering_code. When groepering_code is set and proces_type is not explicitly provided, the wrapper automatically sets proces_type=None (because grouped observations span multiple process types and filtering on "meting" would return nothing).
params = [
{"locatie_code": "ameland.nes", "groepering_code": "GETETBRKD2",
"start_date": "2025-12-01", "end_date": "2026-01-01"},
]
df_tides = rw.get_data(params, return_df=True)
| Code | Description |
|---|---|
GETETBRKD2 |
Calculated tidal extremes (NAP) |
GETETM2 |
Measured tidal extremes (NAP) |
GETETBRKDMSL2 |
Calculated tidal extremes offshore (MSL) |
GETETMSL2 |
Measured tidal extremes offshore (MSL) |
The result holds two series per extreme: the water level and its kind
(hoogwater / laagwater, in Meetwaarde.Waarde_Alfanumeriek).
rw.tidal_extremes(df_tides) puts them side by side: one row per extreme with
Waterhoogte and Type.
Wind gusts
The grootheid WINDST no longer exists (the catalog still lists it, without
data). Gusts are WINDSHD with a WaardeBepalingsMethode:
params = [{"locatie_code": "uithuizerwad", "grootheid_code": "WINDSHD",
"waardebepalingsmethode_code": "other:F137",
"start_date": "2026-08-01", "end_date": "2026-08-03"}]
Chemical concentrations
Combine grootheid_code (e.g. CONCTTE) with parameter_code (e.g. Cd).
Set proces_type=None for chemistry — it is not applicable there.
params = [
{"locatie_code": "lobith.ponton", "compartiment_code": "OW",
"grootheid_code": "CONCTTE", "parameter_code": "Cd",
"start_date": "2023-01-01", "end_date": "2024-01-01",
"proces_type": None},
]
df_cd = rw.get_data(params, return_df=True)
Sampling depth filter
params = [
{"locatie_code": "hoekvanholland", "compartiment_code": "OW",
"grootheid_code": "SALNTT", "start_date": "2025-12-01",
"end_date": "2026-01-01", "bemonsteringshoogtes": ["-250"]}, # -2.5 m
]
Quality code filter
params = [
{"locatie_code": "ameland.nes", "compartiment_code": "OW",
"grootheid_code": "WATHTE", "start_date": "2025-12-01",
"end_date": "2026-01-01",
"kwaliteitswaardecodes": ["00", "10", "20", "25", "30", "40"]},
]
Commissioning body filter
Prevents receiving data from other organisations that also measured at the same location.
params = [
{"locatie_code": "ameland.nes", "compartiment_code": "OW",
"grootheid_code": "WATHTE", "start_date": "2025-12-01",
"end_date": "2026-01-01",
"opdrachtgevende_instanties": ["RIKZ_GOLVEN"]},
]
Save to CSV and update later
rw.get_data(params, filepath="waterlevel.csv")
# Extend the CSV to a newer date
df_updated = rw.update_dataframe("waterlevel.csv", till_date="2026-06-01")
df_updated.to_csv("waterlevel.csv", index=False)
update_dataframe asks again for each series in the file: per location,
compartiment, eenheid, meetapparaat and grootheid, and (when the file has
them) parameter, hoedanigheid, typering, WaardeBewerkingsMethode, ProcesType
and groepering. A file of e.g. several substances at one location, forecasts
or tidal extremes is extended with the same series.
Checking for duplicate measurements
dupes = rw.find_duplicates(df) # rows that occur more than once, with a same_value column
API reference
get_catalog() → DataFrame
Downloads the full catalog (all location × parameter combinations).
Includes ProcesTypes, Grootheden, Compartimenten, Eenheden, Parameters, Hoedanigheden, Typeringen, WaardeBewerkingsMethoden and more.
get_data(params, filepath=None, return_df=False, parallel=True, max_workers=10, proces_type="meting", progress_callback=None, columns=None, normen=False) → DataFrame | None
Downloads observations. See Request formats above. Failed
requests: df.attrs["failed_requests"] and last_failed_requests().
normen=True (or a list of layers) adds the norm columns.
load_catalog(path=None, max_age_days=7, refresh=False, regions=True, categorical=False, normen=False) → DataFrame
The catalog from the local CSV copy; see CSV catalog and regions.
Also update_catalog(path=None, regions=True, force=False), catalog_info(path=None),
default_catalog_dir().
filter_catalog(catalog, provincie=None, krw_waterlichaam=None, locatie=None, grootheid=None, parameter=None, compartiment=None, proces_type=None, zoekterm=None) → DataFrame
Rows matching every given filter (names or codes; a string or a list).
assign_regions(df, layers=("krw", "provincie"), lat_col="Lat", lon_col="Lon", max_distance_m=None) → DataFrame
Adds the KRW waterlichaam and/or province columns.
update_dataframe(filepath, till_date) → DataFrame
Reads an existing CSV saved by get_data(), re-fetches the same series up to till_date, and appends the new rows.
tidal_extremes(df) → DataFrame, find_duplicates(df, keys=None) → DataFrame, last_failed_requests() → list
See the examples above.
Norms
normen(parameter=None, normtype=None, watertype=None, lagen=None, path=None),
assign_normen(df, watertype=None, hardheidsklasse=None, lagen=None, normen_dir=None),
convert_unit(value, from_unit, to_unit),
rapportagegrens_waarden(values, limietsymbool, rapportagegrens="half"),
apply_rapportagegrens(df, rapportagegrens="half"),
normtoetsing(df, rapportagegrens="half", groepen=None),
update_normen(bronnen=("rivm", "wkp"), path=None, jaar=None), normen_info(path=None),
default_normen_dir(). See Water quality norms.
waterkwaliteit.analyse(data, rapportagegrens="half", normen_lagen=None, **opties) → Analyse
Lazily computed sections normtoetsing, trends, pfas, risico, stofgroepen,
correlaties, bovenstroom, datakwaliteit, kaart; correlatie(loc),
vergelijk(a, b), rapport(path), meldingen, uitleg(onderdeel), disclaimer.
Options: normen_dir, indicatief, hardheidsklasse, kwaliteitscodes,
min_jaren, waterlichamen. Also waterkwaliteit.voorbereiden(),
waterkwaliteit.update_stofgroepen() and the chart helpers in
waterkwaliteit.grafieken. See Water quality analysis.
set_logger(verbose)
Controls logging verbosity: "debug", "info", "warning", "error",
"critical", "silent" (case-insensitive) or a number. From "warning" up the
console download progress is silenced too.
Known data issues (API side)
Reported to Rijkswaterstaat on the WaterWebservices issue tracker; these are in the data the API serves, not in this library:
- Duplicate timestamps in some series (e.g. Q at
maastricht.sintpieter,venlo; WATHTE series; twoOpdrachtgevendeInstantiefor one series): #16, #22, #48, #49.find_duplicates(df)lists them; nothing is removed automatically. - Tidal extreme types (
GETETM2, ...) haveWaarde_Numeriek0.0; the value is inWaarde_Alfanumeriek: #24 (tidal_extremes(df)pairs them with the levels). Some Q series contain 0.0 values flagged as checked: #25. WINDST(wind gust) no longer exists; useWINDSHDwithwaardebepalingsmethode_code(other:F137 / F219 / F132): #44, #56 (the library logs this hint when a WINDST request returns nothing); gust codes missing since 2026-08-18: #59.- The maximum number of observations per request (HTTP 400, "Het maximaal aantal waarnemingen ... is overschreden") was 263,088 per series on 2026-10-20 (#14 mentions 160,000); the library splits such periods itself.
- The catalog's
Parameter_Wat_Omschrijvingcan differ from the one in the observations: #26, #39, #40. GroeperingandBioTaxonTypeare empty strings in the catalog, by design: #13.OphalenWaarnemingenhonoursHoedanigheid,Typering,Parameter,WaardeBewerkingsMethode,WaardeBepalingsMethode,BioTaxonandMeetApparaat(verified 2026-10-20);CheckWaarnemingenAanwezigignoresHoedanigheidandBioTaxon.
Links
- WaterWebservices documentation (Rijkswaterstaat): https://rijkswaterstaatdata.nl/waterdata/
- API reference (Swagger UI): https://ddapi20-waterwebservices.rijkswaterstaat.nl/swagger-ui/index.html
- User manual (PDF): https://rijkswaterstaatdata.nl/publish/pages/223004/distributielaagwebservices-sum-2v7-1-.pdf
- Catalog:
rw.load_catalog()orrws-waterinfo catalogus --uitvoer catalogus.csv(the Excel download of the catalog is currently not offered by Rijkswaterstaat) - Location codes, old LMW/DONAR codes to the new ones: https://wrd.rwskennisbron.nl/index.php/Id-048979a4-2037-4605-9e86-3a921f9733bb
- Community: https://github.com/Rijkswaterstaat/WaterWebservices/discussions
- Github issuetracker ddapi20: https://github.com/Rijkswaterstaat/WaterWebservices/issues
Metadata
Release files for rws-waterinfo 1.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 | Provenance | Actions |
|---|---|---|---|---|
| rws_waterinfo-1.1.1.tar.gz | 887.0 kB | Without provenance | Details for rws_waterinfo-1.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| rws_waterinfo-1.1.1-py3-none-any.whl | Python 3 | none | any | Details for rws_waterinfo-1.1.1-py3-none-any.whl |
Total release size: 1.6 MB
Release files / rws_waterinfo-1.1.1.tar.gz
| Download URL | rws_waterinfo-1.1.1.tar.gz |
|---|---|
| Size | 887.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7d315608aa8c526f5f79af86c4ef2d9701af83f817723d4f6a07edc0cf3fa16
|
|
BLAKE2b-256 checksum How to use checksums |
b0c33c4633a995f1760ff64a0728032240619b380efeddb332e2fae259539700
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.16
|
Release files / rws_waterinfo-1.1.1-py3-none-any.whl
| Download URL | rws_waterinfo-1.1.1-py3-none-any.whl |
|---|---|
| Size | 668.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4861bea4505d39dbcf30b6df7952b95613f7ae82f51c0f2be8debcf3fdc2ff9d
|
|
BLAKE2b-256 checksum How to use checksums |
66da45e0a85d931f90d39e1cd7a508e9b88609f6425d0f55b7e1fb75caee0f0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.16
|
Security for rws-waterinfo 1.1.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.