<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Example of DOV search methods for interpretations (geotechnische codering)
Use cases explained below
Get 'geotechnische codering' in a bounding box
Get 'geotechnische codering' with specific properties within a distance from a point
Get 'geotechnische codering' in a bounding box with specific properties
Get 'geotechnische codering' based on fields not available in the standard output dataframe
Get 'geotechnische codering' data, returning fields not available in the standard output dataframe
Step1:  Get information about the datatype 'Geotecnische codering'
Step2:  A description is provided for the 'Geotechnische codering' datatype
Step3:  The different fields that are available for objects of the 'Geotechnische codering' datatype can be requested with the get_fields() method
Step4:  You can get more information of a field by requesting it from the fields dictionary
Step5:  Example use cases
Get 'Geotechnische codering' in a bounding box
Get data for all the 'Geotechnische codering' interpretations that are geographically located within the bounds of the specified box.
The coordinates are in the Belgian Lambert72 (EPSG
Step6:  The dataframe contains one 'Geotechnische codering' interpretation where ten layers ('laag') were identified. The available data are flattened to represent unique attributes per row of the dataframe.
Using the pkey_interpretatie field one can request the details of this interpretation in a webbrowser
Step7:  Get 'Geotechnische codering' with specific properties within a distance from a point
Next to querying interpretations based on their geographic location within a bounding box, we can also search for interpretations matching a specific set of properties. For this we can build a query using a combination of the 'Geotechnische codering' fields and operators provided by the WFS protocol.
A list of possible operators can be found below
Step8:  In this example we build a query using the PropertyIsGreaterThan and PropertyIsEqualTo operators to find all interpretations that are at least 20 m deep, that are deemed appropriate for a range of 1 km from a defined point
Step9:  Once again we can use the pkey_interpretatie as a permanent link to the information of these interpretations
Step10:  Get 'Geotechnische codering' in a bounding box based on specific properties
We can combine a query on attributes with a query on geographic location to get the interpretations within a bounding box that have specific properties.
The following example requests the interpretations of boreholes only, within the given bounding box.
(Note that the datatype of the literal parameter should be a string, regardless of the datatype of this field in the output dataframe.)
Step11:  We can look at one of the interpretations in a webbrowser using its pkey_interpretatie
Step12:  Get 'Geotechnische codering' based on fields not available in the standard output dataframe
To keep the output dataframe size acceptable, not all available WFS fields are included in the standard output. However, one can use this information to select interpretations as illustrated below.
For example, make a selection of the interpretations in municipality the of Antwerp, before 1/1/1990
Step13:  Get 'Geotechnische codering' data, returning fields not available in the standard output dataframe
As denoted in the previous example, not all available fields are available in the default output frame to keep its size limited. However, you can request any available field by including it in the return_fields parameter of the search
Step14:  Visualize results
Using Folium, we can display the results of our search on a map.
<ASSISTANT_TASK:>
Python Code:
%matplotlib inline
import inspect, sys
# check pydov path
import pydov
Explanation: Example of DOV search methods for interpretations (geotechnische codering)
Use cases explained below
Get 'geotechnische codering' in a bounding box
Get 'geotechnische codering' with specific properties within a distance from a point
Get 'geotechnische codering' in a bounding box with specific properties
Get 'geotechnische codering' based on fields not available in the standard output dataframe
Get 'geotechnische codering' data, returning fields not available in the standard output dataframe
End of explanation
from pydov.search.interpretaties import GeotechnischeCoderingSearch
itp = GeotechnischeCoderingSearch()
Explanation: Get information about the datatype 'Geotecnische codering'
End of explanation
itp.get_description()
Explanation: A description is provided for the 'Geotechnische codering' datatype:
End of explanation
fields = itp.get_fields()
# print available fields
for f in fields.values():
    print(f['name'])
Explanation: The different fields that are available for objects of the 'Geotechnische codering' datatype can be requested with the get_fields() method:
End of explanation
fields['Datum']
Explanation: 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
End of explanation
from pydov.util.location import Within, Box
df = itp.search(location=Within(Box(108281, 197850, 108282, 197851)))
df.head()
Explanation: Example use cases
Get 'Geotechnische codering' in a bounding box
Get data for all the 'Geotechnische codering' interpretations 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.
End of explanation
for pkey_interpretatie in set(df.pkey_interpretatie):
    print(pkey_interpretatie)
Explanation: The dataframe contains one 'Geotechnische codering' interpretation where ten layers ('laag') were identified. The available data are flattened to represent unique attributes per row of the dataframe.
Using the pkey_interpretatie field one can request the details of this interpretation in a webbrowser:
End of explanation
[i for i,j in inspect.getmembers(sys.modules['owslib.fes'], inspect.isclass) if 'Property' in i]
Explanation: Get 'Geotechnische codering' with specific properties within a distance from a point
Next to querying interpretations based on their geographic location within a bounding box, we can also search for interpretations matching a specific set of properties. For this we can build a query using a combination of the 'Geotechnische codering' fields and operators provided by the WFS protocol.
A list of possible operators can be found below:
End of explanation
from owslib.fes import And, PropertyIsGreaterThan, PropertyIsEqualTo
from pydov.util.location import WithinDistance, Point
query = And([PropertyIsEqualTo(propertyname='Betrouwbaarheid',
                              literal='goed'),
            PropertyIsGreaterThan(propertyname='diepte_tot_m',
                                 literal='20'),
           ])
            
df = itp.search(query=query, 
                location=WithinDistance(Point(153145, 206930), 1000))
df.head()
Explanation: In this example we build a query using the PropertyIsGreaterThan and PropertyIsEqualTo operators to find all interpretations that are at least 20 m deep, that are deemed appropriate for a range of 1 km from a defined point:
End of explanation
for pkey_interpretatie in set(df.pkey_interpretatie):
    print(pkey_interpretatie)
Explanation: Once again we can use the pkey_interpretatie as a permanent link to the information of these interpretations:
End of explanation
from owslib.fes import PropertyIsEqualTo
query = PropertyIsEqualTo(
            propertyname='Type_proef',
            literal='Boring')
df = itp.search(
    location=Within(Box(153145, 206930, 154145, 207930)),
    query=query
    )
df.head()
Explanation: Get 'Geotechnische codering' in a bounding box based on specific properties
We can combine a query on attributes with a query on geographic location to get the interpretations within a bounding box that have specific properties.
The following example requests the interpretations of boreholes only, within the given bounding box.
(Note that the datatype of the literal parameter should be a string, regardless of the datatype of this field in the output dataframe.)
End of explanation
for pkey_interpretatie in set(df.pkey_interpretatie):
    print(pkey_interpretatie)
Explanation: We can look at one of the interpretations in a webbrowser using its pkey_interpretatie:
End of explanation
from owslib.fes import And, PropertyIsEqualTo, PropertyIsLessThan
query = And([PropertyIsEqualTo(propertyname='gemeente',
                               literal='Antwerpen'),
             PropertyIsLessThan(propertyname='Datum', 
                                 literal='2010-01-01')]
            )
df = itp.search(query=query,
                return_fields=('pkey_interpretatie', 'Datum'))
df.head()
Explanation: Get 'Geotechnische codering' based on fields not available in the standard output dataframe
To keep the output dataframe size acceptable, not all available WFS fields are included in the standard output. However, one can use this information to select interpretations as illustrated below.
For example, make a selection of the interpretations in municipality the of Antwerp, before 1/1/1990:
!remark: mind that the municipality attribute is merely an attribute that is defined by the person entering the data. It can be ok, empty, outdated or wrong!
End of explanation
query = PropertyIsEqualTo(
            propertyname='gemeente',
            literal='Leuven')
df = itp.search(query=query,
                return_fields=('pkey_interpretatie', 'pkey_boring',
                               'x', 'y', 'Z_mTAW', 'gemeente', 'Auteurs', 'Proefnummer'))
df.head()
Explanation: Get 'Geotechnische codering' data, returning fields not available in the standard output dataframe
As denoted in the previous example, not all available fields are available in the default output frame to keep its size limited. However, you can request any available field by including it in the return_fields parameter of the search:
End of explanation
# import the necessary modules (not included in the requirements of pydov!)
import folium
from folium.plugins import MarkerCluster
from pyproj import Transformer
# 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['lon'], df['lat'] = zip(*map(convert_latlon, df['x'], df['y'])) 
# convert to list
loclist = df[['lat', 'lon']].values.tolist()
# initialize the Folium map on the centre of the selected locations, play with the zoom until ok
fmap = folium.Map(location=[df['lat'].mean(), df['lon'].mean()], zoom_start=12)
marker_cluster = MarkerCluster().add_to(fmap)
for loc in range(0, len(loclist)):
    folium.Marker(loclist[loc], popup=df['Proefnummer'][loc]).add_to(marker_cluster)
fmap
Explanation: Visualize results
Using Folium, we can display the results of our search on a map.
End of explanation
<END_TASK>