How well does the Robertson Soil Behavior Type based on CPTs describe our Flemish peat samples?
A practical example to query the DOV database using pydov to validate the Robertson Soil Behavior Type against observed data using samples, observations, boreholes and CPT measurements.
First, we retrieve all observations where a high content (at least 50%) of organic matter was measured. We also retrieve the depth below ground surface. Subsequently, we retrieve the borehole data via the corresponding sample, specifically the start level in mTAW. This allows us to determine the absolute depth (mTAW) of the sample.
Next, we perform a geographical search to find CPT measurements that are located near (within 5 meters) these peat samples. This allows us to efficiently retrieve the nearest CPT measurement for each of the samples. We also recalculate the CPT data to absolute elevation values in meter TAW, so that we can retain only the portion that corresponds planimetrically and altimetrically with the peat sample for further calculations.
Subsequently, the Robertson Soil Behavior Type analysis is performed for each sample (observation) based on the available CPT measurement data. Finally, the results are displayed in charts.
Imports
First we import the required classes and libraries:
[1]:
from pydov.search.observatie import ObservatieSearch
from pydov.search.monster import MonsterSearch
from pydov.search.sondering import SonderingSearch
from pydov.search.boring import BoringSearch
from pydov.types.observatie import Observatie
from pydov.types.sondering import Sondering
from pydov.search.fields import GeometryReturnField
from pydov.util.location import WithinDistance, GeopandasFilter
from pydov.util.query import Join
from owslib.fes2 import PropertyIsEqualTo
import numpy as np
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
Search objects
Next we create a search object for each dataset we need. These search objects can then be used to query each of the datasets.
[2]:
observatie_search = ObservatieSearch()
monster_search = MonsterSearch()
sondering_search = SonderingSearch()
boring_search = BoringSearch()
We don’t need all fields from all datasets: here we define which fields we want to retrieve for each dataset.
For the observations and CPT measurements we need the geometry in addition to the standard fields, to be able to perform the spatial join later.
We retrieve the CPT measurements in two phases: first only the permanent key and the geometry (needed for the spatial join), and only later the complete CPT data.
Retrieve data
Peat observations
For the observations we also need the geometry in addition to the standard fields, which we add here:
[3]:
observatie_fields = Observatie.get_field_names()
observatie_fields.extend([GeometryReturnField(f.name, 31370) for f in observatie_search.get_fields(type='geometry').values()])
observatie_fields
[3]:
['pkey_observatie',
'pkey_parent',
'fenomeentijd',
'diepte_van_m',
'diepte_tot_m',
'parametergroep',
'parameter',
'detectieconditie',
'resultaat',
'eenheid',
'methode',
'uitvoerder',
'herkomst',
<pydov.search.fields.GeometryReturnField at 0x7fd872e30d70>]
Now we can start retrieving the required data. First we retrieve the observations for the parameter ‘Gehalte Organische stoffen’ (Organic matter content). The result is a percentage and we convert it to numbers (float), to retain only those with a percentage of at least 50 percent.
We also add a column with the pkey_monster to which the observations are linked. When observations are linked to objects other than samples, this column will remain empty.
[4]:
df_observaties = observatie_search.search(
query= PropertyIsEqualTo('parameter', 'Gehalte Organische stoffen (Gehalte Organische stoffen)'),
return_fields=observatie_fields
)
df_observaties['resultaat'] = df_observaties['resultaat'].astype(float)
df_observaties = df_observaties[df_observaties['resultaat'] >= 50]
df_observaties['pkey_monster'] = df_observaties['pkey_parent'].apply(lambda x: x if 'monster' in x else np.nan)
df_observaties
[000/002] ..
[4]:
| pkey_observatie | pkey_parent | fenomeentijd | diepte_van_m | diepte_tot_m | parametergroep | parameter | detectieconditie | resultaat | eenheid | methode | uitvoerder | herkomst | geom | pkey_monster | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 59 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2023-06-26 | 5.75 | 5.97 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 88.1 | % | Chemische reactie met waterstofperoxide | NaN | LABO | POINT (150277.4 211260.94) | https://www.dov.vlaanderen.be/data/monster/202... |
| 90 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2023-10-04 | 7.50 | 7.90 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 62.6 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (143476.04 161514.62) | https://www.dov.vlaanderen.be/data/monster/202... |
| 99 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2023-10-04 | 6.70 | 7.00 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 60.7 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (143476.04 161514.62) | https://www.dov.vlaanderen.be/data/monster/202... |
| 102 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2017-04-05 | 7.50 | 8.00 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 75.8 | % | Chemische reactie met waterstofperoxide | GMA | LABO | POINT (148857.03 212851.95) | https://www.dov.vlaanderen.be/data/monster/201... |
| 103 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2017-04-05 | 8.10 | 8.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 83.8 | % | Chemische reactie met waterstofperoxide | GMA | LABO | POINT (148857.03 212851.95) | https://www.dov.vlaanderen.be/data/monster/201... |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 13429 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2002-12-02 | 7.00 | 7.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 70.8 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (116790.49 189146.29) | https://www.dov.vlaanderen.be/data/monster/201... |
| 13542 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 1967-03-21 | 3.00 | 3.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 59.8 | % | Chemische reactie met waterstofperoxide | Rijksinstituut voor Grondmechanica | LABO | POINT (153802 176597) | https://www.dov.vlaanderen.be/data/monster/201... |
| 13589 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2006-07-06 | 8.50 | 8.96 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 62.0 | % | Chemische reactie met waterstofperoxide | Katholieke Universiteit Leuven (KUL) | LABO | POINT (141229.95 225203.22) | https://www.dov.vlaanderen.be/data/monster/201... |
| 13751 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-04-17 | 4.50 | 4.98 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 54.8 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (119536.32 189184.38) | https://www.dov.vlaanderen.be/data/monster/201... |
| 13758 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2001-08-28 | 4.80 | 5.20 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 79.6 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (126518.8 189455) | https://www.dov.vlaanderen.be/data/monster/201... |
306 rows × 15 columns
We already have the (relative) depth available for these observations, but to convert this to absolute elevations we also need the start level (ground surface). This can be found via the sample and the borehole.
First we retrieve the samples to which these observations are linked and add a column with the pkey_boring. For samples linked to multiple boreholes, the first one is retained; for samples linked to other objects, this column remains empty.
[5]:
df_monsters = monster_search.search(
query=Join(df_observaties, on='pkey_monster'),
return_fields=['pkey_monster', 'pkey_parents']
)
df_monsters['pkey_boring'] = df_monsters['pkey_parents'].apply(lambda x: [i for i in x if 'boring' in i][0])
df_monsters
[000/001] .
[5]:
| pkey_monster | pkey_parents | pkey_boring | |
|---|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2001... |
| 1 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2000... |
| 2 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2001... |
| 3 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2001... |
| 4 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2001... |
| ... | ... | ... | ... |
| 301 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2005... |
| 302 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2008... |
| 303 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2008... |
| 304 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2008... |
| 305 | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2008... |
306 rows × 3 columns
Based on this link to the boreholes, we can finally retrieve the start level of the borehole:
[6]:
df_boringen = boring_search.search(
query=Join(df_monsters, on='pkey_boring'),
return_fields=['pkey_boring', 'start_boring_mtaw']
)
df_boringen
[000/001] .
[6]:
| pkey_boring | start_boring_mtaw | |
|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/boring/1998... | 6.58 |
| 1 | https://www.dov.vlaanderen.be/data/boring/1998... | 2.48 |
| 2 | https://www.dov.vlaanderen.be/data/boring/1998... | 4.54 |
| 3 | https://www.dov.vlaanderen.be/data/boring/1999... | 0.55 |
| 4 | https://www.dov.vlaanderen.be/data/boring/2002... | 6.89 |
| ... | ... | ... |
| 256 | https://www.dov.vlaanderen.be/data/boring/2013... | 8.01 |
| 257 | https://www.dov.vlaanderen.be/data/boring/2013... | 6.00 |
| 258 | https://www.dov.vlaanderen.be/data/boring/2013... | 6.24 |
| 259 | https://www.dov.vlaanderen.be/data/boring/2013... | 2.09 |
| 260 | https://www.dov.vlaanderen.be/data/boring/2013... | 1.96 |
261 rows × 2 columns
Subsequently, we can merge all results back into a single dataframe using pd.merge(). First we merge the samples and the boreholes based on the pkey_boring, and then this result with the observations based on the pkey_monster:
[7]:
df_monsters = pd.merge(df_monsters, df_boringen, 'outer', 'pkey_boring')
df_observaties = pd.merge(df_observaties, df_monsters, 'outer', 'pkey_monster')
df_observaties
[7]:
| pkey_observatie | pkey_parent | fenomeentijd | diepte_van_m | diepte_tot_m | parametergroep | parameter | detectieconditie | resultaat | eenheid | methode | uitvoerder | herkomst | geom | pkey_monster | pkey_parents | pkey_boring | start_boring_mtaw | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/196... | 1967-03-20 | 4.2 | 4.28 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 59.3 | % | Chemische reactie met waterstofperoxide | Rijksinstituut voor Grondmechanica | LABO | POINT (153931 176643) | https://www.dov.vlaanderen.be/data/monster/196... | (https://www.dov.vlaanderen.be/data/boring/196... | https://www.dov.vlaanderen.be/data/boring/1967... | 17.83 |
| 1 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2006-08-03 | 11.0 | 11.47 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 92.2 | % | Chemische reactie met waterstofperoxide | MVG - Afdeling Geotechniek | LABO | POINT (149350 196921) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2006... | 8.24 |
| 2 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 1967-03-17 | 6.5 | 6.75 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 71.4 | % | Chemische reactie met waterstofperoxide | Rijksinstituut voor Grondmechanica | LABO | POINT (154018 176662) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/196... | https://www.dov.vlaanderen.be/data/boring/1967... | 18.47 |
| 3 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 1967-03-20 | 7.0 | 7.28 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 59.3 | % | Chemische reactie met waterstofperoxide | Rijksinstituut voor Grondmechanica | LABO | POINT (153931 176643) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/196... | https://www.dov.vlaanderen.be/data/boring/1967... | 17.83 |
| 4 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 1967-03-21 | 3.0 | 3.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 59.8 | % | Chemische reactie met waterstofperoxide | Rijksinstituut voor Grondmechanica | LABO | POINT (153802 176597) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/196... | https://www.dov.vlaanderen.be/data/boring/1967... | 17.62 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 301 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-18 | 8.0 | 8.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 76.2 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (140180.82 220020.08) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 6.27 |
| 302 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-20 | 7.5 | 7.90 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 97.8 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (140027.49 220118.96) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 6.38 |
| 303 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-21 | 9.5 | 10.00 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 67.4 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (139978.91 219818.45) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 7.26 |
| 304 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-08-29 | 9.0 | 9.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 81.7 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (69751.19 225638.32) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 7.75 |
| 305 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-08-29 | 13.0 | 13.48 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 78.2 | % | Chemische reactie met waterstofperoxide | VO - Afdeling Geotechniek | LABO | POINT (69751.19 225638.32) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 7.75 |
306 rows × 18 columns
From this we create a GeoPandas GeoDataFrame, to be able to use in a pydov search query and later to use in the spatial join with the CPT measurements.
[8]:
geo_df_observaties = gpd.GeoDataFrame(df_observaties, geometry='geom', crs='EPSG:31370')
geo_df_observaties.explore()
[8]:
Nearby CPT measurements
Initially we want to build a dataframe of all nearby CPT measurements and their location, but without the complete CPT data yet. So first we only retrieve the permanent URL and the location:
[9]:
sondering_fields_base = [
'pkey_sondering',
]
sondering_fields_geom = [GeometryReturnField(f.name, 31370) for f in observatie_search.get_fields(type='geometry').values()]
sondering_fields_base.extend(sondering_fields_geom)
sondering_fields_base
[9]:
['pkey_sondering', <pydov.search.fields.GeometryReturnField at 0x7fd823e7c050>]
Now that we have all peat samples available, we can search for all nearby CPT measurements. This can be done very easily by using the GeopandasFilter in pydov: with the following command we can find all CPT measurements that are located 5 meters or less from one of the previously found peat samples:
[10]:
df_sonderingen_base = sondering_search.search(
location=GeopandasFilter(geo_df_observaties, WithinDistance, {'distance': 5}),
query=PropertyIsEqualTo('sondeermethode', 'continu elektrisch'),
return_fields=sondering_fields_base
)
df_sonderingen_base
[000/001] .
[10]:
| pkey_sondering | geom | |
|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (141356.2 218562.1) |
| 1 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (149606.6 213102.4) |
| 2 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (149440.5 212336.7) |
| 3 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (149579.8 212801.4) |
| 4 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (149826.6 213310.4) |
| ... | ... | ... |
| 173 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (68564.5 223202.2) |
| 174 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (122144.8 188881.2) |
| 175 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (46343.3 211391.8) |
| 176 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (46012.1 211344) |
| 177 | https://www.dov.vlaanderen.be/data/sondering/2... | POINT (150522.5 221639.5) |
178 rows × 2 columns
We also create a GeoDataFrame from this:
[11]:
geo_df_sonderingen_base = gpd.GeoDataFrame(df_sonderingen_base, geometry='geom', crs='EPSG:31370')
geo_df_sonderingen_base.explore()
[11]:
Now we can join the two GeoDataFrames based on their location: this way we find for each observation which CPT measurement(s) are nearby, as well as their mutual distance:
[12]:
df_joined = gpd.sjoin_nearest(geo_df_observaties, geo_df_sonderingen_base, max_distance=5, distance_col='dist')
df_joined
[12]:
| pkey_observatie | pkey_parent | fenomeentijd | diepte_van_m | diepte_tot_m | parametergroep | parameter | detectieconditie | resultaat | eenheid | ... | uitvoerder | herkomst | geom | pkey_monster | pkey_parents | pkey_boring | start_boring_mtaw | index_right | pkey_sondering | dist | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2006-08-03 | 11.0 | 11.47 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 92.2 | % | ... | MVG - Afdeling Geotechniek | LABO | POINT (149350 196921) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2006... | 8.24 | 41 | https://www.dov.vlaanderen.be/data/sondering/2... | 0.322025 |
| 10 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2006-07-06 | 8.5 | 8.96 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 62.0 | % | ... | Katholieke Universiteit Leuven (KUL) | LABO | POINT (141229.95 225203.22) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2006... | 7.81 | 28 | https://www.dov.vlaanderen.be/data/sondering/2... | 3.019884 |
| 11 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-01-29 | 7.0 | 7.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 79.4 | % | ... | Katholieke Universiteit Leuven (KUL) | LABO | POINT (140836.3 225113.28) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2007... | 7.10 | 66 | https://www.dov.vlaanderen.be/data/sondering/2... | 1.801139 |
| 12 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-04-17 | 4.5 | 4.98 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 54.8 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (119536.32 189184.38) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2007... | 4.07 | 26 | https://www.dov.vlaanderen.be/data/sondering/2... | 2.993125 |
| 14 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-02-28 | 8.0 | 8.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 87.6 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (152353 213884.55) | https://www.dov.vlaanderen.be/data/monster/201... | (https://www.dov.vlaanderen.be/data/boring/200... | https://www.dov.vlaanderen.be/data/boring/2007... | 7.66 | 25 | https://www.dov.vlaanderen.be/data/sondering/2... | 2.540709 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 301 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-18 | 8.0 | 8.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 76.2 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (140180.82 220020.08) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 6.27 | 138 | https://www.dov.vlaanderen.be/data/sondering/2... | 0.930054 |
| 302 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-20 | 7.5 | 7.90 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 97.8 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (140027.49 220118.96) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 6.38 | 140 | https://www.dov.vlaanderen.be/data/sondering/2... | 4.396931 |
| 303 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-21 | 9.5 | 10.00 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 67.4 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (139978.91 219818.45) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 7.26 | 136 | https://www.dov.vlaanderen.be/data/sondering/2... | 1.478716 |
| 304 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-08-29 | 9.0 | 9.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 81.7 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (69751.19 225638.32) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 7.75 | 172 | https://www.dov.vlaanderen.be/data/sondering/2... | 2.464731 |
| 305 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-08-29 | 13.0 | 13.48 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 78.2 | % | ... | VO - Afdeling Geotechniek | LABO | POINT (69751.19 225638.32) | https://www.dov.vlaanderen.be/data/monster/202... | (https://www.dov.vlaanderen.be/data/boring/202... | https://www.dov.vlaanderen.be/data/boring/2025... | 7.75 | 172 | https://www.dov.vlaanderen.be/data/sondering/2... | 2.464731 |
202 rows × 21 columns
Now we only need the CPT data itself: this can be requested based on the previously found CPT measurements, but now with the complete list of fields as return_fields:
[13]:
sondering_fields = Sondering.get_field_names()
sondering_fields.extend(sondering_fields_geom)
sondering_fields
[13]:
['pkey_sondering',
'sondeernummer',
'x',
'y',
'mv_mtaw',
'start_sondering_mtaw',
'diepte_sondering_van',
'diepte_sondering_tot',
'datum_aanvang',
'uitvoerder',
'sondeermethode',
'apparaat',
'datum_gw_meting',
'diepte_gw_m',
'lengte',
'diepte',
'qc',
'Qt',
'fs',
'u',
'i',
<pydov.search.fields.GeometryReturnField at 0x7fd823e7c050>]
[14]:
df_sonderingen = sondering_search.search(
query=Join(df_sonderingen_base, 'pkey_sondering'),
return_fields=sondering_fields
)
df_sonderingen
[000/001] .
[000/178] cccccccccccccccccccccccccccccccccccccccccccccccccc
[050/178] cccccccccccccccccccccccccccccccccccccccccccccccccc
[100/178] cccccccccccccccccccccccccccccccccccccccccccccccccc
[150/178] cccccccccccccccccccccccccccc
[14]:
| pkey_sondering | sondeernummer | x | y | mv_mtaw | start_sondering_mtaw | diepte_sondering_van | diepte_sondering_tot | datum_aanvang | uitvoerder | ... | datum_gw_meting | diepte_gw_m | lengte | diepte | qc | Qt | fs | u | i | geom | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/153-SZS126 | 141356.2 | 218562.1 | NaN | 6.75 | 1.2 | 32.15 | 2002-09-06 | MVG - Afdeling Geotechniek | ... | 2002-09-06 00:00:00 | 1.15 | 1.25 | 1.25 | 9.96 | NaN | 110.0 | NaN | -3.1 | POINT (141356.2 218562.1) |
| 1 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/153-SZS126 | 141356.2 | 218562.1 | NaN | 6.75 | 1.2 | 32.15 | 2002-09-06 | MVG - Afdeling Geotechniek | ... | 2002-09-06 00:00:00 | 1.15 | 1.30 | 1.30 | 10.50 | NaN | 120.0 | NaN | -3.1 | POINT (141356.2 218562.1) |
| 2 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/153-SZS126 | 141356.2 | 218562.1 | NaN | 6.75 | 1.2 | 32.15 | 2002-09-06 | MVG - Afdeling Geotechniek | ... | 2002-09-06 00:00:00 | 1.15 | 1.35 | 1.35 | 17.02 | NaN | 140.0 | NaN | -3.1 | POINT (141356.2 218562.1) |
| 3 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/153-SZS126 | 141356.2 | 218562.1 | NaN | 6.75 | 1.2 | 32.15 | 2002-09-06 | MVG - Afdeling Geotechniek | ... | 2002-09-06 00:00:00 | 1.15 | 1.40 | 1.40 | 16.74 | NaN | 150.0 | NaN | -3.1 | POINT (141356.2 218562.1) |
| 4 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/153-SZS126 | 141356.2 | 218562.1 | NaN | 6.75 | 1.2 | 32.15 | 2002-09-06 | MVG - Afdeling Geotechniek | ... | 2002-09-06 00:00:00 | 1.15 | 1.45 | 1.45 | 16.13 | NaN | 160.0 | NaN | -3.1 | POINT (141356.2 218562.1) |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 153411 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/182-S4 | 150522.5 | 221639.5 | NaN | 6.70 | 1.4 | 12.35 | 2002-02-27 | MVG - Afdeling Geotechniek | ... | 2002-02-27 15:00:00 | 5.10 | 12.15 | 12.15 | 30.65 | NaN | 260.0 | NaN | 0.1 | POINT (150522.5 221639.5) |
| 153412 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/182-S4 | 150522.5 | 221639.5 | NaN | 6.70 | 1.4 | 12.35 | 2002-02-27 | MVG - Afdeling Geotechniek | ... | 2002-02-27 15:00:00 | 5.10 | 12.20 | 12.20 | 27.91 | NaN | 250.0 | NaN | 0.1 | POINT (150522.5 221639.5) |
| 153413 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/182-S4 | 150522.5 | 221639.5 | NaN | 6.70 | 1.4 | 12.35 | 2002-02-27 | MVG - Afdeling Geotechniek | ... | 2002-02-27 15:00:00 | 5.10 | 12.25 | 12.25 | 28.06 | NaN | 250.0 | NaN | 0.1 | POINT (150522.5 221639.5) |
| 153414 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/182-S4 | 150522.5 | 221639.5 | NaN | 6.70 | 1.4 | 12.35 | 2002-02-27 | MVG - Afdeling Geotechniek | ... | 2002-02-27 15:00:00 | 5.10 | 12.30 | 12.30 | 27.85 | NaN | 260.0 | NaN | 0.1 | POINT (150522.5 221639.5) |
| 153415 | https://www.dov.vlaanderen.be/data/sondering/2... | GEO-01/182-S4 | 150522.5 | 221639.5 | NaN | 6.70 | 1.4 | 12.35 | 2002-02-27 | MVG - Afdeling Geotechniek | ... | 2002-02-27 15:00:00 | 5.10 | 12.35 | 12.35 | 26.88 | NaN | 260.0 | NaN | 0.1 | POINT (150522.5 221639.5) |
153416 rows × 22 columns
Data analysis
Now that we have all the data, we can start our analysis. First we create an empty dataframe with the required columns to later save the results in:
[15]:
new_columns = [
'pkey_observatie',
"qc_avg",
"qc_med",
"qc_var",
"fs_avg",
"fs_med",
"fs_var",
"rf_avg",
"rf_med",
"rf_var",
"Qtn_avg",
"Qtn_med",
"Qtn_var",
"F_avg",
"F_med",
"F_var",
"IC_avg",
"IC_med",
"IC_var",
] # create the variables that you want to store
sonddata_df = pd.DataFrame(
columns=new_columns
) # make a dataframe with the same shape as gdf but with above specified columns
And we perform the actual analysis. For each observation (peat sample), the nearest CPT measurement is searched and its data is loaded. After converting both the observation and the CPT data to meter TAW, the Robertson Soil Behavior Type parameters can be calculated. These are added to the result dataframe.
[16]:
for observation in set(df_joined['pkey_observatie']):
nearest_sondering = df_joined[df_joined['pkey_observatie'] == observation].sort_values(by='dist', ascending=False).iloc[0]['pkey_sondering']
sondering_data = df_sonderingen[
(df_sonderingen['pkey_sondering'] == nearest_sondering)
& (df_sonderingen['fs'] > 0)
& (df_sonderingen['qc'] > 0)
].copy()
observatie_data = df_joined[df_joined['pkey_observatie'] == observation]
if sondering_data.size == 0:
continue
sondering_data["rf"] = sondering_data["fs"] / sondering_data["qc"] / 10 # calculate rf
# convert depths to relative levels
sondering_data["mtaw"] = (
sondering_data["start_sondering_mtaw"] - sondering_data["diepte"]
)
sondering_data["mtaw"] = sondering_data["mtaw"].fillna(sondering_data["start_sondering_mtaw"] - sondering_data["lengte"])
# for the moment there will be no correction with the lag index, this is hard to do automatically, could possibly be done by looking at max curvature or by looping through the indices and finding the first maxima
sondering_data["unitw"] = 9.81 * (
0.27 * np.log10(sondering_data["rf"]) + 0.36 * np.log10((sondering_data["qc"] / 0.1)) + 1.236
) # calculate unitw
# if there is no groundwaterdata then take GW equal to start of the sounding
sondering_data["diepte_gw_m"] = sondering_data["diepte_gw_m"].fillna(sondering_data["start_sondering_mtaw"])
# if above the groundwater, give a value 0 for pwp
sondering_data.loc[sondering_data['lengte'] < sondering_data['diepte_gw_m'], 'pwp'] = 0
# if below GW, give value equal to hydrostatic pwp
sondering_data.loc[sondering_data['lengte'] >= sondering_data['diepte_gw_m'], 'pwp'] = (sondering_data["lengte"] - sondering_data["diepte_gw_m"]) * 9.81
sondering_data["stot"] = 0 # make a stot column
sondering_data['stot'] = (sondering_data['lengte'] - sondering_data['lengte'].shift(1).fillna(0)) * sondering_data['unitw']
sondering_data['stot'] = sondering_data['stot'].cumsum()
sondering_data["seff"] = sondering_data["stot"] - sondering_data["pwp"] # calculate effective stress
if sondering_data["seff"].isna().any(): # check i used for detecting nan values
print(f"NaN found for 'seff' in rows {sondering_data[sondering_data['seff'].isna()].index}")
break
sondering_data["Qtn"] = ((sondering_data["qc"] * 1000 - sondering_data["stot"]) / 100) * (
100 / sondering_data["seff"]
) # calculate corrected Qtn
sondering_data["F"] = sondering_data["fs"] * 100 / (sondering_data["qc"] * 1000 - sondering_data["stot"])
# calculate corrected F-factor
sondering_data["IC"] = (
(3.47 - np.log10(sondering_data["Qtn"])) ** 2 + (np.log10(sondering_data["F"]) + 1.22) ** 2
) ** 0.5 # Ic for soil behaviour type
sondering_data["peil"] = (
sondering_data["start_sondering_mtaw"] - sondering_data["lengte"]
) # absolute level
bovenpeil = (observatie_data['start_boring_mtaw'] - observatie_data["diepte_van_m"]).iloc[0] # extract boundaries of sample
onderpeil = (observatie_data['start_boring_mtaw'] - observatie_data["diepte_tot_m"]).iloc[0] # extract boundaries of sample
sondering_data_subset = sondering_data[
(sondering_data["peil"] <= bovenpeil) & (sondering_data["peil"] >= onderpeil)
] # define a subset with the CPT values at the depth of the sample
if sondering_data_subset.size == 0: # if this subset is empty just restart loop
continue
mean_values = sondering_data_subset.mean(numeric_only=True) # find mean
median_values = sondering_data_subset.median(numeric_only=True) # find median
if len(sondering_data_subset) > 1:
variance_values = (
sondering_data_subset.var(numeric_only=True)
) # find variance if there is more than one datapoint
else:
variance_values = pd.Series(
[0 for _ in sondering_data_subset.columns], index=sondering_data_subset.columns
) # if this in not the case put a 0 for variance
new_data = pd.DataFrame(index=observatie_data.index, data={
'pkey_observatie': observatie_data['pkey_observatie'].iloc[0],
"qc_avg": mean_values["qc"],
"fs_avg": mean_values["fs"],
"rf_avg": mean_values["rf"],
"Qtn_avg": mean_values["Qtn"],
"F_avg": mean_values["F"],
"IC_avg": mean_values["IC"],
"qc_med": median_values["qc"],
"fs_med": median_values["fs"],
"rf_med": median_values["rf"],
"Qtn_med": median_values["Qtn"],
"F_med": median_values["F"] ,
"qc_var": variance_values["qc"],
"fs_var": variance_values["fs"],
"rf_var": variance_values["rf"],
"Qtn_var": variance_values["Qtn"],
"F_var": variance_values["F"],
"IC_var": variance_values["IC"],
})
sonddata_df = pd.concat([sonddata_df, new_data], ignore_index=True)
sonddata_df
/tmp/ipykernel_69852/329157286.py:99: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.
sonddata_df = pd.concat([sonddata_df, new_data], ignore_index=True)
/home/roel/Work/DOV/pydov/Code/pydov/.venv/lib/python3.13/site-packages/pandas/core/arraylike.py:399: RuntimeWarning: invalid value encountered in log10
result = getattr(ufunc, method)(*inputs, **kwargs)
/home/roel/Work/DOV/pydov/Code/pydov/.venv/lib/python3.13/site-packages/pandas/core/arraylike.py:399: RuntimeWarning: invalid value encountered in log10
result = getattr(ufunc, method)(*inputs, **kwargs)
/home/roel/Work/DOV/pydov/Code/pydov/.venv/lib/python3.13/site-packages/pandas/core/arraylike.py:399: RuntimeWarning: invalid value encountered in log10
result = getattr(ufunc, method)(*inputs, **kwargs)
/home/roel/Work/DOV/pydov/Code/pydov/.venv/lib/python3.13/site-packages/pandas/core/arraylike.py:399: RuntimeWarning: invalid value encountered in log10
result = getattr(ufunc, method)(*inputs, **kwargs)
[16]:
| pkey_observatie | qc_avg | qc_med | qc_var | fs_avg | fs_med | fs_var | rf_avg | rf_med | rf_var | Qtn_avg | Qtn_med | Qtn_var | F_avg | F_med | F_var | IC_avg | IC_med | IC_var | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/observatie/... | 0.630200 | 0.620 | 0.002412 | 49.240000 | 49.0 | 11.773333 | 7.821904 | 7.894737 | 0.070205 | 4.740368 | 4.645491 | 0.205764 | 9.744119 | 9.866772 | 0.185043 | 3.562928 | NaN | 0.001710 |
| 1 | https://www.dov.vlaanderen.be/data/observatie/... | 1.212000 | 1.240 | 0.012442 | 103.760000 | 104.0 | 312.190000 | 8.503695 | 8.474576 | 0.671222 | 8.551131 | 8.765523 | 0.970369 | 9.653296 | 9.672040 | 0.662625 | 3.363599 | NaN | 0.000734 |
| 2 | https://www.dov.vlaanderen.be/data/observatie/... | 1.631667 | 1.670 | 0.013657 | 138.833333 | 141.5 | 42.166667 | 8.523800 | 8.476587 | 0.095081 | 9.730427 | 9.984077 | 0.642491 | 9.516977 | 9.431645 | 0.174604 | 3.316316 | NaN | 0.001501 |
| 3 | https://www.dov.vlaanderen.be/data/observatie/... | 1.020000 | 1.070 | 0.014900 | 111.240000 | 118.0 | 186.690000 | 10.905240 | 10.882353 | 0.117365 | 10.090128 | 10.621029 | 2.482326 | 12.843006 | 12.893282 | 0.240293 | 3.395762 | NaN | 0.003559 |
| 4 | https://www.dov.vlaanderen.be/data/observatie/... | 0.889080 | 0.849 | 0.028728 | 70.640000 | 63.5 | 296.439184 | 8.116217 | 8.372675 | 3.840904 | 7.685592 | 7.196305 | 2.940919 | 9.358642 | 9.794007 | 5.273899 | 3.384799 | NaN | 0.017229 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 191 | https://www.dov.vlaanderen.be/data/observatie/... | 1.056364 | 1.070 | 0.005745 | 84.545455 | 86.0 | 86.672727 | 7.991460 | 7.909091 | 0.241539 | 6.060677 | 6.180074 | 0.233525 | 9.421659 | 9.279148 | 0.320236 | 3.470083 | NaN | 0.000919 |
| 192 | https://www.dov.vlaanderen.be/data/observatie/... | 1.260000 | 1.220 | 0.039150 | 99.000000 | 101.0 | 68.500000 | 7.953141 | 8.362069 | 0.839800 | 19.887764 | 19.228392 | 9.879201 | 8.661825 | 9.146527 | 1.125909 | 3.061948 | NaN | 0.007006 |
| 193 | https://www.dov.vlaanderen.be/data/observatie/... | 0.830000 | 0.850 | 0.007775 | 66.666667 | 70.0 | 25.000000 | 8.062722 | 8.045977 | 0.193296 | 9.113621 | 9.487740 | 1.727365 | 9.800348 | 9.897149 | 0.522967 | 3.347741 | NaN | 0.004492 |
| 194 | https://www.dov.vlaanderen.be/data/observatie/... | 0.892222 | 0.880 | 0.002769 | 73.444444 | 76.0 | 139.277778 | 8.195528 | 8.351648 | 0.829784 | 6.439954 | 6.355233 | 0.323608 | 9.467302 | 9.621253 | 0.925751 | 3.450596 | NaN | 0.000276 |
| 195 | https://www.dov.vlaanderen.be/data/observatie/... | 0.484615 | 0.465 | 0.005818 | 46.423077 | 48.0 | 29.213846 | 9.680974 | 9.540169 | 1.152286 | 7.553400 | 7.324486 | 1.428584 | 11.281733 | 11.150253 | 1.955788 | 3.448938 | NaN | 0.006541 |
196 rows × 19 columns
The results are then merged with the source data of the observations, based on the pkey_observatie:
[17]:
merged_df = pd.merge(geo_df_observaties, sonddata_df, on='pkey_observatie') # join the two dataframes together
merged_df = merged_df.dropna(
subset=["Qtn_avg"]
) # drop all rows with nan values
merged_df
[17]:
| pkey_observatie | pkey_parent | fenomeentijd | diepte_van_m | diepte_tot_m | parametergroep | parameter | detectieconditie | resultaat | eenheid | ... | rf_var | Qtn_avg | Qtn_med | Qtn_var | F_avg | F_med | F_var | IC_avg | IC_med | IC_var | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2006-08-03 | 11.0 | 11.47 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 92.2 | % | ... | 0.445840 | 9.501619 | 9.433575 | 0.428062 | 9.610620 | 9.513810 | 0.625950 | 3.326070 | NaN | 0.001339 |
| 1 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2006-07-06 | 8.5 | 8.96 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 62.0 | % | ... | 0.495409 | 10.109567 | 9.796345 | 1.498985 | 9.975426 | 10.416742 | 0.750912 | 3.317791 | NaN | 0.003992 |
| 2 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-01-29 | 7.0 | 7.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 79.4 | % | ... | 1.376713 | 13.505217 | 12.992110 | 4.110502 | 8.358371 | 8.389959 | 1.720787 | 3.171420 | NaN | 0.008375 |
| 3 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-04-17 | 4.5 | 4.98 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 54.8 | % | ... | 0.237022 | 11.511098 | 11.103406 | 2.300224 | 10.365036 | 10.613481 | 0.421005 | 3.288280 | NaN | 0.002691 |
| 4 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/201... | 2007-02-28 | 8.0 | 8.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 87.6 | % | ... | 0.450051 | 8.659261 | 8.238914 | 1.503024 | 4.338650 | 4.028841 | 0.505988 | 3.141798 | NaN | 0.000813 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 191 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-14 | 6.5 | 7.00 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 95.7 | % | ... | 4.931109 | 23.646598 | 21.726537 | 26.986828 | 11.329137 | 11.034213 | 5.955055 | 3.091688 | NaN | 0.014351 |
| 192 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-20 | 7.5 | 7.90 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 97.8 | % | ... | 0.220248 | 8.106500 | 8.026561 | 0.220557 | 11.754576 | 11.861887 | 0.334535 | 3.435978 | NaN | 0.000856 |
| 193 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-03-21 | 9.5 | 10.00 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 67.4 | % | ... | 1.995651 | 7.533010 | 7.318299 | 0.667049 | 8.130456 | 7.378547 | 2.626026 | 3.353749 | NaN | 0.001325 |
| 194 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-08-29 | 9.0 | 9.50 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 81.7 | % | ... | 0.316637 | 5.595731 | 5.753455 | 0.606544 | 10.668221 | 10.502535 | 0.768665 | 3.532824 | NaN | 0.004671 |
| 195 | https://www.dov.vlaanderen.be/data/observatie/... | https://www.dov.vlaanderen.be/data/monster/202... | 2025-08-29 | 13.0 | 13.48 | Onderkenning - proeven | Gehalte Organische stoffen (Gehalte Organische... | NaN | 78.2 | % | ... | 0.107421 | 2.444450 | 2.327236 | 0.113523 | 3.110840 | 3.266407 | 0.348281 | 3.525596 | NaN | 0.007681 |
196 rows × 36 columns
Finally, we can display these results in a chart:
[18]:
# define boundaries for Roberson's graph and plot them
X1 = np.array(
[
-3,
-1,
-0.890243902439026,
-0.774390243902441,
-0.66158536585366,
-0.548780487804878,
-0.439024390243903,
-0.326219512195123,
-0.210365853658537,
-0.112804878048781,
-0.00609756097560987,
0.082317073170729,
0.161585365853658,
0.204268292682926,
0.225609756097559,
0.397940008672038,
0.52244423350632,
3,
]
)
Y1 = np.array(
[
1,
1,
0.998624484181568,
0.98624484181568,
0.961485557083906,
0.92847317744154,
0.878954607977991,
0.812929848693259,
0.726272352132049,
0.631361760660247,
0.50343878954608,
0.359009628610727,
0.189821182943603,
0.0784044016506188,
0,
-0.476892499139314,
-1,
-1,
]
)
X2 = np.array(
[
-3,
0.079181246,
0.131097560975609,
0.182926829268291,
0.246951219512193,
0.292682926829266,
0.335365853658536,
0.38109756097561,
0.445121951219511,
0.493902439024389,
0.551829268292683,
0.631097560975609,
0.740853658536585,
0.838414634146341,
0.984756097560975,
1.04878048780488,
1.17609125905568,
3,
]
)
Y2 = np.array(
[
4,
4,
3.03301237964236,
2.88445667125172,
2.72352132049518,
2.6079779917469,
2.50068775790921,
2.40165061898212,
2.26134800550206,
2.15405777166437,
2.04264099037139,
1.91884456671252,
1.82806052269601,
1.78266850068776,
1.75378266850069,
1.7455295735901,
1.74036268949424,
1.73639650227664,
]
)
X3 = np.array(
[
-3,
-2,
-1.04575749056068,
-0.522878745280338,
-0.0457574905606751,
0.216463414634144,
0.420731707317072,
0.594512195121951,
0.771341463414634,
0.887195121951219,
0.963414634146341,
0.996951219512195,
1.04139268515823,
1.11394335230684,
1.20411998265592,
1.252574989,
1.30102999566398,
1.47712125471966,
1.61172330800734,
3,
]
)
Y3 = np.array(
[
-0.107504662868674,
-0.107504662868674,
-0.099484807248056,
-0.0784326862439331,
-0.0182837690892966,
0.045392022008251,
0.15268225584594,
0.292984869325996,
0.491059147180191,
0.664374140302613,
0.808803301237964,
0.878954607977991,
0.994223003013752,
1.19471939352921,
1.49546397930239,
1.6959604,
1.8964567603333,
2.89893871291058,
4,
4,
]
)
X4 = np.array(
[
-3,
-2,
-1,
-0.522878745280338,
-0.301029995663981,
-0.140243902439025,
-0.0213414634146342,
0.128048780487803,
0.277439024390242,
0.378048780487804,
0.47560975609756,
0.570121951219511,
0.655487804878049,
0.71951219512195,
0.774390243902439,
0.845098040014257,
0.954242509439325,
1.07918124604762,
1.21218760440396,
3,
]
)
Y4 = np.array(
[
0.548714105446867,
0.548714105446867,
0.567812943589182,
0.610254806127659,
0.652696668666137,
0.664374140302613,
0.734525447042641,
0.837689133425034,
0.969738651994498,
1.08115543328748,
1.20082530949106,
1.34112792297111,
1.49793672627235,
1.63823933975241,
1.80742778541953,
2.03205720116665,
2.45647582655142,
3.09310376462857,
4,
4,
]
)
X5 = np.array(
[
-3,
-2,
-1.39794000867204,
-0.823908740944319,
-0.503048780487805,
-0.332317073170732,
-0.128048780487805,
0.0579268292682913,
0.222560975609754,
0.390243902439023,
0.506097560975609,
0.582317073170732,
0.643292682926829,
0.658536585365853,
0.673780487804877,
0.679878048780487,
0.700578048780487,
3,
]
)
Y5 = np.array(
[
0.793022628459515,
0.793022628459515,
0.803892063893693,
0.84374666048568,
0.907840440165061,
0.994497936726272,
1.11416781292985,
1.25034387895461,
1.40302613480055,
1.60522696011004,
1.79917469050894,
1.98899587345254,
2.30674002751032,
2.45116918844567,
2.69050894085282,
2.98762035763411,
4,
4,
]
)
X6 = np.array(
[
-3,
-2,
-1.39794000867204,
-1,
-0.771341463414636,
-0.533536585365855,
-0.283536585365854,
-0.0487804878048781,
0.164634146341461,
0.314024390243902,
0.393292682926828,
0.423780487804877,
0.544068044350276,
0.698970004336019,
0.807589142389764,
3,
]
)
Y6 = np.array(
[
1.39511433919444,
1.39511433919444,
1.4073041167125,
1.41953232462173,
1.4484181568088,
1.50206327372765,
1.62173314993122,
1.76342799356294,
1.97661623108666,
2.20357634112792,
2.36863823933975,
2.45942228335626,
2.81319179046214,
3.42268066636517,
4,
4,
]
)
X7 = np.array(
[
-3,
-2,
-1.52287874528034,
-1.15490195998574,
-1,
-0.786585365853661,
-0.588414634146342,
-0.39329268292683,
-0.219512195121951,
-0.076219512195122,
0.00609756097560594,
0.0304878048780472,
0.113943352306837,
0.204119982655925,
0.34409740359441,
3,
]
)
Y7 = np.array(
[
2.10124566205107,
2.10124566205107,
2.11851911705649,
2.15306602706735,
2.17881705639615,
2.22833562585969,
2.3191196698762,
2.45116918844567,
2.6162310866575,
2.8101788170564,
2.97111416781293,
3.03301237964236,
3.21538350990112,
3.47448533498253,
4,
4,
]
)
Y8 = np.array(
[
1,
1.236584507,
1.467593452,
1.641390069,
2.00087167,
2.561283296,
3.04027751,
3.864751926,
4.513435735,
5.329418952,
5.737406993,
6.934489818,
7.871627474,
9.405725877,
10.71461614,
13.26504071,
14.33512247,
16.67039577,
17.48101531,
20.73321573,
25.76980375,
30.8239924,
]
)
X8 = np.array(
[
5.218732546,
5.224237832,
5.235265833,
5.251851499,
5.290756014,
5.324332041,
5.358121147,
5.420625748,
5.45502595,
5.559541963,
5.61254852,
5.885259102,
6.145248773,
6.512143221,
6.934981111,
7.811089495,
8.281805716,
9.300236388,
9.731586954,
11.63135731,
15.24313395,
19.81818615,
]
)
Y9 = np.array(
[
1,
1.24570471,
1.457672448,
1.734757,
2.022753999,
2.244335431,
2.546558574,
2.887030331,
3.29529913,
4.377751156,
5.390771626,
5.982484067,
7.152449831,
7.972379175,
9.518039505,
10.38663667,
11.63636757,
12.44098606,
13.1809551,
14.21891386,
15.08325454,
16.11449903,
16.95549455,
19.15734093,
20.67643722,
22.67543126,
25.76980375,
31.22082999,
]
)
X9 = np.array(
[
2.359210475,
2.381703987,
2.412029295,
2.450479487,
2.481680486,
2.521240988,
2.572257547,
2.660524333,
2.751819986,
3.00507027,
3.314662302,
3.499621817,
3.91963219,
4.195462425,
4.867922672,
5.240788561,
5.866673096,
6.2441507,
6.626424983,
7.192139126,
7.700695838,
8.334363447,
8.93498453,
10.23676764,
11.22018726,
12.69483156,
15.00257488,
19.66118419,
]
)
Y10 = np.array(
[
1,
1.490163293,
1.722664767,
1.902319213,
2.331621252,
2.669482766,
2.950129966,
3.29529913,
3.574741878,
3.924187211,
4.578962969,
4.912810557,
5.593309253,
6.119288823,
6.644642623,
7.023246768,
7.361639679,
8.081269437,
8.575422275,
10.30942724,
11.15336857,
12.18152662,
12.75222616,
13.7914596,
14.48171973,
15.39332793,
16.55068513,
17.67101739,
18.40892945,
20.02936469,
21.64511984,
22.72845428,
23.96333726,
25.50421875,
27.14418142,
28.48824655,
30.28155009,
]
)
X10 = np.array(
[
0.695855433,
0.743646766,
0.788045272,
0.821991165,
0.916285475,
0.991683911,
1.058117967,
1.143377667,
1.221904814,
1.336468837,
1.518324783,
1.624314987,
1.896625055,
2.063542636,
2.279566394,
2.419670763,
2.561432124,
2.846248441,
3.057806323,
3.908489836,
4.312064256,
4.914335096,
5.169445303,
5.837057497,
6.223493829,
6.785502665,
7.532065355,
8.288357264,
8.822649179,
9.933738163,
11.18475323,
12.03638898,
13.01858971,
14.26925174,
15.81417007,
16.90919862,
18.5825382,
]
)
plt.plot(
10**X1, 10**Y1, color="grey", linestyle="-", linewidth=1, label="Robertson's zones"
)
plt.plot(10**X2, 10**Y2, color="grey", linestyle="-", linewidth=1)
plt.plot(10 ** X3[5:16], 10 ** Y3[5:16], color="grey", linestyle="-", linewidth=1)
plt.plot(10 ** X4[5:15], 10 ** Y4[5:15], color="grey", linestyle="-", linewidth=1)
plt.plot(10 ** X5[4:17], 10 ** Y5[4:17], color="grey", linestyle="-", linewidth=1)
plt.plot(10 ** X6[0:11], 10 ** Y6[0:11], color="grey", linestyle="-", linewidth=1)
plt.plot(10 ** X7[0:13], 10 ** Y7[0:13], color="grey", linestyle="-", linewidth=1)
plt.plot(
X8,
Y8,
color="red",
linestyle="-",
linewidth=1,
label="Possibly peat / Possibly clay",
)
# plt.plot(X9,Y9, color='black',linestyle='-', linewidth=1, label="Lengkeek & Brinkgreve zone 2B")
plt.plot(
X10,
Y10,
color="purple",
linestyle="-",
linewidth=1,
label="Possibly slightly peaty clay / Possibly clay",
)
# Customize the plot
plt.title("Robertson's Soil Identification Chart")
plt.xlabel("F")
plt.ylabel("Qtn")
plt.grid(True)
plt.xscale("log")
plt.yscale("log")
# Set custom x and y axis labels
x_labels = [0.1, 0.5, 1, 5, 10, 50, 100, 500, 1000]
y_labels = [0.1, 0.5, 1, 5, 10, 50, 100, 500, 1000]
plt.xticks(x_labels)
plt.yticks(y_labels)
plt.xlim([0.1, 15])
plt.ylim([1, 1000])
# Average values from your DataFrame (replace with your actual values)
avg_Qtn = merged_df["Qtn_avg"]
avg_F = merged_df["F_avg"]
# just plot the dots
plt.scatter(avg_F, avg_Qtn, label="Pydov_data")
plt.legend()
[18]:
<matplotlib.legend.Legend at 0x7fd81ba627b0>