Example of DOV search methods for groundwater screens (grondwaterfilters)¶
Use cases:¶
Get groundwater screens in a bounding box
Get groundwater screens with specific properties
Get the coordinates of all groundwater screens in Ghent
Get the ‘meetnet’ and ‘meetnet_code’ for groundwater screens in Boortmeerbeek
Get all details of groundwaterscreens of ‘meetnet 9’ within the given bounding box
Get groundwater screens based on a combination of specific properties
Get groundwater screens within a groundwater body
[1]:
%matplotlib inline
import inspect, sys
[2]:
# check pydov path
import pydov
Get information about the datatype ‘GrondwaterFilter’¶
[3]:
from pydov.search.grondwaterfilter import GrondwaterFilterSearch
gwfilter = GrondwaterFilterSearch()
A description is provided for the ‘GrondwaterFilter’ datatype:
[4]:
print(gwfilter.get_description())
In de Databank Ondergrond Vlaanderen zijn verschillende grondwatermeetnetten opgenomen. Deze meetnetten staan in functie van uitgebreide monitoringprogramma’s met de bedoeling een goed beeld te krijgen van de beschikbare grondwaterkwantiteit en grondwaterkwaliteit van de watervoerende lagen in Vlaanderen.
The different fields that are available for objects of the ‘GrondwaterFilter’ datatype can be requested with the get_fields() method:
[5]:
fields = gwfilter.get_fields()
# print available fields
for f in fields.values():
print(f['name'])
gw_id
pkey_grondwaterlocatie
filternummer
pkey_filter
namen
filtergrafiek
putgrafiek
aquifer
diepte_onderkant_filter
lengte_filter
putsoort
filtertype
meetnet
x
y
start_grondwaterlocatie_mtaw
gemeente
grondwaterlichaam
afgesloten_volgens_gwdecreet
datum_in_filter
datum_uit_filter
stijghoogterapport
analyserapport
boornummer
boringfiche
peilmetingen_van
peilmetingen_tot
kwaliteitsmetingen_van
kwaliteitsmetingen_tot
recentste_exploitant
beheerder
eerste_invoer
recentste_installatie
geom
meetnet_code
aquifer_code
grondwaterlichaam_code
regime
datum
tijdstip
peil_mtaw
betrouwbaarheid
methode
filterstatus
filtertoestand
mv_mtaw
You can get more information of a field by requesting it from the fields dictionary: * name: name of the field * definition: definition of this field * cost: currently this is either 1 or 10, depending on the datasource of the field. It is an indication of the expected time it will take to retrieve this field in the output dataframe. * notnull: whether the field is mandatory or not * type: datatype of the values of this field
[6]:
# print information for a certain field
fields['aquifer']
[6]:
{'name': 'aquifer',
'definition': 'De aquifer waarin de filter hangt. Als tekst, opgebouwd uit de HCOV code (vier karakters) en de naam gescheiden door " - "',
'type': 'string',
'notnull': True,
'query': True,
'cost': 1}
Optionally, if the values of the field have a specific domain the possible values are listed as values:
[7]:
# if an attribute can have several values, these are listed under 'values', e.g. for 'putsoort':
fields['putsoort']['values']
[7]:
{'Installatie': None,
'batterijput': None,
'bodemlus': None,
'bron, natuurlijke holte': None,
'bronbemaling': None,
'draineringsinrichting': None,
'galerij': None,
'graverij, mijn, groeve': None,
'niet-verbuisde boorput': None,
'onbekend': None,
'ring- of steenput': None,
'verbuisde boorput': None,
'vijver': None}
Example use cases¶
Get groundwater screens in a bounding box¶
Get data for all the groundwater screens that are geographically located within the bounds of the specified box.
The coordinates are in the Belgian Lambert72 (EPSG:31370) coordinate system and are given in the order of lower left x, lower left y, upper right x, upper right y.
[8]:
from pydov.util.location import Within, Box
df = gwfilter.search(location=Within(Box(93378, 168009, 94246, 169873)))
df.head()
[000/001] .
[000/026] ..........................
[8]:
pkey_filter | pkey_grondwaterlocatie | gw_id | filternummer | filtertype | x | y | start_grondwaterlocatie_mtaw | mv_mtaw | gemeente | ... | regime | diepte_onderkant_filter | lengte_filter | datum | tijdstip | peil_mtaw | betrouwbaarheid | methode | filterstatus | filtertoestand | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2018-00... | SWPP006 | 1 | peilfilter | 94147.0 | 169582.0 | 9.4 | 9.4 | Wortegem-Petegem | ... | onbekend | NaN | NaN | 1999-04-13 | NaN | 9.22 | onbekend | peillint | onbekend | 1.0 |
1 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2018-00... | SWPP006 | 1 | peilfilter | 94147.0 | 169582.0 | 9.4 | 9.4 | Wortegem-Petegem | ... | onbekend | NaN | NaN | 1999-04-14 | NaN | 9.41 | onbekend | peillint | onbekend | 1.0 |
2 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2018-00... | SWPP006 | 1 | peilfilter | 94147.0 | 169582.0 | 9.4 | 9.4 | Wortegem-Petegem | ... | onbekend | NaN | NaN | 1999-04-22 | NaN | 9.29 | onbekend | peillint | onbekend | 1.0 |
3 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2018-00... | SWPP006 | 1 | peilfilter | 94147.0 | 169582.0 | 9.4 | 9.4 | Wortegem-Petegem | ... | onbekend | NaN | NaN | 1999-05-06 | NaN | 9.11 | onbekend | peillint | onbekend | 1.0 |
4 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2018-00... | SWPP006 | 1 | peilfilter | 94147.0 | 169582.0 | 9.4 | 9.4 | Wortegem-Petegem | ... | onbekend | NaN | NaN | 1999-05-18 | NaN | 9.01 | onbekend | peillint | onbekend | 1.0 |
5 rows × 23 columns
Using the pkey attributes one can request the details of the corresponding put or filter in a webbrowser:
[9]:
for pkey_grondwaterlocatie in set(df.pkey_grondwaterlocatie):
print(pkey_grondwaterlocatie)
for pkey_filter in set(df.pkey_filter):
print(pkey_filter)
https://www.dov.vlaanderen.be/data/put/2018-007296
https://www.dov.vlaanderen.be/data/put/2019-019725
https://www.dov.vlaanderen.be/data/put/2018-007287
https://www.dov.vlaanderen.be/data/put/2018-007286
https://www.dov.vlaanderen.be/data/put/2018-007289
https://www.dov.vlaanderen.be/data/put/2018-007310
https://www.dov.vlaanderen.be/data/put/2017-002867
https://www.dov.vlaanderen.be/data/put/2018-007291
https://www.dov.vlaanderen.be/data/put/2018-007304
https://www.dov.vlaanderen.be/data/put/2018-007294
https://www.dov.vlaanderen.be/data/put/2018-007293
https://www.dov.vlaanderen.be/data/put/2018-007307
https://www.dov.vlaanderen.be/data/put/2018-007313
https://www.dov.vlaanderen.be/data/put/2017-002868
https://www.dov.vlaanderen.be/data/put/2018-007300
https://www.dov.vlaanderen.be/data/put/2019-020544
https://www.dov.vlaanderen.be/data/put/2018-007295
https://www.dov.vlaanderen.be/data/put/2017-002866
https://www.dov.vlaanderen.be/data/put/2018-007299
https://www.dov.vlaanderen.be/data/put/2018-007311
https://www.dov.vlaanderen.be/data/put/2018-007292
https://www.dov.vlaanderen.be/data/put/2018-007312
https://www.dov.vlaanderen.be/data/put/2018-007290
https://www.dov.vlaanderen.be/data/put/2018-007305
https://www.dov.vlaanderen.be/data/put/2018-007288
https://www.dov.vlaanderen.be/data/put/2018-007285
https://www.dov.vlaanderen.be/data/filter/1991-062098
https://www.dov.vlaanderen.be/data/filter/2007-011018
https://www.dov.vlaanderen.be/data/filter/2007-011024
https://www.dov.vlaanderen.be/data/filter/1999-011014
https://www.dov.vlaanderen.be/data/filter/1999-011007
https://www.dov.vlaanderen.be/data/filter/1999-011029
https://www.dov.vlaanderen.be/data/filter/1999-011009
https://www.dov.vlaanderen.be/data/filter/1999-011010
https://www.dov.vlaanderen.be/data/filter/2009-011026
https://www.dov.vlaanderen.be/data/filter/2007-011023
https://www.dov.vlaanderen.be/data/filter/1999-000605
https://www.dov.vlaanderen.be/data/filter/1999-000606
https://www.dov.vlaanderen.be/data/filter/1999-011011
https://www.dov.vlaanderen.be/data/filter/1999-011005
https://www.dov.vlaanderen.be/data/filter/1999-011013
https://www.dov.vlaanderen.be/data/filter/1999-011012
https://www.dov.vlaanderen.be/data/filter/1999-011031
https://www.dov.vlaanderen.be/data/filter/2007-011019
https://www.dov.vlaanderen.be/data/filter/1999-011030
https://www.dov.vlaanderen.be/data/filter/1995-061303
https://www.dov.vlaanderen.be/data/filter/1999-011008
https://www.dov.vlaanderen.be/data/filter/1999-011032
https://www.dov.vlaanderen.be/data/filter/1999-000607
https://www.dov.vlaanderen.be/data/filter/1999-011015
https://www.dov.vlaanderen.be/data/filter/1999-011006
https://www.dov.vlaanderen.be/data/filter/1999-011004
Get groundwater screens with specific properties¶
Next to querying groundwater screens based on their geographic location within a bounding box, we can also search for groundwater screens matching a specific set of properties. For this we can build a query using a combination of the ‘GrondwaterFilter’ fields and operators provided by the WFS protocol.
A list of possible operators can be found below:
[10]:
[i for i,j in inspect.getmembers(sys.modules['owslib.fes2'], inspect.isclass) if 'Property' in i]
[10]:
['PropertyIsBetween',
'PropertyIsEqualTo',
'PropertyIsGreaterThan',
'PropertyIsGreaterThanOrEqualTo',
'PropertyIsLessThan',
'PropertyIsLessThanOrEqualTo',
'PropertyIsLike',
'PropertyIsNotEqualTo',
'PropertyIsNull',
'SortProperty']
In this example we build a query using the PropertyIsEqualTo operator to find all groundwater screens that are within the community (gemeente) of ‘Hamme’:
[11]:
from owslib.fes2 import PropertyIsEqualTo
query = PropertyIsEqualTo(
propertyname='gemeente',
literal='Herstappe')
df = gwfilter.search(query=query)
df.head()
[000/001] .
[000/002] ..
[11]:
pkey_filter | pkey_grondwaterlocatie | gw_id | filternummer | filtertype | x | y | start_grondwaterlocatie_mtaw | mv_mtaw | gemeente | ... | regime | diepte_onderkant_filter | lengte_filter | datum | tijdstip | peil_mtaw | betrouwbaarheid | methode | filterstatus | filtertoestand | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/1993... | https://www.dov.vlaanderen.be/data/put/2019-02... | 7-001016 | 1 | pompfilter | 224798.0 | 157819.0 | 130.8 | 130.8 | Herstappe | ... | freatisch | 45.0 | 5.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | https://www.dov.vlaanderen.be/data/filter/1900... | https://www.dov.vlaanderen.be/data/put/2019-05... | 7-97027 | 1 | pompfilter | 224843.0 | 157842.0 | -1.0 | -1.0 | Herstappe | ... | onbekend | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 rows × 23 columns
Once again we can use the pkey_filter as a permanent link to the information of the groundwater screens:
[12]:
for pkey_filter in set(df.pkey_filter):
print(pkey_filter)
https://www.dov.vlaanderen.be/data/filter/1900-050992
https://www.dov.vlaanderen.be/data/filter/1993-065801
Get the coordinates of all groundwater screens in Ghent¶
[13]:
query = PropertyIsEqualTo(propertyname='gemeente',
literal='Gent')
df = gwfilter.search(query=query,
return_fields=('pkey_filter', 'x', 'y', 'meetnet'))
df.head()
[000/001] .
[13]:
pkey_filter | x | y | meetnet | |
---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/2021... | 105963.14 | 192492.99 | meetnet 20 - eDOV erkende boorbedrijven |
1 | https://www.dov.vlaanderen.be/data/filter/2021... | 107808.68 | 193262.21 | meetnet 20 - eDOV erkende boorbedrijven |
2 | https://www.dov.vlaanderen.be/data/filter/2021... | 104066.30 | 197002.80 | meetnet 20 - eDOV erkende boorbedrijven |
3 | https://www.dov.vlaanderen.be/data/filter/2021... | 96449.24 | 193281.13 | meetnet 20 - eDOV erkende boorbedrijven |
4 | https://www.dov.vlaanderen.be/data/filter/2021... | 101933.21 | 188065.16 | meetnet 20 - eDOV erkende boorbedrijven |
Get the ‘meetnet’ and ‘meetnet_code’ for groundwater screens in Boortmeerbeek¶
[14]:
query = PropertyIsEqualTo(propertyname='gemeente',
literal='Boortmeerbeek')
df = gwfilter.search(query=query,
return_fields=('pkey_filter', 'meetnet', 'meetnet_code'))
df.head()
[000/001] .
[000/058] ..................................................
[050/058] ........
[14]:
pkey_filter | meetnet | meetnet_code | |
---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/2000... | meetnet 7 - winningsputten | 7 |
1 | https://www.dov.vlaanderen.be/data/filter/2018... | meetnet 7 - winningsputten | 7 |
2 | https://www.dov.vlaanderen.be/data/filter/1976... | meetnet 7 - winningsputten | 7 |
3 | https://www.dov.vlaanderen.be/data/filter/1981... | meetnet 7 - winningsputten | 7 |
4 | https://www.dov.vlaanderen.be/data/filter/1980... | meetnet 7 - winningsputten | 7 |
Get all details of groundwaterscreens of ‘meetnet 9’ within the given bounding box¶
[15]:
from owslib.fes2 import PropertyIsLike
query = PropertyIsLike(propertyname='meetnet',
literal='meetnet 9 %')
df = gwfilter.search(query=query,
location=Within(Box(87676, 163442, 91194, 168043)))
df.head()
[000/001] .
[000/017] .................
[15]:
pkey_filter | pkey_grondwaterlocatie | gw_id | filternummer | filtertype | x | y | start_grondwaterlocatie_mtaw | mv_mtaw | gemeente | ... | regime | diepte_onderkant_filter | lengte_filter | datum | tijdstip | peil_mtaw | betrouwbaarheid | methode | filterstatus | filtertoestand | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2017-00... | WVSP009 | 1 | peilfilter | 89720.046875 | 165712.140625 | 11.84 | 11.84 | Avelgem | ... | onbekend | 5.78 | 1.0 | 1999-01-12 | NaN | 12.20 | onbekend | peillint | in rust | 1.0 |
1 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2017-00... | WVSP009 | 1 | peilfilter | 89720.046875 | 165712.140625 | 11.84 | 11.84 | Avelgem | ... | onbekend | 5.78 | 1.0 | 1999-01-21 | NaN | 12.26 | onbekend | peillint | in rust | 1.0 |
2 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2017-00... | WVSP009 | 1 | peilfilter | 89720.046875 | 165712.140625 | 11.84 | 11.84 | Avelgem | ... | onbekend | 5.78 | 1.0 | 1999-02-01 | NaN | 12.31 | onbekend | peillint | in rust | 1.0 |
3 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2017-00... | WVSP009 | 1 | peilfilter | 89720.046875 | 165712.140625 | 11.84 | 11.84 | Avelgem | ... | onbekend | 5.78 | 1.0 | 1999-02-06 | NaN | 12.29 | onbekend | peillint | in rust | 1.0 |
4 | https://www.dov.vlaanderen.be/data/filter/1999... | https://www.dov.vlaanderen.be/data/put/2017-00... | WVSP009 | 1 | peilfilter | 89720.046875 | 165712.140625 | 11.84 | 11.84 | Avelgem | ... | onbekend | 5.78 | 1.0 | 1999-02-12 | NaN | 12.18 | onbekend | peillint | in rust | 1.0 |
5 rows × 23 columns
Get groundwater screens based on a combination of specific properties¶
Get all groundwater screens in Hamme that have a value for length_filter and either belong to the primary meetnet of VMM or that have a depth bottom screen less than 3 meter.
[16]:
from owslib.fes2 import Or, Not, PropertyIsNull, PropertyIsLessThanOrEqualTo, And
query = And([PropertyIsEqualTo(propertyname='gemeente',
literal='Hamme'),
Not([PropertyIsNull(propertyname='lengte_filter')]),
Or([PropertyIsLike(propertyname='meetnet',
literal='meetnet 1%'),
PropertyIsLessThanOrEqualTo(
propertyname='diepte_onderkant_filter',
literal='3')])])
df_hamme = gwfilter.search(query=query,
return_fields=('pkey_filter', 'x', 'y', 'gw_id', 'filternummer', 'diepte_onderkant_filter'))
df_hamme.head()
[000/001] .
[16]:
pkey_filter | x | y | gw_id | filternummer | diepte_onderkant_filter | |
---|---|---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/2023... | 129002.000000 | 199133.000000 | DURP040 | 1 | 2.39 |
1 | https://www.dov.vlaanderen.be/data/filter/2001... | 130078.000000 | 196561.000000 | MORP002 | 1 | 1.91 |
2 | https://www.dov.vlaanderen.be/data/filter/2003... | 131763.200000 | 198674.500000 | 802/21/3 | 1 | 2.50 |
3 | https://www.dov.vlaanderen.be/data/filter/2003... | 131837.656250 | 197054.203125 | 810/21/1 | 1 | 2.50 |
4 | https://www.dov.vlaanderen.be/data/filter/2003... | 133865.921875 | 195656.328125 | 813/21/2 | 1 | 2.50 |
Combine datum
and tijdstip
in a datetime object¶
Get some data and keep only the relevant waterlevel measurements:
[17]:
query = PropertyIsEqualTo(
propertyname='pkey_filter',
literal='https://www.dov.vlaanderen.be/data/filter/1997-000494')
df = gwfilter.search(query=query)
df = df[df.filterstatus == "in rust"]
[000/001] .
[000/001] .
If the tijdstip
field contains data, it can be combined with the datum
field to create a date.datetime object. Make sure to fill the empty tijdstip
fields with a default timestamp.
[18]:
import pandas as pd
df.reset_index(inplace=True)
df['tijdstip'] = df.tijdstip.fillna('00:00:00')
df['tijd'] = pd.to_datetime(df.datum.astype(str)+' '+df.tijdstip.astype(str))
df.tijd.head()
[18]:
0 1998-07-31 01:05:00
1 1999-01-16 15:01:00
2 1999-08-14 01:05:00
3 1999-11-14 02:40:00
4 1999-12-27 00:01:00
Name: tijd, dtype: datetime64[ns]
Working with water head time series¶
For further analysis and visualisation of the time series data, we can use the data analysis library pandas and visualisation library matplotlib.
[19]:
import pandas as pd
import matplotlib.pyplot as plt
Query the data of a specific filter using its pkey
:
[20]:
query = PropertyIsEqualTo(
propertyname='pkey_filter',
literal='https://www.dov.vlaanderen.be/data/filter/2003-009883')
df = gwfilter.search(query=query)
df.head()
[000/001] .
[000/001] .
[20]:
pkey_filter | pkey_grondwaterlocatie | gw_id | filternummer | filtertype | x | y | start_grondwaterlocatie_mtaw | mv_mtaw | gemeente | ... | regime | diepte_onderkant_filter | lengte_filter | datum | tijdstip | peil_mtaw | betrouwbaarheid | methode | filterstatus | filtertoestand | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | onbekend | 0.68 | 0.3 | 2003-10-18 | NaN | 58.26 | onbekend | peillint | onbekend | 1 |
1 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | onbekend | 0.68 | 0.3 | 2003-11-01 | NaN | 58.30 | onbekend | peillint | onbekend | 1 |
2 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | onbekend | 0.68 | 0.3 | 2003-11-17 | NaN | 58.31 | onbekend | peillint | onbekend | 1 |
3 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | onbekend | 0.68 | 0.3 | 2003-11-23 | NaN | 58.31 | onbekend | peillint | onbekend | 1 |
4 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | onbekend | 0.68 | 0.3 | 2003-12-14 | NaN | 58.30 | onbekend | peillint | onbekend | 1 |
5 rows × 23 columns
The date is still stored as a string type. Transforming to a data type using the available pandas function `to_datetime
<https://pandas.pydata.org/pandas-docs/stable/generated/pandas.to_datetime.html>`__ and using these dates as row index:
[21]:
df['datum'] = pd.to_datetime(df['datum'])
df = df.set_index('datum')
Plotting¶
The default plotting functionality of Pandas can be used:
[22]:
df.head()
[22]:
pkey_filter | pkey_grondwaterlocatie | gw_id | filternummer | filtertype | x | y | start_grondwaterlocatie_mtaw | mv_mtaw | gemeente | ... | grondwaterlichaam_code | regime | diepte_onderkant_filter | lengte_filter | tijdstip | peil_mtaw | betrouwbaarheid | methode | filterstatus | filtertoestand | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
datum | |||||||||||||||||||||
2003-10-18 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | NaN | onbekend | 0.68 | 0.3 | NaN | 58.26 | onbekend | peillint | onbekend | 1 |
2003-11-01 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | NaN | onbekend | 0.68 | 0.3 | NaN | 58.30 | onbekend | peillint | onbekend | 1 |
2003-11-17 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | NaN | onbekend | 0.68 | 0.3 | NaN | 58.31 | onbekend | peillint | onbekend | 1 |
2003-11-23 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | NaN | onbekend | 0.68 | 0.3 | NaN | 58.31 | onbekend | peillint | onbekend | 1 |
2003-12-14 | https://www.dov.vlaanderen.be/data/filter/2003... | https://www.dov.vlaanderen.be/data/put/2018-00... | ZWAP205 | 1 | peilfilter | 218953.0 | 198767.0 | 58.44 | 58.44 | Houthalen-Helchteren | ... | NaN | onbekend | 0.68 | 0.3 | NaN | 58.30 | onbekend | peillint | onbekend | 1 |
5 rows × 22 columns
[23]:
ax = df['peil_mtaw'].plot(style='-', figsize=(12, 5))
ax.set_title('Water heads `Put ZWAP205` in Houthalen-Helchteren');
ax.set_ylabel('head (m TAW)');
ax.set_xlabel('');
Or a combination with matplotlib to have full customization options:
[24]:
from matplotlib.dates import MonthLocator, YearLocator, DateFormatter
from matplotlib.ticker import MaxNLocator, MultipleLocator
# Get height of ground surface
ground_surface = df["mv_mtaw"][0]
# create a plot with 2 subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 6),
sharex=False, sharey=True)
# Plot entire time series in the upper plot
df['peil_mtaw'].plot(ax=ax1, title='Water heads `Put ZWAP205`')
ax1.xaxis.set_major_locator(YearLocator(5))
ax1.xaxis.set_major_formatter(DateFormatter('%Y'))
# Plot the data for 2011 in the lower plot
df['peil_mtaw']["2011"].plot(ax=ax2, title='Water heads `Put ZWAP205` year 2011')
ax2.xaxis.set_major_locator(MonthLocator(interval=3))
ax2.xaxis.set_major_formatter(DateFormatter('%Y-%m'))
# Adjust configuration of plot
for ax in (ax1, ax2):
ax.set_xlabel('')
ax.set_ylabel('head (mTAW)')
for tick in ax.get_xticklabels():
tick.set_rotation(0)
tick.set_horizontalalignment('center')
# Only draw spine between the y-ticks
ax.spines['left'].set_position(('outward', 10))
# Hide the right and top spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.yaxis.set_major_locator(MultipleLocator(0.2))
# Add the ground surface (provided in the data) on the subplots
ax.axhline(ground_surface, color = 'brown')
ax.annotate('Ground surface',
xy=(0.05, 0.68),
xycoords='axes fraction',
xytext=(-25, -15), textcoords='offset points',
fontsize=12, color='brown')
fig.tight_layout(h_pad=5)
Analysis¶
The Pandas package provides a the functionality to further analyze and process time series data. Particularly, the `resample
<https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.resample.html>`__ function can be useful.
For example, calculate the yearly minima and maxima of the time series:
[25]:
df["peil_mtaw"].resample("A").agg(['min', 'max'])
[25]:
min | max | |
---|---|---|
datum | ||
2003-12-31 | 58.26 | 58.36 |
2004-12-31 | 58.22 | 58.36 |
2005-12-31 | 58.18 | 58.35 |
2006-12-31 | 58.10 | 58.42 |
2007-12-31 | 58.28 | 58.53 |
2008-12-31 | 58.32 | 58.57 |
2009-12-31 | 58.24 | 58.51 |
2010-12-31 | 58.18 | 58.53 |
2011-12-31 | 58.03 | 58.53 |
2012-12-31 | 58.30 | 58.52 |
2013-12-31 | 58.20 | 58.54 |
2014-12-31 | 58.31 | 58.58 |
2015-12-31 | 58.21 | 58.58 |
2016-12-31 | 58.38 | 58.58 |
2017-12-31 | 58.28 | 58.56 |
2018-12-31 | 58.10 | 58.54 |
2019-12-31 | 58.26 | 58.52 |
2020-12-31 | 58.21 | 58.56 |
2021-12-31 | 58.33 | 58.56 |
or the monthly minima and maxima:
[26]:
ax = df["peil_mtaw"].resample("M").agg(['min', 'max']).plot()
ax.set_title('Monthly minimum and maximum water heads `Put ZWAP205`');
ax.set_ylabel('head (m TAW)');
ax.set_xlabel('');
Calculate 10 and 90 percentiles of the time series with the quantile
function:
[27]:
fig, ax = plt.subplots(figsize=(12, 4))
ax.plot(df["peil_mtaw"], label='head (mTAW)', linewidth=0.75)
ax.axhline(df["peil_mtaw"].quantile(0.1), color = 'brown', label='p10', linewidth=3)
ax.axhline(df["peil_mtaw"].quantile(0.9), color = 'darkblue', label='p90', linewidth=3)
handles, labels = ax.get_legend_handles_labels()
ax.set_title('Water heads `Put ZWAP205` with 10% and 90% quantile');
ax.set_ylabel('head (m TAW)');
ax.set_xlabel('');
fig.legend(handles, labels)
[27]:
<matplotlib.legend.Legend at 0x7fab5e1f1f30>
A duration exceedance curve provides the percentage of time that the water head is above a given value:
[28]:
import numpy as np
[29]:
sorted_heads = np.sort(df["peil_mtaw"])[::-1]
exceedence = np.arange(1.,len(sorted_heads)+1) / len(sorted_heads)
fig, ax = plt.subplots()
ax.plot(exceedence*100, sorted_heads)
ax.set_xlabel("Exceedence [%]");
ax.set_ylabel("Water head (mTAW)");
ax.set_title("Duration exceedance curve `Put ZWAP205`");
Visualize locations¶
Using Folium, we can display the results of our search on a map.
[30]:
# import the necessary modules (not included in the requirements of pydov!)
import folium
from folium.plugins import MarkerCluster
from pyproj import Transformer
[31]:
# convert the coordinates to lat/lon for folium
def convert_latlon(x1, y1):
transformer = Transformer.from_crs("epsg:31370", "epsg:4326", always_xy=True)
x2,y2 = transformer.transform(x1, y1)
return x2, y2
df_hamme['lon'], df_hamme['lat'] = zip(*map(convert_latlon, df_hamme['x'], df_hamme['y']))
# convert to list
loclist = df_hamme[['lat', 'lon']].values.tolist()
[32]:
# initialize the Folium map on the centre of the selected locations, play with the zoom until ok
fmap = folium.Map(location=[df_hamme['lat'].mean(), df_hamme['lon'].mean()], zoom_start=12)
marker_cluster = MarkerCluster().add_to(fmap)
for loc in range(0, len(loclist)):
folium.Marker(loclist[loc], popup=df_hamme['gw_id'][loc]).add_to(marker_cluster)
fmap
[32]:
Get groundwater screens within a “grondwaterlichaam”¶
[33]:
gwfilter = GrondwaterFilterSearch()
[34]:
query = PropertyIsLike(
propertyname='grondwaterlichaam',
literal='BLKS_1000%')
df = gwfilter.search(max_features=10,
query=query,
return_fields=("pkey_filter", "gw_id", "filternummer", "x", "y", "grondwaterlichaam_code"))
df
[000/001] .
[000/010] ..........
[34]:
pkey_filter | gw_id | filternummer | x | y | grondwaterlichaam_code | |
---|---|---|---|---|---|---|
0 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102785 | 1 | 210979.88 | 168230.26 | BLKS_1000_GWL_1S |
1 | https://www.dov.vlaanderen.be/data/filter/1980... | 2-102826 | 1 | 186893.00 | 170107.00 | BLKS_1000_GWL_2S |
2 | https://www.dov.vlaanderen.be/data/filter/1900... | 2-102827 | 1 | 194695.15 | 171663.09 | BLKS_1000_GWL_1S |
3 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102884 | 1 | 207018.00 | 172526.00 | BLKS_1000_GWL_1S |
4 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102885 | 1 | 207390.00 | 172929.00 | BLKS_1000_GWL_1S |
5 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102932 | 1 | 211487.00 | 171449.00 | BLKS_1000_GWL_1S |
6 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102933 | 1 | 202697.00 | 164717.00 | BLKS_1000_GWL_1S |
7 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102934 | 1 | 204608.00 | 164020.00 | BLKS_1000_GWL_1S |
8 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102935 | 1 | 205197.00 | 162965.00 | BLKS_1000_GWL_1S |
9 | https://www.dov.vlaanderen.be/data/filter/1900... | 7-102936 | 1 | 211117.00 | 172960.00 | BLKS_1000_GWL_2S |