import%20marimo%0A%0A__generated_with%20%3D%20%220.23.13%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20OSM%20Network%20from%20a%20Boundary%20File%0A%0A%20%20%20%20Use%20a%20custom%20boundary%20file%20to%20create%20a%20%60networkx%60%20graph%20from%20OSM.%0A%0A%20%20%20%20If%20you%20have%20a%20boundary%20file%20in%20a%20GeoPackage%2C%20shapefile%2C%20or%20similar%20format%2C%20then%20you%20can%20load%20this%20file%20and%20use%20it%20as%20the%20boundary%20for%20creating%20a%20network%20from%20OSM.%0A%0A%20%20%20%20Network%20data%20%C2%A9%20%5BOpenStreetMap%5D(https%3A%2F%2Fwww.openstreetmap.org%2Fcopyright)%20contributors%2C%20available%20under%20the%20Open%20Database%20Licence.%0A%0A%20%20%20%20The%20bundled%20datasets%20and%20their%20source%20attributions%20are%20documented%20on%20the%20%5Bdatasets%20page%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples%2Fdatasets).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20geopandas%20as%20gpd%0A%20%20%20%20from%20cityseer.tools%20import%20io%2C%20plot%0A%0A%20%20%20%20return%20gpd%2C%20io%2C%20plot%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Use%20%60geopandas%60%20to%20load%20the%20boundary%20file.%20Check%20that%20your%20file%20path%20is%20correct!%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(gpd)%3A%0A%20%20%20%20bounds_gpd%20%3D%20gpd.read_file(%22..%2F..%2Fdata%2Fmadrid_nbhds%2Fmadrid_nbhds.gpkg%22)%0A%20%20%20%20bounds_gpd%0A%20%20%20%20return%20(bounds_gpd%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Extract%20the%20EPSG%20code%20from%20the%20boundary%20file.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bounds_gpd)%3A%0A%20%20%20%20epsg_code%20%3D%20bounds_gpd.crs.to_epsg()%0A%20%20%20%20print(epsg_code)%0A%20%20%20%20print(bounds_gpd.crs.is_projected)%0A%20%20%20%20return%20(epsg_code%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20If%20the%20geometry%20is%20not%20in%20a%20projected%20coordinate%20system%2C%20reproject%20it%20to%20a%20locally%20projected%20coordinate%20system%20before%20doing%20buffering%20or%20simplification.%20This%20can%20be%20done%20with%20the%20built-in%20%60to_crs%60%20method%20in%20%60geopandas%60.%20The%20EPSG%20code%20for%20the%20UTM%20zone%20can%20be%20found%20at%20%5Bepsg.io%5D(https%3A%2F%2Fepsg.io%2F).%20For%20example%2C%20if%20your%20boundary%20is%20in%20the%20UTM%20zone%2030N%2C%20you%20can%20use%20code%2032630.%0A%0A%20%20%20%20For%20the%20currently%20opened%20file%2C%20the%20boundary%20is%20already%20in%20a%20projected%20coordinate%20system%2C%20so%20this%20step%20is%20unnecessary.%20When%20working%20with%20a%20file%20that%20does%20need%20to%20be%20reprojected%2C%20use%20the%20following%20code%20to%20project%20to%20a%20given%20EPSG%20code.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bounds_gpd%2C%20epsg_code)%3A%0A%20%20%20%20%23%20shown%20as%20example%20-%20unnecessary%20step%20for%20current%20dataset%0A%20%20%20%20bounds_gpd_1%20%3D%20bounds_gpd.to_crs(epsg%3D25830)%0A%20%20%20%20print(epsg_code)%0A%20%20%20%20print(bounds_gpd_1.crs.is_projected)%0A%20%20%20%20return%20(bounds_gpd_1%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Convert%20the%20%60GeoDataFrame%60%20into%20a%20Polygon%20using%20the%20%60geopandas%60%20%60union_all%60%20method.%20This%20will%20create%20a%20single%20unified%20%60shapely%60%20geometry.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bounds_gpd_1)%3A%0A%20%20%20%20centro_gpd%20%3D%20bounds_gpd_1%5Bbounds_gpd_1%5B%22NOMDIS%22%5D%20%3D%3D%20%22Centro%22%5D%0A%20%20%20%20bounds_geom%20%3D%20centro_gpd.union_all()%0A%20%20%20%20bounds_geom%0A%20%20%20%20return%20bounds_geom%2C%20centro_gpd%0A%0A%0A%40app.cell%0Adef%20_(centro_gpd)%3A%0A%20%20%20%20centro_gpd%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20If%20the%20geometries%20are%20complex%2C%20then%20the%20OSM%20data%20request%20may%20fail%20due%20to%20URL%20length%20limitations%20(because%20each%20coordinate%20has%20to%20be%20passed%20in%20the%20URL).%20To%20avoid%20this%2C%20you%20can%20use%20the%20%60convex_hull%60%20or%20else%20the%20%60simplify%60%20method%20to%20reduce%20the%20number%20of%20points%20in%20the%20geometry.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bounds_geom)%3A%0A%20%20%20%20bounds_geom_simpl%20%3D%20bounds_geom.convex_hull%0A%20%20%20%20bounds_geom_simpl%0A%20%20%20%20return%20(bounds_geom_simpl%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20It%20is%20best%20practice%20to%20buffer%20the%20geometry%20by%20an%20amount%20matching%20the%20farthest%20distance%20used%20for%20centrality%20or%20accessibility%20calculations%2C%20which%20prevents%20edge%20rolloff%20effects.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bounds_geom_simpl)%3A%0A%20%20%20%20bounds_geom_buff%20%3D%20bounds_geom_simpl.buffer(800)%0A%20%20%20%20bounds_geom_buff%0A%20%20%20%20return%20(bounds_geom_buff%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20%60shapely%60%20Polygon%20can%20now%20be%20used%20as%20before%20to%20download%20and%20prepare%20an%20OSM%20graph.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bounds_geom_buff%2C%20epsg_code%2C%20io)%3A%0A%20%20%20%20G%20%3D%20io.osm_graph_from_poly(%0A%20%20%20%20%20%20%20%20bounds_geom_buff%2C%0A%20%20%20%20%20%20%20%20poly_crs_code%3Depsg_code%2C%0A%20%20%20%20%20%20%20%20simplify%3DTrue%2C%0A%20%20%20%20)%0A%20%20%20%20print(G)%0A%20%20%20%20return%20(G%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Setting%20the%20%60x_lim%60%20and%20%60y_lim%60%20extents%20will%20effectively%20zoom-in%20so%20that%20the%20results%20of%20the%20query%20can%20be%20seen%20more%20clearly.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(G%2C%20plot)%3A%0A%20%20%20%20plot.plot_nx(%0A%20%20%20%20%20%20%20%20G%2C%0A%20%20%20%20%20%20%20%20plot_geoms%3DTrue%2C%0A%20%20%20%20%20%20%20%20x_lim%3D(439500%2C%20439500%20%2B%202000)%2C%0A%20%20%20%20%20%20%20%20y_lim%3D(4473500%2C%204473500%20%2B%202000)%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Conclusion%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20This%20notebook%20demonstrated%20how%20to%20load%20a%20custom%20boundary%20file%20(e.g.%20GeoPackage%20or%20shapefile)%20with%20%60geopandas%60%2C%20prepare%20the%20geometry%20through%20union%2C%20simplification%2C%20and%20buffering%2C%20and%20then%20use%20it%20to%20download%20and%20create%20an%20OSM%20street%20network%20graph.%20Buffering%20the%20boundary%20by%20the%20analysis%20distance%20is%20recommended%20to%20prevent%20edge%20rolloff%20effects%20in%20subsequent%20centrality%20or%20accessibility%20calculations.%0A%0A%20%20%20%20To%20continue%20into%20analysis%2C%20hand%20the%20prepared%20graph%20to%20the%20high-level%20API%20with%20%5B%60CityNetwork.from_nx%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fapi%2Fnetwork%23from_nx)%2C%20which%20builds%20the%20dual%20network%20and%20exposes%20the%20centrality%20and%20land-use%20methods.%0A%0A%20%20%20%20**Next%20steps%3A**%20To%20use%20an%20OSM%20relation%20ID%20instead%2C%20see%20%5BRelation%20ID%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples%2Fnetworks%2Fnetwork-from-relation-id).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
78eccc4a1083de9c19c4448433a28ce9