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%20Statistics%20from%20GeoPandas%20Data%0A%0A%20%20%20%20Calculate%20building%20statistics%20from%20a%20%60geopandas%60%20%60GeoDataFrame%60.%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(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20This%20recipe%20uses%20the%20high-level%20%5B%60CityNetwork%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fapi%2Fnetwork)%20class%20for%20the%20statistics%20computation.%20Because%20this%20example%20decomposes%20the%20network%20first%2C%20which%20is%20a%20lower-level%20graph%20operation%20without%20a%20%60CityNetwork%60%20equivalent%2C%20the%20graph%20is%20prepared%20with%20the%20%60tools%60%20modules%20and%20then%20bridged%20into%20the%20high-level%20API%20with%20%60CityNetwork.from_nx%60.%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%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20seaborn%20as%20sns%0A%20%20%20%20from%20cityseer.network%20import%20CityNetwork%0A%20%20%20%20from%20cityseer.tools%20import%20graphs%2C%20io%0A%0A%20%20%20%20return%20CityNetwork%2C%20gpd%2C%20graphs%2C%20io%2C%20np%2C%20plt%2C%20sns%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%20start%2C%20follow%20the%20same%20approach%20as%20shown%20in%20the%20network%20examples%20to%20create%20the%20network.%20The%20full%20bundled%20network%20is%20clipped%20to%20a%202km%20study%20area%20around%20the%20city%20centre%2C%20buffered%20by%20the%20maximum%20analysis%20distance%20so%20that%20nodes%20near%20the%20study%20edge%20keep%20their%20full%20catchments.%20Since%20decomposition%20multiplies%20the%20number%20of%20network%20nodes%2C%20this%20example%20works%20with%20a%20district%20rather%20than%20the%20whole%20city%3B%20the%20statistics%20are%20computed%20per%20node%20from%20local%20catchments%2C%20so%20the%20results%20within%20the%20study%20area%20are%20unaffected.%0A%0A%20%20%20%20The%20graph%20is%20decomposed%20with%20%5B%60nx_decompose%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Ftools%2Fgraphs%23nx_decompose)%20so%20that%20statistics%20are%20sampled%20at%20a%20higher%20spatial%20resolution%2C%20then%20handed%20to%20%60CityNetwork.from_nx%60%3B%20the%20%60boundary%60%20argument%20marks%20the%20nodes%20inside%20the%20study%20area%20as%20%60live%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(CityNetwork%2C%20gpd%2C%20graphs%2C%20io)%3A%0A%20%20%20%20streets_gpd%20%3D%20gpd.read_file(%22..%2F..%2Fdata%2Fmadrid_streets%2Fstreet_network.gpkg%22)%0A%20%20%20%20streets_gpd%20%3D%20streets_gpd.explode(ignore_index%3DTrue)%0A%20%20%20%20%23%20the%20source%20data%20contains%20a%20small%20number%20of%20exact%20duplicate%20geometries%0A%20%20%20%20streets_gpd%20%3D%20streets_gpd.drop_duplicates(subset%3D%22geometry%22)%0A%20%20%20%20%23%202km%20study%20area%20around%20the%20city%20centre%2C%20with%20the%20network%20buffered%20a%20further%20200m%0A%20%20%20%20%23%20(the%20maximum%20analysis%20distance)%20to%20prevent%20edge%20rolloff%0A%20%20%20%20centre%20%3D%20gpd.GeoSeries.from_xy(%5B440300%5D%2C%20%5B4474300%5D%2C%20crs%3Dstreets_gpd.crs)%0A%20%20%20%20study_poly%20%3D%20centre.buffer(2000).iloc%5B0%5D%0A%20%20%20%20buffered_poly%20%3D%20centre.buffer(2200).iloc%5B0%5D%0A%20%20%20%20streets_clip%20%3D%20streets_gpd%5Bstreets_gpd.intersects(buffered_poly)%5D%0A%20%20%20%20G%20%3D%20io.nx_from_generic_geopandas(streets_clip)%0A%20%20%20%20G%20%3D%20graphs.nx_decompose(G%2C%2050)%0A%20%20%20%20cn%20%3D%20CityNetwork.from_nx(G%2C%20boundary%3Dstudy_poly)%0A%20%20%20%20return%20buffered_poly%2C%20cn%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%20Read%20the%20buildings%20dataset%20with%20GeoPandas%2C%20for%20example%20from%20a%20GeoPackage%20or%20Shapefile.%20The%20buildings%20are%20clipped%20to%20the%20buffered%20study%20area%2C%20since%20only%20buildings%20within%20reach%20of%20the%20clipped%20network%20can%20contribute%20to%20the%20statistics.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(buffered_poly%2C%20gpd)%3A%0A%20%20%20%20bldgs_gpd%20%3D%20gpd.read_file(%22..%2F..%2Fdata%2Fmadrid_buildings%2Fmadrid_bldgs.gpkg%22)%0A%20%20%20%20bldgs_gpd%20%3D%20bldgs_gpd%5Bbldgs_gpd.intersects(buffered_poly)%5D%0A%20%20%20%20bldgs_gpd.head()%0A%20%20%20%20return%20(bldgs_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%20Use%20the%20%5B%60compute_stats%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fapi%2Fnetwork%23compute_stats)%20method%20to%20compute%20statistics%20for%20numeric%20columns%20in%20the%20%60GeoDataFrame%60%2C%20specified%20with%20the%20%60stats_column_labels%60%20argument.%20The%20statistics%20are%20aggregated%20over%20the%20network%20using%20network%20distances.%20The%20%60measures%60%20argument%20selects%20which%20statistics%20to%20compute%3B%20without%20it%2C%20the%20full%20set%20of%20%60count%60%2C%20%60sum%60%2C%20%60min%60%2C%20%60max%60%2C%20%60mean%60%2C%20%60median%60%2C%20%60mad%60%20(median%20absolute%20deviation)%20and%20%60var%60%20is%20generated.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bldgs_gpd%2C%20cn)%3A%0A%20%20%20%20distances%20%3D%20%5B100%2C%20200%5D%0A%20%20%20%20_cn%2C%20bldgs_gpd_1%20%3D%20cn.compute_stats(%0A%20%20%20%20%20%20%20%20bldgs_gpd%2C%0A%20%20%20%20%20%20%20%20stats_column_labels%3D%5B%22area%22%2C%20%22perimeter%22%2C%20%22compactness%22%2C%20%22orientation%22%2C%20%22shape_index%22%5D%2C%0A%20%20%20%20%20%20%20%20distances%3Ddistances%2C%0A%20%20%20%20%20%20%20%20measures%3D%5B%22mean%22%2C%20%22median%22%2C%20%22mad%22%2C%20%22var%22%5D%2C%0A%20%20%20%20)%0A%20%20%20%20nodes_gdf_1%20%3D%20cn.to_geopandas()%0A%20%20%20%20return%20bldgs_gpd_1%2C%20nodes_gdf_1%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%20generates%20a%20%60cc_%7Bcolumn%7D_%7Bmeasure%7D_%7Bdistance%7D%60%20column%20per%20selected%20measure%20for%20each%20of%20the%20input%20distance%20thresholds.%20By%20default%20the%20aggregations%20are%20unweighted%3B%20pass%20a%20%60decay_fn%60%20expression%20such%20as%20%60%22exp(-4%20*%20p)%22%60%20to%20weight%20the%20contribution%20of%20each%20point%20by%20its%20distance%20from%20the%20point%20of%20measure.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(nodes_gdf_1)%3A%0A%20%20%20%20list(nodes_gdf_1.columns)%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%20The%20result%20in%20columns%20can%20be%20explored%20with%20conventional%20Python%20ecosystem%20tools%20such%20as%20%60seaborn%60%20and%20%60matplotlib%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(nodes_gdf_1%2C%20plt%2C%20sns)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(9%2C%205)%2C%20dpi%3D150)%0A%20%20%20%20sns.histplot(%0A%20%20%20%20%20%20%20%20data%3Dnodes_gdf_1%2C%0A%20%20%20%20%20%20%20%20x%3D%22cc_orientation_mean_200%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22%233465a4%22%2C%0A%20%20%20%20%20%20%20%20alpha%3D0.35%2C%0A%20%20%20%20%20%20%20%20edgecolor%3D%22%2323425f%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20%20%20%20%20label%3D%22Mean%22%2C%0A%20%20%20%20%20%20%20%20element%3D%22step%22%2C%0A%20%20%20%20%20%20%20%20ax%3D_ax%2C%0A%20%20%20%20)%0A%20%20%20%20sns.histplot(%0A%20%20%20%20%20%20%20%20data%3Dnodes_gdf_1%2C%0A%20%20%20%20%20%20%20%20x%3D%22cc_orientation_median_200%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22%23f57900%22%2C%0A%20%20%20%20%20%20%20%20alpha%3D0.35%2C%0A%20%20%20%20%20%20%20%20edgecolor%3D%22%23a55000%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20%20%20%20%20label%3D%22Median%22%2C%0A%20%20%20%20%20%20%20%20element%3D%22step%22%2C%0A%20%20%20%20%20%20%20%20ax%3D_ax%2C%0A%20%20%20%20)%0A%20%20%20%20_ax.set_xlabel(%22Orientation%20(degrees)%22)%0A%20%20%20%20_ax.set_ylabel(%22Count%22)%0A%20%20%20%20_ax.set_title(%22Orientation%20Distribution%3A%20Mean%20vs%20Median%20(200m%20network%20distance)%22)%0A%20%20%20%20_ax.legend(frameon%3DFalse%2C%20ncol%3D2)%0A%20%20%20%20_ax.set_xlim(0%2C%2045)%0A%20%20%20%20sns.despine()%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(nodes_gdf_1%2C%20np%2C%20plt%2C%20sns)%3A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(9%2C%205)%2C%20dpi%3D150)%0A%20%20%20%20sns.histplot(%0A%20%20%20%20%20%20%20%20data%3Dnodes_gdf_1%2C%0A%20%20%20%20%20%20%20%20x%3D%22cc_orientation_mad_200%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22%233465a4%22%2C%0A%20%20%20%20%20%20%20%20alpha%3D0.35%2C%0A%20%20%20%20%20%20%20%20edgecolor%3D%22%2323425f%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20%20%20%20%20label%3D%22Median%20Absolute%20Deviation%22%2C%0A%20%20%20%20%20%20%20%20element%3D%22step%22%2C%0A%20%20%20%20%20%20%20%20ax%3D_ax%2C%0A%20%20%20%20)%0A%20%20%20%20nodes_gdf_1%5B%22std%22%5D%20%3D%20np.sqrt(nodes_gdf_1%5B%22cc_orientation_var_200%22%5D)%0A%20%20%20%20sns.histplot(%0A%20%20%20%20%20%20%20%20data%3Dnodes_gdf_1%2C%0A%20%20%20%20%20%20%20%20x%3D%22std%22%2C%0A%20%20%20%20%20%20%20%20color%3D%22%23f57900%22%2C%0A%20%20%20%20%20%20%20%20alpha%3D0.35%2C%0A%20%20%20%20%20%20%20%20edgecolor%3D%22%23a55000%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20%20%20%20%20label%3D%22Standard%20Deviation%22%2C%0A%20%20%20%20%20%20%20%20element%3D%22step%22%2C%0A%20%20%20%20%20%20%20%20ax%3D_ax%2C%0A%20%20%20%20)%0A%20%20%20%20_ax.set_xlabel(%22Orientation%20(degrees)%22)%0A%20%20%20%20_ax.set_ylabel(%22Count%22)%0A%20%20%20%20_ax.set_title(%22MAD%20vs.%20Standard%20Deviation%20(200m%20network%20distance)%22)%0A%20%20%20%20_ax.legend(frameon%3DFalse%2C%20ncol%3D2)%0A%20%20%20%20_ax.set_xlim(0%2C%2020)%0A%20%20%20%20sns.despine()%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(bldgs_gpd_1%2C%20nodes_gdf_1%2C%20plt)%3A%0A%20%20%20%20g%20%3D%20nodes_gdf_1%5Bnodes_gdf_1.live%5D.copy()%0A%20%20%20%20g%5B%22_r%22%5D%20%3D%20g%5B%22cc_orientation_median_200%22%5D.rank(pct%3DTrue)%0A%20%20%20%20g%20%3D%20g.sort_values(%22_r%22)%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%20g.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*%20g%5B%22_r%22%5D)%0A%20%20%20%20%23%20buildings%20as%20light-grey%20context%0A%20%20%20%20bldgs_gpd_1.plot(color%3D%22%23cccccc%22%2C%20edgecolor%3D%22%23bbbbbb%22%2C%20linewidth%3D0.1%2C%20ax%3D_ax)%0A%20%20%20%20_ax.set_title(%22Median%20building%20orientation%2C%20200%20m%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_ax.set_xlim(438500%2C%20438500%20%2B%203500)%0A%20%20%20%20_ax.set_ylim(4472500%2C%204472500%20%2B%203500)%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%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%20computed%20network-distance%20statistics%20for%20building%20morphology%20attributes%20(area%2C%20perimeter%2C%20compactness%2C%20orientation%2C%20and%20shape%20index)%20from%20a%20GeoDataFrame%20using%20%60CityNetwork.compute_stats%60%2C%20with%20the%20decomposed%20graph%20bridged%20into%20the%20high-level%20API%20via%20%60from_nx%60.%20The%20method%20produces%20summary%20statistics%20such%20as%20mean%2C%20median%2C%20variance%2C%20and%20MAD%2C%20selectable%20via%20%60measures%60%2C%20enabling%20fine-grained%20spatial%20analysis%20of%20building%20characteristics%20across%20a%20district%20of%20the%20bundled%20street%20network.%0A%0A%20%20%20%20**Next%20steps%3A**%20To%20compute%20statistics%20from%20OSM%20data%2C%20see%20%5BOSM%20Statistics%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples%2Fstats%2Fosm-stats).%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
7c2586a9e317893cb6873c0b5d394e2f