Waterwebservices: POST-requests versus ddlpy#
The Rijkswaterstaat WADAR Waterwebservices provide access to almost all measurement data collected by Rijkswaterstaat. Users can send HTTP POST requests to retrieve specific (meta)data from the https://ddapi20-waterwebservices.rijkswaterstaat.nl API. There are five public endpoints:
/METADATASERVICES/OphalenCatalogus/ONLINEWAARNEMINGENSERVICES/OphalenWaarnemingen/ONLINEWAARNEMINGENSERVICES/OphalenLaatsteWaarnemingen/ONLINEWAARNEMINGENSERVICES/CheckWaarnemingenAanwezig/ONLINEWAARNEMINGENSERVICES/OphalenAantalWaarnemingen
The new RWS Waterwebservices are available since 5 December 2025. They are documented on https://rijkswaterstaatdata.nl/waterdata. This page also contains a link to documentation about migrating from the old to the new Waterwebservices (“overschakel-documentatie”), which in turn contains a link to the RWS webinar Waterdata. On the Waterwebservices Github, users can post questions/discussions or report issues/bugs. Any issues with the actual (meta)data can also be reported via the RWS Servicedesk Data.
The Python toolbox ddlpy is a simple wrapper around the Waterwebservices, which simplifies the interaction with the Waterwebservices. It it useful for:
Easy filtering/subsetting of available data and stations
Retrieving data/metadata from the new RWS Waterwebservices
Automatically chunking your large data requests
Conversion to pandas and xarray datasets
Error handling: knowing why your request fails
This notebook provides some examples of POST-requests and responses, followed by the ddlpy alternatives.
POST-requests: retrieving the catalog#
The /METADATASERVICES/OphalenCatalogus endpoint provides metadata, for instance:
LocatieLijst: a list of locationsAquoMetadataLijst: a list of metadataAquoMetadataLocatieLijst: a list of location-metadata combinations
[1]:
# imports
import requests
import pandas as pd
# retrieve the catalog (takes approximately 30 seconds)
url = "https://ddapi20-waterwebservices.rijkswaterstaat.nl/METADATASERVICES/OphalenCatalogus"
req = {
"CatalogusFilter": {
"Eenheden": True,
"Grootheden": True,
"Hoedanigheden": True,
"Groeperingen": True,
"Parameters": True,
"Typeringen": True,
"ProcesTypes": True,
"Compartimenten": True
}
}
resp = requests.post(url=url, json=req)
result_cat = resp.json()
print("Available keys in the response:")
print(result_cat.keys())
Available keys in the response:
dict_keys(['Succesvol', 'AquoMetadataLijst', 'AquoMetadataLocatieLijst', 'BemonsteringshoogteLijst', 'LocatieLijst', 'OpdrachtgevendeInstantieLijst', 'ReferentievlakLijst', 'StatuswaardeLijst'])
The LocatieLijst contains information like name/coordinates/ID of all the locations for which measurements are available in the Waterwebservices.
[2]:
# get all dataframes from the response
print("LocatieLijst raw output (first few entries):")
print(result_cat["LocatieLijst"][:2], "[...]")
print()
print("LocatieLijst pandas DataFrame:")
df_LocatieLijst = pd.DataFrame(result_cat["LocatieLijst"])
# print the list of available locations
df_LocatieLijst
LocatieLijst raw output (first few entries):
[{'Code': '4epetroleumhaven', 'Lat': 51.953524, 'Lon': 4.140491, 'Coordinatenstelsel': 'ETRS89', 'Naam': '4e Petroleumhaven', 'Omschrijving': '4e Petroleumhaven', 'Locatie_MessageID': 10603}, {'Code': '7epetroleumhaven', 'Lat': 51.915615, 'Lon': 4.21277, 'Coordinatenstelsel': 'ETRS89', 'Naam': '7e Petroleumhaven', 'Omschrijving': '7e Petroleumhaven', 'Locatie_MessageID': 17056}] [...]
LocatieLijst pandas DataFrame:
[2]:
| Code | Lat | Lon | Coordinatenstelsel | Naam | Omschrijving | Locatie_MessageID | |
|---|---|---|---|---|---|---|---|
| 0 | 4epetroleumhaven | 51.953524 | 4.140491 | ETRS89 | 4e Petroleumhaven | 4e Petroleumhaven | 10603 |
| 1 | 7epetroleumhaven | 51.915615 | 4.212770 | ETRS89 | 7e Petroleumhaven | 7e Petroleumhaven | 17056 |
| 2 | a12 | 55.383333 | 3.800000 | ETRS89 | A12 | platform | 3627 |
| 3 | aadorp | 52.372600 | 6.633300 | ETRS89 | Aadorp | Aadorp | 11036 |
| 4 | aa.helmond | 51.488763 | 5.682549 | ETRS89 | Aa, Helmond | Aa, Helmond | 2303 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 2432 | zwolle | 52.523047 | 6.069995 | ETRS89 | Zwolle | Hasselterhaven, Zwarte Water | 16580 |
| 2433 | zwolle.ijssel | 52.508600 | 6.053000 | ETRS89 | Zwolle, IJssel | voorheen Katerveer | 144 |
| 2434 | zwolle.zwartewater.kanaal | 52.509831 | 6.054957 | ETRS89 | Zwolle, Zwarte Water, kanaal | voorheen Spooldersluis binnen | 1489 |
| 2435 | zwolsehoek.badstrand | 52.615386 | 5.653051 | ETRS89 | Zwolse Hoek, badstrand | Zwolse Hoek, badstrand | 10007 |
| 2436 | zwolsehoek.badstrand.2 | 52.614817 | 5.654509 | ETRS89 | Zwolse Hoek, badstrand, 2 | Zwolse Hoek, badstrand, 2 | 3857 |
2437 rows × 7 columns
The AquoMetadataLijst contains metadata for all the parameters available in the Waterwebservices. After converting the response to a pandas.DataFrame() with pd.json_normalize(), the response is a DataFrame with the following columns:
Combination of
*.Codeand*.Omschrijvingcolumns for all parameters inCatalogusFilterprovided in the POST requestParameter_Wat_Omschrijvingis a readable description of what is measured, a combination of several other “.Omschrijving” columnsAquoMetadata_MessageIDis a unique identifier of the metadata entry.
[3]:
print("AquoMetadataLijst raw output (first few entries):")
print(result_cat["AquoMetadataLijst"][:1], "[...]")
print()
print("AquoMetadataLijst pandas DataFrame:")
df_AquoMetadataLijst = pd.json_normalize(result_cat["AquoMetadataLijst"])
# print the list of available metadata
df_AquoMetadataLijst
AquoMetadataLijst raw output (first few entries):
[{'Compartiment': {'Code': 'OW', 'Omschrijving': 'Oppervlaktewater'}, 'Grootheid': {'Code': '50%_L', 'Omschrijving': '50 percentiel van de levendigheid'}, 'Eenheid': {'Code': 'cm2', 'Omschrijving': 'vierkante centimeter'}, 'Hoedanigheid': {'Code': 'NVT', 'Omschrijving': 'NVT'}, 'Parameter': {'Code': 'NVT', 'Omschrijving': 'NVT'}, 'Groepering': {'Code': 'LEVDHD5', 'Omschrijving': 'Levendigheid'}, 'Typering': {'Code': 'LEVDHD', 'Omschrijving': 'Levendigheid'}, 'Parameter_Wat_Omschrijving': 'Percentielen per etmaal Levendigheid 50 percentiel van de levendigheid in Oppervlaktewater in cm2', 'ProcesType': 'meting', 'AquoMetadata_MessageID': 569}] [...]
AquoMetadataLijst pandas DataFrame:
[3]:
| Parameter_Wat_Omschrijving | ProcesType | AquoMetadata_MessageID | Compartiment.Code | Compartiment.Omschrijving | Grootheid.Code | Grootheid.Omschrijving | Eenheid.Code | Eenheid.Omschrijving | Hoedanigheid.Code | Hoedanigheid.Omschrijving | Parameter.Code | Parameter.Omschrijving | Groepering.Code | Groepering.Omschrijving | Typering.Code | Typering.Omschrijving | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Percentielen per etmaal Levendigheid 50 percen... | meting | 569 | OW | Oppervlaktewater | 50%_L | 50 percentiel van de levendigheid | cm2 | vierkante centimeter | NVT | NVT | NVT | NVT | LEVDHD5 | Levendigheid | LEVDHD | Levendigheid |
| 1 | Percentielen per etmaal Levendigheid 70 percen... | meting | 1415 | OW | Oppervlaktewater | 70%_L | 70 percentiel van de levendigheid | cm2 | vierkante centimeter | NVT | NVT | NVT | NVT | LEVDHD5 | Levendigheid | LEVDHD | Levendigheid |
| 2 | Percentielen per etmaal Levendigheid 80 percen... | meting | 1045 | OW | Oppervlaktewater | 80%_L | 80 percentiel van de levendigheid | cm2 | vierkante centimeter | NVT | NVT | NVT | NVT | LEVDHD5 | Levendigheid | LEVDHD | Levendigheid |
| 3 | Percentielen per etmaal Levendigheid 90 percen... | meting | 1734 | OW | Oppervlaktewater | 90%_L | 90 percentiel van de levendigheid | cm2 | vierkante centimeter | NVT | NVT | NVT | NVT | LEVDHD5 | Levendigheid | LEVDHD | Levendigheid |
| 4 | Aantal Plastic deeltjes, herkomst industrie (p... | meting | 772 | OE | Organisme (biota) | AANTL | Aantal | DIMSLS | dimensieloos | NVT | NVT | OSPAR_PLAIND | Plastic deeltjes, herkomst industrie (plastic ... | OSPAR_PLAIND_VOV | Plastic deeltjes bron industrie(granulaat) onv... | NVT | NVT |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2042 | 1' scalair gemiddelde van de windsnelheid in L... | meting | 514 | LT | Lucht | WS1 | 1' scalair gemiddelde van de windsnelheid | m/s | meter per seconde | NVT | NVT | NVT | NVT | NVT | NVT | ||
| 2043 | 10' scalair genmiddelde van de windsnelheid in... | meting | 1857 | LT | Lucht | WS10 | 10' scalair genmiddelde van de windsnelheid | m/s | meter per seconde | NVT | NVT | NVT | NVT | NVT | NVT | ||
| 2044 | 10' scalair genmiddelde van de windsnelheid in... | meting | 385 | LT | Lucht | WS10 | 10' scalair genmiddelde van de windsnelheid | m/s | meter per seconde | NVT | NVT | NVT | NVT | WS10STD2 | mux van WS10 en WS10STD | NVT | NVT |
| 2045 | Doorzicht in Oppervlaktewater in dm | meting | 1988 | OW | Oppervlaktewater | ZICHT | Doorzicht | dm | decimeter | NVT | NVT | NVT | NVT | NVT | NVT | ||
| 2046 | Doorzicht in Lucht in m | meting | 124 | LT | Lucht | ZICHT | Doorzicht | m | meter | NVT | NVT | NVT | NVT | NVT | NVT |
2047 rows × 17 columns
The AquoMetadataLocatieLijst is a list of metadata-location-combinations. It contains the AquoMetadata_MessageID from AquoMetadataLijst and Locatie_MessageID from LocatieLijst.
[4]:
print("AquoMetadataLocatieLijst raw output (first few entries):")
print(result_cat["AquoMetadataLocatieLijst"][:6], "[...]")
print()
print("AquoMetadataLocatieLijst pandas DataFrame:")
df_AquoMetadataLocatieLijst = pd.DataFrame(result_cat["AquoMetadataLocatieLijst"])
# print the list of location/metadata combinations
df_AquoMetadataLocatieLijst
AquoMetadataLocatieLijst raw output (first few entries):
[{'AquoMetaData_MessageID': 1312, 'Locatie_MessageID': 16287}, {'AquoMetaData_MessageID': 1742, 'Locatie_MessageID': 11210}, {'AquoMetaData_MessageID': 1957, 'Locatie_MessageID': 12815}, {'AquoMetaData_MessageID': 889, 'Locatie_MessageID': 10578}, {'AquoMetaData_MessageID': 289, 'Locatie_MessageID': 1635}, {'AquoMetaData_MessageID': 512, 'Locatie_MessageID': 6068}] [...]
AquoMetadataLocatieLijst pandas DataFrame:
[4]:
| AquoMetaData_MessageID | Locatie_MessageID | |
|---|---|---|
| 0 | 1312 | 16287 |
| 1 | 1742 | 11210 |
| 2 | 1957 | 12815 |
| 3 | 889 | 10578 |
| 4 | 289 | 1635 |
| ... | ... | ... |
| 97528 | 625 | 16226 |
| 97529 | 1814 | 4119 |
| 97530 | 1113 | 12035 |
| 97531 | 955 | 98 |
| 97532 | 1206 | 17485 |
97533 rows × 2 columns
POST-requests: selecting locations/metadata#
When combining the information from these three lists, it is possible to retrieve for instance waterlevels for Hoek van Holland:
Get the
Locatie_MessageIDfromdf_LocatieLijstGet a list of available
AquoMetaData_MessageID(metadata) for thisLocatie_MessageID(location) fromdf_AquoMetadataLocatieLijstFilter the
df_AquoMetadataLijstbased on location, and the desired metadata (for instance water level:Grootheid.Code==WATHTE)
[5]:
# first get the station Locatie_MessageID from df_locations via the station Code
bool_station = df_LocatieLijst["Code"] == 'hoekvanholland'
locatie_messid = df_LocatieLijst.loc[bool_station]["Locatie_MessageID"].iloc[0]
# print the location ID for the selected station
locatie_messid
[5]:
np.int64(1319)
[6]:
# get the available metadata (AquoMetaData_MessageID) for this station from df_AquoMetadataLocatieLijst
bool_station_in_metadatalocation = df_AquoMetadataLocatieLijst["Locatie_MessageID"] == locatie_messid
meta_messid_for_station = df_AquoMetadataLocatieLijst.loc[bool_station_in_metadatalocation]["AquoMetaData_MessageID"]
# print the metadata ID's available for the selected station
meta_messid_for_station
[6]:
1675 1863
3143 603
3454 607
3801 388
5864 1328
...
85105 89
91500 1798
91900 569
95637 1107
97500 626
Name: AquoMetaData_MessageID, Length: 65, dtype: int64
[7]:
# from those, get the waterhoogte-related metadata (for this station)
bool_meta_for_station = df_AquoMetadataLijst["AquoMetadata_MessageID"].isin(meta_messid_for_station.values)
bool_wathte = df_AquoMetadataLijst["Grootheid.Code"] == "WATHTE"
station_wathte_data = df_AquoMetadataLijst.loc[bool_meta_for_station & bool_wathte]
# print the selection
station_wathte_data
[7]:
| Parameter_Wat_Omschrijving | ProcesType | AquoMetadata_MessageID | Compartiment.Code | Compartiment.Omschrijving | Grootheid.Code | Grootheid.Omschrijving | Eenheid.Code | Eenheid.Omschrijving | Hoedanigheid.Code | Hoedanigheid.Omschrijving | Parameter.Code | Parameter.Omschrijving | Groepering.Code | Groepering.Omschrijving | Typering.Code | Typering.Omschrijving | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2021 | Etmaalgemiddelde Waterhoogte in Oppervlaktewat... | meting | 1376 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | centimeter | NAP | t.o.v. Normaal Amsterdams Peil | NVT | NVT | NVT | NVT | ||
| 2025 | Waterhoogte verwachting in Oppervlaktewater t.... | verwachting | 830 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | centimeter | NAP | t.o.v. Normaal Amsterdams Peil | NVT | NVT | NVT | NVT | ||
| 2026 | Etmaalgemiddelde Waterhoogte in Oppervlaktewat... | meting | 1801 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | centimeter | NAP | t.o.v. Normaal Amsterdams Peil | NVT | NVT | GETETM2 | Getijextremen | NVT | NVT |
| 2029 | Waterhoogte astronomisch in Oppervlaktewater t... | astronomisch | 528 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | centimeter | NAP | t.o.v. Normaal Amsterdams Peil | NVT | NVT | GETETBRKD2 | Getijextreem berekend | NVT | NVT |
| 2030 | Waterhoogte astronomisch in Oppervlaktewater t... | astronomisch | 1355 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | centimeter | NAP | t.o.v. Normaal Amsterdams Peil | NVT | NVT | NVT | NVT |
POST-requests: retrieving measurements#
Finally, we can retrieve the measurements for a desired period with the /ONLINEWAARNEMINGENSERVICES/OphalenWaarnemingen endpoint. Depending on the input provided via “AquoMetadata”, “Locatie” and “Periode” there is a certain amount of data returned. There is a maximum of 160000 waarnemingen returned per request.
[8]:
# retrieve the measurements
url = "https://ddapi20-waterwebservices.rijkswaterstaat.nl/ONLINEWAARNEMINGENSERVICES/OphalenWaarnemingen"
req = {
"AquoPlusWaarnemingMetadata": {
"AquoMetadata": {
"ProcesType": "meting", # meting/astronomisch/verwachting
"Grootheid": {"Code": "WATHTE"},
"Hoedanigheid": {"Code": "NAP"},
"Groepering": {"Code": ""}, # ""/GETETBRKD2/GETETM2
# "Compartiment": {"Code": "OW"},
# "Eenheid": {"Code": "cm"},
# "Parameter": {"Code": "NVT"},
# "BioTaxon": {"Code": "NVT"},
# "Orgaan": {"Code": "NVT"},
# "Typering": {"Code": "NVT"},
# "WaardeBewerkingsMethode": {"Code": "NVT"},
}
},
"Locatie": {"Code": "hoekvanholland"},
"Periode": {"Begindatumtijd": "2023-01-01T00:00:00.000+00:00", "Einddatumtijd": "2023-01-15T00:00:00.000+00:00"}
}
resp = requests.post(url=url, json=req)
if not resp.ok:
raise Exception(f"{resp.status_code} {resp.reason}: {resp.text}")
result_meas = resp.json()
print("Available keys in the response:")
print(result_meas["WaarnemingenLijst"][0].keys())
print()
print("MetingenLijst raw (first few entries):")
print(result_meas["WaarnemingenLijst"][0]["MetingenLijst"][:2], "[...]")
print()
print("MetingenLijst:")
# print the metingenlijst
pd.json_normalize(result_meas["WaarnemingenLijst"][0]["MetingenLijst"])
Available keys in the response:
dict_keys(['AquoMetadata', 'Locatie', 'MetingenLijst'])
MetingenLijst raw (first few entries):
[{'Meetwaarde': {'Waarde_Alfanumeriek': '63', 'Waarde_Numeriek': 63.0}, 'Tijdstip': '2023-01-01T01:00:00.000+01:00', 'WaarnemingMetadata': {'Statuswaarde': 'Gecontroleerd', 'Bemonsteringshoogte': '-999999999', 'Referentievlak': 'NVT', 'OpdrachtgevendeInstantie': 'RIKZMON_WAT', 'Kwaliteitswaardecode': '00'}}, {'Meetwaarde': {'Waarde_Alfanumeriek': '56', 'Waarde_Numeriek': 56.0}, 'Tijdstip': '2023-01-01T01:10:00.000+01:00', 'WaarnemingMetadata': {'Statuswaarde': 'Gecontroleerd', 'Bemonsteringshoogte': '-999999999', 'Referentievlak': 'NVT', 'OpdrachtgevendeInstantie': 'RIKZMON_WAT', 'Kwaliteitswaardecode': '00'}}] [...]
MetingenLijst:
[8]:
| Tijdstip | Meetwaarde.Waarde_Alfanumeriek | Meetwaarde.Waarde_Numeriek | WaarnemingMetadata.Statuswaarde | WaarnemingMetadata.Bemonsteringshoogte | WaarnemingMetadata.Referentievlak | WaarnemingMetadata.OpdrachtgevendeInstantie | WaarnemingMetadata.Kwaliteitswaardecode | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2023-01-01T01:00:00.000+01:00 | 63 | 63.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 1 | 2023-01-01T01:10:00.000+01:00 | 56 | 56.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 2 | 2023-01-01T01:20:00.000+01:00 | 51 | 51.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 3 | 2023-01-01T01:30:00.000+01:00 | 46 | 46.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 4 | 2023-01-01T01:40:00.000+01:00 | 40 | 40.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2012 | 2023-01-15T00:20:00.000+01:00 | 15 | 15.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 2013 | 2023-01-15T00:30:00.000+01:00 | 13 | 13.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 2014 | 2023-01-15T00:40:00.000+01:00 | 10 | 10.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 2015 | 2023-01-15T00:50:00.000+01:00 | 8 | 8.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
| 2016 | 2023-01-15T01:00:00.000+01:00 | 6 | 6.0 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 |
2017 rows × 8 columns
ddlpy: a wrapper around the RWS Waterwebservices#
The POST-requests to Waterwebservices work very well, but require quite some database knowledge for the user. The Python toolbox ddlpy simplifies the interaction with the WADAR Waterwebservices. When using ddlpy, the subsetting and retrieval of data becomes much less complex:
all (meta)data automatically converted to
pandas.DataFrameddlpy.locations()is a combination of all available locations and measurements, so this is the only DataFrame required for subsettingddlpy.measurements()takes one row ofddlpy.locations()DataFrame,start_dateandend_dateautomatic chunking of requests (per year/month/day) makes it possible to retrieve longer timeseries at once
proper handling of potential errors returned by the server
[9]:
# imports
import ddlpy
import pandas as pd
# enabling debug logging so we can see what happens in the background
import logging
logging.basicConfig()
logging.getLogger("ddlpy").setLevel(logging.DEBUG)
ddlpy: retrieving the catalog#
[10]:
# get the dataframe with locations and their available parameters
# this operation is cached, but also takes 30 seconds the first time
locations = ddlpy.locations()
locations
INFO:ddlpy.ddlpy:Loading Waterwebservices catalog from cache
[10]:
| Locatie_MessageID | Lat | Lon | Coordinatenstelsel | Naam | Omschrijving | Parameter_Wat_Omschrijving | ProcesType | Compartiment.Code | Compartiment.Omschrijving | ... | BioTaxon.Code | BioTaxon.Omschrijving | Orgaan.Code | Orgaan.Omschrijving | Groepering.Code | Groepering.Omschrijving | Typering.Code | Typering.Omschrijving | WaardeBewerkingsMethode.Code | WaardeBewerkingsMethode.Omschrijving | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Code | |||||||||||||||||||||
| 4epetroleumhaven | 10603 | 51.953524 | 4.140491 | ETRS89 | 4e Petroleumhaven | 4e Petroleumhaven | (massa)Concentratie totaal organisch koolstof ... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| poeldonk.dungensebrug | 9402 | 51.680673 | 5.368564 | ETRS89 | Poeldonk, Dungense Brug | Poeldonk, Dungense Brug | (massa)Concentratie ibuprofen in Oppervlaktewa... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hagestein.boven | 13806 | 51.989500 | 5.135200 | ETRS89 | Hagestein, boven | Hagestein, boven | Debiet verwachting in Oppervlaktewater in m3/s | verwachting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| 4epetroleumhaven | 10603 | 51.953524 | 4.140491 | ETRS89 | 4e Petroleumhaven | 4e Petroleumhaven | (massa)Concentratie Onopgeloste stoffen in Opp... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| boomkensdiep | 18648 | 53.378964 | 5.167224 | ETRS89 | Boomkensdiep | Boomkensdiep | (massa)Concentratie perfluorbutaanzuur in Oppe... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| eemmeerdijk.km23 | 16222 | 52.278751 | 5.355114 | ETRS89 | Eemmeerdijk, kilometer 23 | Eemmeerdijk, kilometer 23 | Massafractie 2,5-dichloornitrobenzeen in Bodem... | meting | BS | Bodem/Sediment | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| dreischor | 14049 | 51.714620 | 3.999330 | ETRS89 | Dreischor | Dreischor | Massafractie 2,2',3,4,4',5',6-heptabroomdifeny... | meting | BS | Bodem/Sediment | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| kuilvanmarken | 4482 | 52.478941 | 5.270994 | ETRS89 | Kuil van Marken | Kuil van Marken | (massa)Concentratie ammonium in Oppervlaktewat... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| eijsden | 15467 | 50.779500 | 5.698700 | ETRS89 | Eijsden | Eijsden | (massa)Concentratie captan in Oppervlaktewater... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| huibertgat.oost | 3377 | 53.559133 | 6.661199 | ETRS89 | Huibertgat, oost | Huibertgat, oost | (massa)Concentratie dimethoxymethaan in Opperv... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT |
99660 rows × 28 columns
ddlpy: selecting locations/metadata#
Since locations already is a combination of all locations/metadata, this is the only DataFrame that is required for subsetting.
[11]:
# Filter all measurements for a single station
bool_stations = locations.index.isin(["hoekvanholland"])
selected = locations.loc[bool_stations]
# print the selection
selected
[11]:
| Locatie_MessageID | Lat | Lon | Coordinatenstelsel | Naam | Omschrijving | Parameter_Wat_Omschrijving | ProcesType | Compartiment.Code | Compartiment.Omschrijving | ... | BioTaxon.Code | BioTaxon.Omschrijving | Orgaan.Code | Orgaan.Omschrijving | Groepering.Code | Groepering.Omschrijving | Typering.Code | Typering.Omschrijving | WaardeBewerkingsMethode.Code | WaardeBewerkingsMethode.Omschrijving | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Code | |||||||||||||||||||||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | Versie | meting | NT | Niet van toepassing | ... | NVT | NVT | NVT | NVT | SLOTGMDDE | Slotgemiddelden | NVT | NVT | NVT | NVT |
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | (massa)Concentratie lood in Oppervlaktewater o... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | (massa)Concentratie som orthofosfaat en hydrol... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | Windrichting in Lucht t.o.v. ware Noorden in g... | meting | LT | Lucht | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | Waterhoogte astronomisch in Oppervlaktewater t... | astronomisch | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | GETETBRKD2 | Getijextreem berekend | NVT | NVT | NVT | NVT |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | (massa)Concentratie lood in Oppervlaktewater i... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | Hoogwater dag in Oppervlaktewater t.o.v. Norma... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | (massa)Concentratie zuurstof in Oppervlaktewat... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | (massa)Concentratie ammonium in Oppervlaktewat... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT | ||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | Slotgemiddelde laagwater in Oppervlaktewater B... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | SLOTGMDDE | Slotgemiddelden | NVT | NVT | NVT | NVT |
66 rows × 28 columns
[12]:
# Filter the locations dataframe with the desired parameters and stations.
bool_stations = locations.index.isin(["hoekvanholland"])
bool_procestype = locations["ProcesType"].isin(["meting"]) # meting/astronomisch/verwachting
bool_grootheid = locations["Grootheid.Code"].isin(["WATHTE"]) # waterhoogte
bool_hoedanigheid = locations["Hoedanigheid.Code"].isin(["NAP"]) #vertical reference (NAP/MSL)
bool_groepering = locations["Groepering.Code"].isin([""]) # timeseries versus extremes: ""/GETETBRKD2/GETETM2
selected = locations.loc[
bool_stations
& bool_procestype
& bool_grootheid
& bool_hoedanigheid
& bool_groepering
]
# print the selection
selected
[12]:
| Locatie_MessageID | Lat | Lon | Coordinatenstelsel | Naam | Omschrijving | Parameter_Wat_Omschrijving | ProcesType | Compartiment.Code | Compartiment.Omschrijving | ... | BioTaxon.Code | BioTaxon.Omschrijving | Orgaan.Code | Orgaan.Omschrijving | Groepering.Code | Groepering.Omschrijving | Typering.Code | Typering.Omschrijving | WaardeBewerkingsMethode.Code | WaardeBewerkingsMethode.Omschrijving | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Code | |||||||||||||||||||||
| hoekvanholland | 1319 | 51.976899 | 4.119827 | ETRS89 | Hoek van Holland | rechter oever kilometer 1030.1 | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | OW | Oppervlaktewater | ... | NVT | NVT | NVT | NVT | NVT | NVT | NVT | NVT |
1 rows × 28 columns
ddlpy: retrieving measurements#
A single line of the locations (or selected) row can be passed to ddlpy.measurements(), together with a start_date/end_date, to retrieve the selected measurements.
[13]:
# provide a single row of the locations dataframe to ddlpy.measurements
start_date = "2023-01-01"
end_date = "2023-01-15"
measurements = ddlpy.measurements(selected.iloc[0], start_date=start_date, end_date=end_date)
# print the retrieved measurements
measurements
0%| | 0/1 [00:00<?, ?it/s]DEBUG:ddlpy.ddlpy:Requesting at https://ddapi20-waterwebservices.rijkswaterstaat.nl/ONLINEWAARNEMINGENSERVICES/OphalenWaarnemingen with request: {"AquoPlusWaarnemingMetadata": {"AquoMetadata": {"Compartiment": {"Code": "OW"}, "Grootheid": {"Code": "WATHTE"}, "Eenheid": {"Code": "cm"}, "Hoedanigheid": {"Code": "NAP"}, "Parameter": {"Code": "NVT"}, "BioTaxon": {"Code": "NVT"}, "Orgaan": {"Code": "NVT"}, "Groepering": {"Code": ""}, "Typering": {"Code": "NVT"}, "WaardeBewerkingsMethode": {"Code": "NVT"}, "ProcesType": "meting"}}, "Locatie": {"Code": "hoekvanholland"}, "Periode": {"Begindatumtijd": "2023-01-01T00:00:00.000+00:00", "Einddatumtijd": "2023-01-15T00:00:00.000+00:00"}}
100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 2.67it/s]
DEBUG:ddlpy.ddlpy:0 duplicated values dropped
[13]:
| WaarnemingMetadata.Statuswaarde | WaarnemingMetadata.Bemonsteringshoogte | WaarnemingMetadata.Referentievlak | WaarnemingMetadata.OpdrachtgevendeInstantie | WaarnemingMetadata.Kwaliteitswaardecode | Compartiment.Code | Compartiment.Omschrijving | Grootheid.Code | Grootheid.Omschrijving | Eenheid.Code | ... | WaardeBewerkingsMethode.Omschrijving | Parameter_Wat_Omschrijving | ProcesType | Meetwaarde.Waarde_Alfanumeriek | Meetwaarde.Waarde_Numeriek | Code | Coordinatenstelsel | Naam | Lon | Lat | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | |||||||||||||||||||||
| 2023-01-01 01:00:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 63 | 63.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-01 01:10:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 56 | 56.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-01 01:20:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 51 | 51.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-01 01:30:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 46 | 46.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-01 01:40:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 40 | 40.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2023-01-15 00:20:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 15 | 15.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-15 00:30:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 13 | 13.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-15 00:40:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 10 | 10.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-15 00:50:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 8 | 8.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
| 2023-01-15 01:00:00+01:00 | Gecontroleerd | -999999999 | NVT | RIKZMON_WAT | 00 | OW | Oppervlaktewater | WATHTE | Waterhoogte | cm | ... | NVT | Waterhoogte in Oppervlaktewater t.o.v. Normaal... | meting | 6 | 6.0 | hoekvanholland | ETRS89 | Hoek van Holland | 4.119827 | 51.976899 |
2017 rows × 48 columns
[14]:
# A dataframe can be easily plotted
measurements.plot(y="Meetwaarde.Waarde_Numeriek", linewidth=0.8)
[14]:
<Axes: xlabel='time'>
ddlpy: other useful features#
In ddlpy there are several other useful features available:
access to the other Waterwebservices endpoints via
ddlpy.measurements_latest(),ddlpy.measurements_available()andddlpy.measurements_amount()simplifying the returned measurement dataframe by dropping constant columns
size-efficient conversion to xarray.Dataset
[15]:
# `ddlpy.simplify_dataframe()` drops constant columns
# these constant columns are added as attributes to the simplified DataFrame (meas_simple.attrs)
# if needed, some columns can be preserved via `always_preserved`
meas_simple = ddlpy.simplify_dataframe(measurements, always_preserve=["WaardeBepalingsMethode.Code"])
meas_simple
[15]:
| WaarnemingMetadata.Kwaliteitswaardecode | WaardeBepalingsMethode.Code | Meetwaarde.Waarde_Numeriek | |
|---|---|---|---|
| time | |||
| 2023-01-01 01:00:00+01:00 | 00 | other:F007 | 63.0 |
| 2023-01-01 01:10:00+01:00 | 00 | other:F007 | 56.0 |
| 2023-01-01 01:20:00+01:00 | 00 | other:F007 | 51.0 |
| 2023-01-01 01:30:00+01:00 | 00 | other:F007 | 46.0 |
| 2023-01-01 01:40:00+01:00 | 00 | other:F007 | 40.0 |
| ... | ... | ... | ... |
| 2023-01-15 00:20:00+01:00 | 00 | other:F007 | 15.0 |
| 2023-01-15 00:30:00+01:00 | 00 | other:F007 | 13.0 |
| 2023-01-15 00:40:00+01:00 | 00 | other:F007 | 10.0 |
| 2023-01-15 00:50:00+01:00 | 00 | other:F007 | 8.0 |
| 2023-01-15 01:00:00+01:00 | 00 | other:F007 | 6.0 |
2017 rows × 3 columns
[16]:
# `ddlpy.dataframe_to_xarray()` converts the DataFrame to an xarray object
# the input dataframe is first passed trough `ddlpy.simplify_dataframe()` and the
# constant columns are added as attributes to the xarray Dataset (ds_meas.attrs)
# all "*.Omschrijving" columns are converted to attributes of the "*.Code" variables
ds_meas = ddlpy.dataframe_to_xarray(measurements, always_preserve=["WaardeBepalingsMethode.Code"])
ds_meas
[16]:
<xarray.Dataset> Size: 65kB
Dimensions: (time: 2017)
Coordinates:
* time (time) datetime64[ns] 16kB 2023-...
Data variables:
WaarnemingMetadata.Kwaliteitswaardecode (time) object 16kB '00' ... '00'
WaardeBepalingsMethode.Code (time) object 16kB 'other:F007' ...
Meetwaarde.Waarde_Numeriek (time) float64 16kB 63.0 ... 6.0
Attributes: (12/45)
WaarnemingMetadata.Statuswaarde: Gecontroleerd
WaarnemingMetadata.Bemonsteringshoogte: -999999999
WaarnemingMetadata.Referentievlak: NVT
WaarnemingMetadata.OpdrachtgevendeInstantie: RIKZMON_WAT
Compartiment.Code: OW
Compartiment.Omschrijving: Oppervlaktewater
... ...
Meetwaarde.Waarde_Alfanumeriek: 63
Code: hoekvanholland
Coordinatenstelsel: ETRS89
Naam: Hoek van Holland
Lon: 4.119827
Lat: 51.976899[ ]: