1616app = marimo .App (width = "medium" )
1717
1818
19+ @app .cell
20+ def _ ():
21+ import datetime
22+ import json
23+ import xml .dom .minidom as minidom
24+ from io import BytesIO
25+ from urllib .request import Request , urlopen
26+
27+ import folium
28+ import geopandas as gpd
29+ import marimo as mo
30+ import xmltodict
31+ from folium .plugins import Draw
32+ from lxml import etree
33+ from pygef import read_cpt
34+ from pygef .plotting import plot_cpt
35+
36+ cwd = mo .notebook_location ()
37+ return (
38+ BytesIO ,
39+ Draw ,
40+ Request ,
41+ datetime ,
42+ etree ,
43+ folium ,
44+ gpd ,
45+ json ,
46+ minidom ,
47+ mo ,
48+ plot_cpt ,
49+ read_cpt ,
50+ urlopen ,
51+ xmltodict ,
52+ )
53+
54+
1955@app .cell
2056def _ (mo ):
2157 mo .md (
@@ -28,47 +64,196 @@ def _(mo):
2864 2. [REST](https://www.bro-productomgeving.nl/bpo/latest/url-s-publieke-rest-services)
2965 1. CPT: <https://publiek.broservices.nl/sr/cpt/v1>
3066 2. Goetechnical boreholes: <https://publiek.broservices.nl/sr/bhrgt/v2>
31- 3. [PDOK](https://app.pdok.nl/viewer) - WMS
32-
67+ 3. [PDOK](https://app.pdok.nl/viewer)
68+ 1. WMS - This is useful for quickly viewing the location of historic CPTs or geotechnical boreholes.
69+ 2. ATOM feed - For downloading the whole dataset, i.e. to download all CPTs or all geotechnical boreholes in BRO.
3370 """
3471 )
3572 return
3673
3774
75+ @app .cell (hide_code = True )
76+ def _ (Draw , buffer , folium , geojson_text_area , gpd , json , site_geojson ):
77+ geojson = geojson_text_area .value if geojson_text_area .value else site_geojson
78+ # Create a folium interactive map (leaflet.js maps)
79+ site = gpd .GeoDataFrame .from_features (
80+ {
81+ "type" : "FeatureCollection" ,
82+ "name" : "site" ,
83+ "features" : [json .loads (geojson )],
84+ },
85+ crs = 4326 ,
86+ ).to_crs (28992 )
87+ buffered_site = site .geometry .buffer (buffer .value )
88+ bounds = buffered_site .to_crs (4326 ).bounds .to_numpy ()[0 ]
89+ folium_map = buffered_site .explore (
90+ tiles = "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}" ,
91+ style_kwds = {"fillOpacity" : 0.1 },
92+ attr = ("Esri.WorldStreetMap" ),
93+ )
94+ site .explore (m = folium_map , color = "red" , style_kwds = {"fill" : False })
95+ folium .Rectangle (
96+ bounds = [[bounds [1 ], bounds [0 ]], [bounds [3 ], bounds [2 ]]],
97+ color = "black" ,
98+ weight = 0.5 ,
99+ ).add_to (folium_map )
100+
101+ # Add PDOK's CPT WMS layer
102+ folium .WmsTileLayer (
103+ url = "https://service.pdok.nl/bzk/geologie/bro-geotechnisch-sondeeronderzoek/wms/v1_0?request=GetCapabilities&service=WMS" ,
104+ name = "BRO CPT" ,
105+ fmt = "image/png" ,
106+ layers = "GE.conePenetrationTest" ,
107+ transparent = True ,
108+ ).add_to (folium_map )
109+
110+ # Add PDOK's geotechnical borehole WMS layer
111+ folium .WmsTileLayer (
112+ url = "https://service.pdok.nl/bzk/geologie/bro-geotechnisch-booronderzoek/wms/v1_0?request=getcapabilities&service=wms" ,
113+ name = "BRO BHR-GT" ,
114+ fmt = "image/png" ,
115+ layers = "GE.Borehole" ,
116+ transparent = True ,
117+ ).add_to (folium_map )
118+
119+ # Add drawing widget
120+ draw = Draw (
121+ export = True ,
122+ filename = "site.geojson" ,
123+ position = "topleft" ,
124+ draw_options = {
125+ "polyline" : True ,
126+ "polygon" : True ,
127+ "circle" : False ,
128+ "rectangle" : False ,
129+ "marker" : True ,
130+ "circlemarker" : False ,
131+ },
132+ ).add_to (folium_map )
133+
134+ folium_map
135+ return (bounds ,)
136+
137+
38138@app .cell
39139def _ (mo ):
40- cwd = mo .notebook_location ()
41- return (cwd ,)
140+ site_geojson = '{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[4.902889698063478,52.385435257999404],[4.902923632305726,52.385509906165986],[4.902901716440955,52.385619936470341],[4.903006347021203,52.38569026942325],[4.90389499998988,52.385854235381281],[4.904091535809526,52.385902562073795],[4.904285950739031,52.385988859607401],[4.904484607448818,52.38602683046868],[4.904532680958658,52.386042363993511],[4.904790722592364,52.386094573856099],[4.904799206152918,52.386073862513044],[4.904974533071164,52.386108812898868],[4.904999276789463,52.386100183176488],[4.905287541107636,52.385853480276289],[4.903576336246269,52.385074312916224],[4.903554420381488,52.385093082996256],[4.903498923756159,52.38509416173622],[4.903484784488561,52.385100202679702],[4.903473119592793,52.385110990076754],[4.903287895187223,52.385027927051986],[4.903256788798504,52.38504302943177],[4.903150390809821,52.38513472234078],[4.903119637902792,52.385127171167227],[4.903098782483085,52.38514421524286],[4.903084996697174,52.385139037296511],[4.90302349088312,52.385198152147602],[4.902889698063478,52.385435257999404]]]}}'
141+ geojson_text_area = mo .ui .text_area (
142+ placeholder = "1. Draw a shape on the map.\n 2. Click it.\n 3. Copy the GeoJSON from the pop-up.\n 4. Paste GeoJSON here." ,
143+ debounce = 5 ,
144+ full_width = True ,
145+ )
146+ buffer = mo .ui .slider (start = 0 , stop = 200 , label = "Buffer" , value = 100 , step = 10 )
147+ mo .hstack (
148+ [geojson_text_area , buffer ],
149+ widths = [1 , 0 ],
150+ )
151+ return buffer , geojson_text_area , site_geojson
42152
43153
44154@app .cell
45- def _ (cwd , gpd ):
46- site_plot = gpd .read_file (cwd / "context.gpkg" )
47- site_plot .explore ()
155+ def _ (buffer ):
156+ # EPSG:4258 is the European Terrestrial Reference System 1989 (ETR)
157+ # ETR89 coordinates are in [Longitude (x), Latitude (y)]
158+ lonlat_bounds = buffer .to_crs (4258 ).bounds
159+ lonlat_bounds
48160 return
49161
50162
51163@app .cell
52- def _ (cwd , read_cpt ):
53- cpt_data = read_cpt (cwd / "data" / "CPT000000061548.xml" )
54- cpt_data .data
55- return (cpt_data ,)
164+ def _ (Request , bounds , datetime , json , minidom , mo , urlopen , xmltodict ):
165+ cpt_search_url = "https://publiek.broservices.nl/sr/cpt/v1/characteristics/searches"
166+ api_request_data = json .dumps (
167+ {
168+ "registrationPeriod" : {
169+ "beginDate" : "2017-01-01" ,
170+ "endDate" : datetime .date .today ().isoformat (),
171+ },
172+ "area" : {
173+ "boundingBox" : {
174+ "lowerCorner" : {
175+ "lon" : bounds [0 ],
176+ "lat" : bounds [1 ],
177+ },
178+ "upperCorner" : {
179+ "lon" : bounds [2 ],
180+ "lat" : bounds [3 ],
181+ },
182+ }
183+ },
184+ }
185+ ).encode ("utf-8" )
186+
187+ cpt_search_req = Request (
188+ cpt_search_url ,
189+ data = api_request_data ,
190+ headers = {"Content-Type" : "application/json" },
191+ method = "POST" ,
192+ )
193+ with urlopen (cpt_search_req , timeout = 30 ) as cpt_search_resp :
194+ xml = cpt_search_resp .read ()
195+
196+ cpt_search = xmltodict .parse (
197+ xml ,
198+ xml_attribs = False ,
199+ process_namespaces = True ,
200+ namespaces = {
201+ "http://www.broservices.nl/xsd/dscpt/1.1" : None ,
202+ "http://www.broservices.nl/xsd/brocommon/3.0" : None ,
203+ },
204+ )
205+
206+ tabs = mo .ui .tabs (
207+ {
208+ "XML" : mo .md (
209+ f"```xml\n { minidom .parseString (xml ).toprettyxml (indent = ' ' )} \n ```"
210+ ),
211+ "JSON" : xmltodict .parse (xml ),
212+ "JSON, no XML attributes" : cpt_search ,
213+ }
214+ )
215+
216+ tabs
217+ return
218+
219+
220+ app ._unparsable_cell (
221+ r"""
222+ for cpt in cpt_search
223+ """ ,
224+ name = "_" ,
225+ )
56226
57227
58228@app .cell
59- def _ (cpt_data , plot_cpt ):
60- plot_cpt (cpt_data )
229+ def _ (Request , etree , urlopen ):
230+ cpt_get_url = "https://publiek.broservices.nl/sr/cpt/v1/objects/CPT000000198164"
231+ cpt_get_req = Request (cpt_get_url , method = "GET" )
232+ with urlopen (cpt_get_req , timeout = 30 ) as resp :
233+ cpt_str = resp .read ()
234+ cpt_xml = etree .fromstring (cpt_str )
235+
236+ print (etree .tostring (cpt_xml , pretty_print = True , encoding = "unicode" ))
237+ return (cpt_str ,)
238+
239+
240+ @app .cell
241+ def _ (cpt_str ):
242+ cpt_str
61243 return
62244
63245
64246@app .cell
65- def _ ():
66- import geopandas as gpd
67- import marimo as mo
68- from pygef import read_cpt
69- from pygef . plotting import plot_cpt
247+ def _ (BytesIO , cpt_str , read_cpt ):
248+ cpt_data = read_cpt ( BytesIO ( cpt_str ))
249+ cpt_data . __dict__
250+ return ( cpt_data ,)
251+
70252
71- return gpd , mo , plot_cpt , read_cpt
253+ @app .cell
254+ def _ (cpt_data , plot_cpt ):
255+ plot_cpt (cpt_data )
256+ return
72257
73258
74259if __name__ == "__main__" :
0 commit comments