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%20Street%20Continuity%20from%20OS%20Open%20Roads%0A%0A%20%20%20%20Compute%20street%20continuity%20metrics%20from%20the%20Ordnance%20Survey%20OS%20Open%20Roads%20dataset.%20Continuity%20measures%20how%20far%20streets%20extend%20as%20continuous%20entities%20based%20on%20shared%20names%2C%20route%20numbers%2C%20or%20road%20classifications.%0A%0A%20%20%20%20Continuity%20analysis%20operates%20directly%20on%20the%20%60networkx%60%20graph%20through%20the%20lower-level%20functional%20API%3B%20it%20is%20not%20wrapped%20by%20the%20higher-level%20%5B%60CityNetwork%60%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fguide%2Ffundamentals%23citynetwork-api)%20class.%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%20%23%23%20Data%20Source%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%20The%20following%20example%20uses%20the%20%5BOS%20Open%20Roads%5D(https%3A%2F%2Fosdatahub.os.uk%2Fdownloads%2Fopen%2FOpenRoads)%20dataset%2C%20which%20is%20available%20under%20the%20%5BOpen%20Government%20License%5D(http%3A%2F%2Fos.uk%2Fopendata%2Flicence).%0A%0A%20%20%20%20_%C2%A9%20Crown%20copyright%20and%20database%20right%202022_%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%20%23%23%20Preparation%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%20The%20dataset%20is%20not%20bundled%20with%20the%20repository.%20This%20example%20assumes%20the%20OS%20Open%20Roads%20GeoPackage%20download%20has%20been%20unzipped%20into%20%60temp%2F%60%20at%20the%20root%20of%20a%20cloned%20%60cityseer-api%60%20repository%2C%20giving%20%60temp%2Foproad_gpkg_gb%2FData%2Foproad_gb.gpkg%60%20(the%20layout%20of%20the%20official%20download).%20Edit%20the%20path%20below%20if%20your%20data%20lives%20elsewhere.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20open_roads_path%20%3D%20Path(%22..%2F..%2F..%2Ftemp%2Foproad_gpkg_gb%2FData%2Foproad_gb.gpkg%22)%0A%20%20%20%20print(%22data%20path%3A%22%2C%20open_roads_path.resolve())%0A%20%20%20%20print(%22path%20exists%3A%22%2C%20open_roads_path.exists())%0A%20%20%20%20%23%20halt%20gracefully%20when%20the%20manually%20downloaded%20dataset%20is%20not%20present%0A%20%20%20%20mo.stop(%0A%20%20%20%20%20%20%20%20not%20open_roads_path.exists()%2C%0A%20%20%20%20%20%20%20%20%22OS%20Open%20Roads%20dataset%20not%20found%3B%20download%20it%20to%20run%20the%20rest%20of%20this%20notebook.%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(open_roads_path%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%23%23%20Extents%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%20Instead%20of%20loading%20the%20entire%20dataset%2C%20we'll%20use%20a%20bounding%20box%20to%20only%20load%20an%20area%20of%20interest.%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%20from%20cityseer.tools%20import%20io%0A%20%20%20%20from%20pyproj%20import%20Transformer%0A%20%20%20%20from%20shapely%20import%20geometry%0A%0A%20%20%20%20%23%20create%20graph%20-%20only%20UK%20locations%20will%20work%20for%20OS%20Open%20Roads%20data%0A%20%20%20%20%23%20stratford-upon-avon%0A%20%20%20%20%23%20lng%2C%20lat%2C%20buffer_dist%2C%20plot_buffer%20%3D%20-1.7063649924889566%2C%2052.19277374082795%2C%202500%2C%202000%0A%20%20%20%20%23%20london%0A%20%20%20%20lng%2C%20lat%2C%20buffer_dist%2C%20plot_buffer%20%3D%20(%0A%20%20%20%20%20%20%20%20-0.13039709427587876%2C%0A%20%20%20%20%20%20%20%2051.516434828344366%2C%0A%20%20%20%20%20%20%20%206000%2C%0A%20%20%20%20%20%20%20%205000%2C%0A%20%20%20%20)%0A%20%20%20%20%23%20transform%20from%20WGS%20to%20BNG%0A%20%20%20%20transformer%20%3D%20Transformer.from_crs(%22EPSG%3A4326%22%2C%20%22EPSG%3A27700%22)%0A%20%20%20%20easting%2C%20northing%20%3D%20transformer.transform(lat%2C%20lng)%0A%20%20%20%20%23%20calculate%20bbox%20relative%20to%20centroid%0A%20%20%20%20centroid%20%3D%20geometry.Point(easting%2C%20northing)%0A%20%20%20%20target_bbox%3A%20tuple%5Bfloat%2C%20float%2C%20float%2C%20float%5D%20%3D%20centroid.buffer(buffer_dist).bounds%20%20%23%20type%3A%20ignore%0A%20%20%20%20plot_bbox%3A%20tuple%5Bfloat%2C%20float%2C%20float%2C%20float%5D%20%3D%20centroid.buffer(plot_buffer).bounds%20%20%23%20type%3A%20ignore%0A%20%20%20%20return%20io%2C%20plot_bbox%2C%20target_bbox%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%23%20Load%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%20We%20can%20now%20load%20the%20OS%20Open%20Roads%20dataset%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(io%2C%20open_roads_path%2C%20target_bbox%3A%20tuple%5Bfloat%2C%20float%2C%20float%2C%20float%5D)%3A%0A%20%20%20%20%23%20load%20OS%20Open%20Roads%20data%20from%20downloaded%20geopackage%0A%20%20%20%20G_open%20%3D%20io.nx_from_open_roads(open_roads_path%2C%20target_bbox%3Dtarget_bbox)%0A%20%20%20%20return%20(G_open%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%23%20Observe%20continuity%20metrics%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%20step%20runs%20the%20continuity%20analysis%20using%20the%20specified%20heuristic.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(G_open)%3A%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20from%20cityseer.metrics%20import%20observe%0A%20%20%20%20from%20cityseer.tools%20import%20plot%0A%0A%20%20%20%20print(%22Continuity%20by%20street%20names%22)%0A%20%20%20%20G_cont%2C%20NamesContReport%20%3D%20observe.street_continuity(G_open%2C%20method%3D%22names%22)%0A%20%20%20%20%23%20methods%20can%20be%20%22names%22%2C%20%22routes%22%2C%20%22highways%22%0A%20%20%20%20NamesContReport.report_by_count(n_items%3D5)%0A%20%20%20%20NamesContReport.report_by_length(n_items%3D5)%0A%20%20%20%20print(%22Continuity%20by%20route%20numbers%22)%0A%20%20%20%20G_cont%2C%20RoutesContReport%20%3D%20observe.street_continuity(G_cont%2C%20method%3D%22routes%22)%0A%20%20%20%20RoutesContReport.report_by_count(n_items%3D5)%0A%20%20%20%20RoutesContReport.report_by_length(n_items%3D5)%0A%20%20%20%20print(%22Continuity%20by%20highway%20types%22)%0A%20%20%20%20G_cont%2C%20HwyContReport%20%3D%20observe.street_continuity(G_cont%2C%20method%3D%22highways%22)%0A%20%20%20%20HwyContReport.report_by_count(n_items%3D5)%0A%20%20%20%20HwyContReport.report_by_length(n_items%3D5)%0A%20%20%20%20print(%22Continuity%20by%20overlapping%20routes%20and%20names%20types%22)%0A%20%20%20%20G_cont%2C%20HybridContReport%20%3D%20observe.hybrid_street_continuity(G_cont)%0A%20%20%20%20HybridContReport.report_by_count(n_items%3D5)%0A%20%20%20%20HybridContReport.report_by_length(n_items%3D5)%0A%20%20%20%20return%20G_cont%2C%20plot%2C%20plt%0A%0A%0A%40app.cell%0Adef%20_(G_cont%2C%20plot%2C%20plot_bbox%3A%20tuple%5Bfloat%2C%20float%2C%20float%2C%20float%5D%2C%20plt)%3A%0A%20%20%20%20for%20method%2C%20shape_exp%2C%20descriptor%2C%20cmap%2C%20inverse%2C%20col_by_categ%20in%20zip(%0A%20%20%20%20%20%20%20%20%5B%22names%22%2C%20%22routes%22%2C%20%22highways%22%2C%20%22hybrid%22%5D%2C%20%20%23%0A%20%20%20%20%20%20%20%20%5B1%2C%200.75%2C%200.5%2C%201%5D%2C%20%20%23%0A%20%20%20%20%20%20%20%20%5B%22Street%20names%22%2C%20%22Routes%22%2C%20%22Road%20types%22%2C%20%22Hybrid%20routes%20%26%20names%22%5D%2C%20%20%23%0A%20%20%20%20%20%20%20%20%5B%22plasma%22%2C%20%22viridis%22%2C%20%22tab10%22%2C%20%22tab10%22%5D%2C%20%20%23%0A%20%20%20%20%20%20%20%20%5BFalse%2C%20False%2C%20True%2C%20False%5D%2C%20%20%23%0A%20%20%20%20%20%20%20%20%5BFalse%2C%20False%2C%20True%2C%20True%5D%2C%0A%20%20%20%20%20%20%20%20strict%3DFalse%2C%0A%20%20%20%20)%3A%0A%20%20%20%20%20%20%20%20print(f%22Plotting%20results%20for%20method%3A%20%7Bmethod%7D%22)%0A%20%20%20%20%20%20%20%20%23%20plot%0A%20%20%20%20%20%20%20%20bg_colour%20%3D%20%22%231d1d1d%22%0A%20%20%20%20%20%20%20%20fig%2C%20axes%20%3D%20plt.subplots(2%2C%201%2C%20dpi%3D150%2C%20figsize%3D(8%2C%2012)%2C%20facecolor%3Dbg_colour%2C%20constrained_layout%3DTrue)%0A%20%20%20%20%20%20%20%20fig.suptitle(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22OS%20Open%20Roads%20plotted%20by%20%7Bdescriptor%7D%20continuity%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20fontsize%3D%22small%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20ha%3D%22center%22%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%23%20by%20count%0A%20%20%20%20%20%20%20%20plot.plot_nx_edges(%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5B0%5D%2C%20%20%23%20type%3A%20ignore%0A%20%20%20%20%20%20%20%20%20%20%20%20nx_multigraph%3DG_cont%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20edge_metrics_key%3Df%22%7Bmethod%7D_cont_by_count%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20bbox_extents%3Dplot_bbox%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cmap_key%3Dcmap%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20lw_min%3D0.5%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20lw_max%3D2%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20edge_label_key%3Df%22%7Bmethod%7D_cont_by_label%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colour_by_categorical%3Dcol_by_categ%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20shape_exp%3Dshape_exp%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20face_colour%3Dbg_colour%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20invert_plot_order%3Dinverse%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20axes%5B0%5D.set_xlabel(f%22%7Bdescriptor%7D%20by%20count%22%2C%20fontsize%3D%22x-small%22)%20%20%23%20type%3A%20ignore%0A%20%20%20%20%20%20%20%20%23%20by%20length%0A%20%20%20%20%20%20%20%20plot.plot_nx_edges(%0A%20%20%20%20%20%20%20%20%20%20%20%20axes%5B1%5D%2C%20%20%23%20type%3A%20ignore%0A%20%20%20%20%20%20%20%20%20%20%20%20nx_multigraph%3DG_cont%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20edge_metrics_key%3Df%22%7Bmethod%7D_cont_by_length%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20bbox_extents%3Dplot_bbox%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20cmap_key%3Dcmap%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20lw_min%3D0.5%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20lw_max%3D2%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20edge_label_key%3Df%22%7Bmethod%7D_cont_by_label%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colour_by_categorical%3Dcol_by_categ%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20shape_exp%3Dshape_exp%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20face_colour%3Dbg_colour%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20invert_plot_order%3Dinverse%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20axes%5B1%5D.set_xlabel(f%22%7Bdescriptor%7D%20by%20length%20(metres)%22%2C%20fontsize%3D%22x-small%22)%20%20%23%20type%3A%20ignore%0A%20%20%20%20%20%20%20%20plt.show()%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%0A%20%20%20%20This%20notebook%20demonstrated%20how%20to%20compute%20street%20continuity%20metrics%20from%20the%20OS%20Open%20Roads%20dataset%20for%20London%2C%20applying%20the%20same%20name%2C%20route%2C%20highway%2C%20and%20hybrid%20continuity%20heuristics%20as%20the%20OSM%20example%20but%20using%20an%20authoritative%20UK%20national%20dataset.%20The%20OS%20Open%20Roads%20data%20provides%20well-structured%20road%20classification%20attributes%2C%20producing%20clean%20continuity%20results%20that%20highlight%20the%20extent%20of%20major%20arterial%20routes%20like%20the%20A1%20and%20A41.%0A%0A%20%20%20%20**Next%20steps%3A**%20For%20other%20analysis%20types%2C%20return%20to%20the%20%5BRecipes%20overview%5D(https%3A%2F%2Fcityseer.benchmarkurbanism.com%2Fexamples).%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
2d67de8d7d2c680f47aa4954df769c30