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%20Boundaries%20and%20Live%20Nodes%0A%0A%20%20%20%20Use%20a%20boundary%20polygon%20to%20demarcate%20the%20study%20area%20from%20the%20buffered%20surrounding%20extents%20that%20are%20included%20to%20avoid%20edge%20rolloff.%20The%20algorithms%20continue%20to%20route%20through%20the%20parts%20of%20the%20network%20outside%20the%20boundary%20(thereby%20preventing%20edge%20rolloff)%2C%20but%20results%20are%20only%20reported%20for%20nodes%20inside%20it.%0A%0A%20%20%20%20The%20high-level%20%5B%60CityNetwork%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fapi%2Fnetwork)%20class%20provides%20the%20%5B%60set_boundary%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fapi%2Fnetwork%23set_boundary)%20method%20for%20this%20purpose.%20Under%20the%20hood%20it%20sets%20a%20%60live%60%20attribute%20per%20node%3A%20nodes%20inside%20the%20boundary%20are%20%60live%3DTrue%60%20and%20reported%3B%20nodes%20outside%20are%20%60live%3DFalse%60%20and%20used%20for%20routing%20only.%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%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%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20from%20cityseer.network%20import%20CityNetwork%0A%20%20%20%20from%20cityseer.tools%20import%20io%0A%0A%20%20%20%20return%20CityNetwork%2C%20io%2C%20plt%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%20When%20using%20this%20approach%20it%20is%20best%20to%20work%20in%20a%20projected%20coordinate%20reference%20system.%20In%20this%20example%20the%20buffered%20point%20polygon%20is%20cast%20to%20a%20projected%20CRS%20by%20using%20the%20%60projected%3DTrue%60%20parameter.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(io)%3A%0A%20%20%20%20lng%2C%20lat%20%3D%20-0.13396079424572427%2C%2051.51371088849723%0A%20%20%20%20buffer%20%3D%20500%0A%20%20%20%20poly_utm%2C%20epsg_code%20%3D%20io.buffered_point_poly(lng%2C%20lat%2C%20buffer%2C%20projected%3DTrue)%0A%20%20%20%20poly_utm%0A%20%20%20%20return%20epsg_code%2C%20poly_utm%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%20Since%20the%20Polygon%20is%20in%20a%20projected%20CRS%2C%20the%20buffering%20step%20can%20proceed%20with%20a%20distance%20defined%20in%20metres.%20Here%20the%20Polygon%20is%20buffered%20by%20400m%20since%20this%20is%20the%20maximum%20distance%20considered%20for%20the%20centrality%20analysis%20in%20the%20next%20step.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(poly_utm)%3A%0A%20%20%20%20pol_buff%20%3D%20poly_utm.buffer(400)%0A%20%20%20%20pol_buff%0A%20%20%20%20return%20(pol_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%20buffer%20polygon%20can%20then%20be%20used%20as%20an%20argument%20for%20retrieving%20the%20OSM%20network%20with%20the%20%5B%60from_osm%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fapi%2Fnetwork%23from_osm)%20constructor.%20The%20%60poly_crs_code%60%20and%20%60to_crs_code%60%20parameters%20need%20to%20be%20set%20so%20that%20the%20constructor%20knows%20which%20CRS%20the%20input%20geometry%20is%20in%2C%20and%20which%20CRS%20to%20convert%20the%20network%20to.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(CityNetwork%2C%20epsg_code%2C%20pol_buff)%3A%0A%20%20%20%20cn%20%3D%20CityNetwork.from_osm(pol_buff%2C%20poly_crs_code%3Depsg_code%2C%20to_crs_code%3Depsg_code)%0A%20%20%20%20return%20(cn%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%20Since%20the%20network%20and%20the%20source%20geometry%20are%20in%20the%20same%20CRS%2C%20%60set_boundary%60%20can%20now%20mark%20the%20study%20area%20with%20the%20original%2C%20unbuffered%20polygon%3A%20nodes%20inside%20it%20become%20%60live%3DTrue%60%2C%20nodes%20in%20the%20surrounding%20buffer%20become%20%60live%3DFalse%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cn%2C%20poly_utm)%3A%0A%20%20%20%20cn_bounded%20%3D%20cn.set_boundary(poly_utm)%0A%20%20%20%20print(f%22%7Bint(cn_bounded.nodes_gdf.live.sum())%7D%20of%20%7Bcn_bounded.node_count%7D%20nodes%20are%20live%22)%0A%20%20%20%20return%20(cn_bounded%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%20Metrics%20can%20then%20be%20computed%20based%20on%20the%20target%20distance%20without%20encountering%20edge%20roll-off.%20(%60set_boundary%60%20returns%20the%20network%20itself%2C%20so%20it%20can%20also%20be%20chained%20directly%20after%20the%20constructor.)%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cn_bounded)%3A%0A%20%20%20%20distances%20%3D%20%5B400%5D%0A%20%20%20%20cn_bounded.centrality_shortest(distances%3Ddistances)%0A%20%20%20%20nodes_gdf%20%3D%20cn_bounded.to_geopandas()%0A%20%20%20%20nodes_gdf.head()%0A%20%20%20%20return%20(nodes_gdf%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%20Values%20are%20only%20reported%20for%20live%20nodes%3B%20non-live%20nodes%20remain%20%60NaN%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(nodes_gdf%2C%20plt)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(1%2C%201%2C%20figsize%3D(7%2C%207)%2C%20dpi%3D150)%0A%20%20%20%20%23%20non-live%20(buffer)%20nodes%20have%20NaN%20values%3B%20draw%20them%20as%20a%20faint%20grey%20context%20layer%0A%20%20%20%20nodes_gdf%5B~nodes_gdf.live%5D.plot(ax%3D_ax%2C%20color%3D%22%23dddddd%22%2C%20linewidth%3D0.3)%0A%20%20%20%20_g%20%3D%20nodes_gdf%5Bnodes_gdf.live%5D.copy()%0A%20%20%20%20_g%5B%22_r%22%5D%20%3D%20_g%5B%22cc_harmonic_400%22%5D.rank(pct%3DTrue)%0A%20%20%20%20_g%20%3D%20_g.sort_values(%22_r%22)%20%20%23%20strongest%20drawn%20last%2C%20on%20top%0A%20%20%20%20_g.plot(ax%3D_ax%2C%20color%3Dplt.get_cmap(%22OrRd%22)(_g%5B%22_r%22%5D)%2C%20linewidth%3D0.15%20%2B%202.25%20*%20_g%5B%22_r%22%5D)%0A%20%20%20%20_ax.set_title(%22Harmonic%20closeness%2C%20400%20m%20(full%20network%3B%20buffer%20in%20grey)%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_ax.set_axis_off()%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%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%20To%20print%20or%20save%20only%20live%20nodes%2C%20filter%20the%20data%20frame%20accordingly.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(nodes_gdf%2C%20plt)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(1%2C%201%2C%20figsize%3D(7%2C%207)%2C%20dpi%3D150)%0A%20%20%20%20_g%20%3D%20nodes_gdf%5Bnodes_gdf.live%5D.copy()%0A%20%20%20%20_g%5B%22_r%22%5D%20%3D%20_g%5B%22cc_harmonic_400%22%5D.rank(pct%3DTrue)%0A%20%20%20%20_g%20%3D%20_g.sort_values(%22_r%22)%20%20%23%20strongest%20drawn%20last%2C%20on%20top%0A%20%20%20%20_g.plot(ax%3D_ax%2C%20color%3Dplt.get_cmap(%22OrRd%22)(_g%5B%22_r%22%5D)%2C%20linewidth%3D0.15%20%2B%202.25%20*%20_g%5B%22_r%22%5D)%0A%20%20%20%20_ax.set_title(%22Harmonic%20closeness%2C%20400%20m%20(live%20nodes%20only)%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_ax.set_axis_off()%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%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%20Summary%0A%0A%20%20%20%20This%20notebook%20demonstrated%20how%20to%20demarcate%20a%20study%20area%20with%20%60CityNetwork.set_boundary%60%2C%20which%20sets%20%60live%3DTrue%60%20or%20%60live%3DFalse%60%20on%20network%20nodes%20based%20on%20whether%20they%20fall%20within%20the%20original%20(unbuffered)%20study%20area%20boundary.%20This%20prevents%20edge%20rolloff%20effects%3A%20the%20algorithms%20can%20route%20through%20the%20buffer%20zone%2C%20but%20results%20are%20only%20reported%20for%20live%20nodes%20within%20the%20study%20area.%0A%0A%20%20%20%20**Next%20steps%3A**%0A%0A%20%20%20%20-%20See%20%5BNetwork%20Preparation%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples%2Fnetworks)%20for%20different%20ways%20to%20create%20a%20network.%0A%20%20%20%20-%20See%20%5BMetric%20Centrality%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples%2Fcentrality%2Fgpd-metric-centrality)%20or%20%5BAngular%20Centrality%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples%2Fcentrality%2Fgpd-angular-centrality)%20for%20centrality%20analysis%20on%20the%20prepared%20network.%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
fcea0229ed3f3bc39b4442b7138f3c14