Graph Cleaning

Last update

November 30, 2024

Install and update cityseer if necessary.

# !pip install --upgrade cityseer

See the guide for a preamble.

Please also see the graph corrections guide for an alternative approach.

Downloading data

This example will make use of OSM data downloaded from the OSM API. To keep things interesting, let’s pick London Soho, which will be buffered and cleaned for a 1,250m radius.

from shapely import geometry
import utm

from cityseer.tools import graphs, plot, io

# Let's download data within a 1,250m buffer around London Soho:
lng, lat = -0.13396079424572427, 51.51371088849723
# lng, lat = 2.166981, 41.389526 -- Barcelona - which is a complex case
buffer = 1250
# creates a WGS shapely polygon
poly_wgs, _ = io.buffered_point_poly(lng, lat, buffer)
# use a WGS shapely polygon to download information from OSM
# this version will not simplify
G_raw = io.osm_graph_from_poly(poly_wgs, simplify=False)
# whereas this version does simplify
G_utm = io.osm_graph_from_poly(poly_wgs)

# select extents for clipping the plotting extents
easting, northing = utm.from_latlon(lat, lng)[:2]
buff = geometry.Point(easting, northing).buffer(1000)
min_x, min_y, max_x, max_y = buff.bounds


# reusable plot function
def simple_plot(_G, plot_geoms=True):
    # plot using the selected extents
    plot.plot_nx(
        _G,
        labels=False,
        plot_geoms=plot_geoms,
        node_size=4,
        edge_width=1,
        x_lim=(min_x, max_x),
        y_lim=(min_y, max_y),
        figsize=(6, 6),
        dpi=150,
    )
WARNING:cityseer.tools.io:Unable to parse level info: -`;-4
WARNING:cityseer.tools.io:Unable to parse level info: -`;-4
WARNING:cityseer.tools.io:Unable to parse level info: -`;-4
INFO:cityseer.tools.io:Converting networkX graph from EPSG code 4326 to EPSG code 32630.
INFO:cityseer.tools.io:Processing node x, y coordinates.
100%|██████████| 14807/14807 [00:00<00:00, 288798.95it/s]
INFO:cityseer.tools.io:Processing edge geom coordinates, if present.
100%|██████████| 16107/16107 [00:00<00:00, 451151.32it/s]
INFO:cityseer.tools.graphs:Generating interpolated edge geometries.
100%|██████████| 16107/16107 [00:00<00:00, 57577.22it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 14807/14807 [00:02<00:00, 5743.59it/s]
WARNING:cityseer.tools.io:Unable to parse level info: -`;-4
WARNING:cityseer.tools.io:Unable to parse level info: -`;-4
WARNING:cityseer.tools.io:Unable to parse level info: -`;-4
INFO:cityseer.tools.io:Converting networkX graph from EPSG code 4326 to EPSG code 32630.
INFO:cityseer.tools.io:Processing node x, y coordinates.
100%|██████████| 14807/14807 [00:00<00:00, 487790.98it/s]
INFO:cityseer.tools.io:Processing edge geom coordinates, if present.
100%|██████████| 16107/16107 [00:00<00:00, 862034.64it/s]
INFO:cityseer.tools.graphs:Generating interpolated edge geometries.
100%|██████████| 16107/16107 [00:00<00:00, 73156.39it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 14807/14807 [00:02<00:00, 7098.01it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 7848/7848 [00:00<00:00, 485707.72it/s]
100%|██████████| 7848/7848 [00:02<00:00, 3848.54it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 6548/6548 [00:00<00:00, 18867.82it/s]
100%|██████████| 5079/5079 [00:00<00:00, 56567.81it/s]
INFO:cityseer.tools.graphs:Removing dangling nodes.
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 5677/5677 [00:00<00:00, 337014.19it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4592/4592 [00:00<00:00, 751414.01it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3537/3537 [00:00<00:00, 131627.89it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4592/4592 [00:00<00:00, 17749.61it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4564/4564 [00:00<00:00, 359037.52it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3537/3537 [00:00<00:00, 12064.87it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4617/4617 [00:00<00:00, 111192.08it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4607/4607 [00:00<00:00, 474898.83it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3537/3537 [00:00<00:00, 54245.22it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4608/4608 [00:00<00:00, 167887.29it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4608/4608 [00:00<00:00, 344755.76it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3537/3537 [00:00<00:00, 37406.08it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4609/4609 [00:00<00:00, 149759.44it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3537/3537 [00:00<00:00, 80563.33it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3537/3537 [00:00<00:00, 142968.34it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4609/4609 [00:00<00:00, 21399.39it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3537/3537 [00:00<00:00, 212752.81it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3502/3502 [00:00<00:00, 52896.48it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3502/3502 [00:00<00:00, 12486.23it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4166/4166 [00:00<00:00, 30067.42it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3180/3180 [00:00<00:00, 187585.43it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3147/3147 [00:00<00:00, 72510.24it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3147/3147 [00:00<00:00, 28579.20it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 3986/3986 [00:00<00:00, 107372.89it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3113/3113 [00:00<00:00, 400271.87it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3105/3105 [00:00<00:00, 11932.99it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3105/3105 [00:00<00:00, 18287.76it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 3883/3883 [00:00<00:00, 132511.70it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3036/3036 [00:00<00:00, 389928.86it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3030/3030 [00:00<00:00, 46778.00it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 3870/3870 [00:00<00:00, 514402.04it/s]
INFO:cityseer.tools.graphs:Snapping gapped endings.
100%|██████████| 3030/3030 [00:00<00:00, 8065.69it/s] 
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 3985/3985 [00:00<00:00, 655257.23it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3030/3030 [00:00<00:00, 8183.00it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4457/4457 [00:00<00:00, 176611.87it/s]
INFO:cityseer.tools.graphs:Removing dangling nodes.
100%|██████████| 3293/3293 [00:00<00:00, 250914.56it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 2803/2803 [00:00<00:00, 13836.15it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 3289/3289 [00:00<00:00, 782920.88it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 2126/2126 [00:00<00:00, 6288.80it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 3307/3307 [00:00<00:00, 62901.63it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 2126/2126 [00:00<00:00, 61058.81it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 2126/2126 [00:00<00:00, 3080.37it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 2745/2745 [00:00<00:00, 30658.08it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 2640/2640 [00:00<00:00, 763441.99it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 1742/1742 [00:00<00:00, 6372.71it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 2643/2643 [00:00<00:00, 168087.60it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 1742/1742 [00:00<00:00, 53300.05it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 1742/1742 [00:00<00:00, 3437.91it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 2329/2329 [00:00<00:00, 21796.88it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 1481/1481 [00:00<00:00, 46683.93it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 50.
100%|██████████| 2190/2190 [00:00<00:00, 58646.99it/s]
INFO:cityseer.tools.graphs:Ironing edges.
100%|██████████| 2174/2174 [00:00<00:00, 12236.53it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 1.
100%|██████████| 2163/2163 [00:00<00:00, 147655.99it/s]
INFO:cityseer.tools.graphs:Removing dangling nodes.
100%|██████████| 1396/1396 [00:00<00:00, 264106.83it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 1386/1386 [00:00<00:00, 83489.71it/s]

The automated graph cleaning may give satisfactory results depending on the intended end-use. See the steps following beneath for an example of how to manually clean the graph where additional control is preferred.

print("The graph before simplification.")
simple_plot(G_raw, plot_geoms=True)

print("The graph after simplification")
simple_plot(G_utm, plot_geoms=True)
INFO:cityseer.tools.plot:Preparing graph nodes
INFO:cityseer.tools.plot:Preparing graph edges
The graph before simplification.
100%|██████████| 7848/7848 [00:00<00:00, 8405.05it/s] 

INFO:cityseer.tools.plot:Preparing graph nodes
INFO:cityseer.tools.plot:Preparing graph edges
The graph after simplification
100%|██████████| 2125/2125 [00:00<00:00, 9345.96it/s]

Manual cleaning

The automated simplification uses a number of steps and should generally give a solid starting point for further customised cleaning. The following is the steps followed by the automatic cleaning routine. You can adapt this to work for context specific considerations such as which OSM road types to clean and what distances to use.

# deduplicate by hierarchy
G = graphs.nx_deduplicate_edges(G_raw, dissolve_distance=20, max_ang_diff=20)
# remove disconnected components
G = graphs.nx_remove_dangling_nodes(G, despine=0, remove_disconnected=100)
# clean by highway types - leave motorways alone
# split only for a given type at a time
for dist, tags, max_angle in (
    (28, ["trunk"], 45),
    (24, ["primary"], 45),
    (20, ["secondary"], 45),
    (16, ["tertiary"], 45),
):
    G = graphs.nx_split_opposing_geoms(
        G,
        buffer_dist=dist,
        squash_nodes=True,
        centroid_by_itx=True,
        osm_hwy_target_tags=tags,
        osm_matched_tags_only=True,
        prioritise_by_hwy_tag=True,
        simplify_by_max_angle=max_angle,
    )
# consolidate
for dist, tags, max_angle in (
    (28, ["trunk"], 95),
    (24, ["trunk", "primary"], 95),
    (20, ["trunk", "primary", "secondary"], 95),
    (16, ["trunk", "primary", "secondary", "tertiary"], 95),
):
    G = graphs.nx_consolidate_nodes(
        G,
        buffer_dist=dist,
        crawl=False,
        centroid_by_itx=True,
        osm_hwy_target_tags=tags,
        osm_matched_tags_only=True,
        prioritise_by_hwy_tag=True,
        simplify_by_max_angle=max_angle,
    )
    G = graphs.nx_remove_filler_nodes(G)
# snap gapped endings - don't clean danglers before this
G = graphs.nx_snap_gapped_endings(
    G,
    osm_hwy_target_tags=[
        "residential",
        "living_street",
        # "service", # intentionally omitted - e.g. parking lots
        "cycleway",
        "bridleway",
        "pedestrian",
        "steps",
        "footway",
        "footway_green",
        "footway_pedestrian",  # plazas
        "path",
    ],
    buffer_dist=20,
)
# snap gapped endings to roads - don't clean danglers before this
# look for degree 1 dead-ends and link to nearby edges
G = graphs.nx_split_opposing_geoms(
    G,
    buffer_dist=20,
    osm_hwy_target_tags=[
        # "trunk",  # intentionally omitted
        "primary",
        "primary_link",
        "secondary",
        "secondary_link",
        "tertiary",
        "tertiary_link",
        "residential",
        "living_street",
        # "service", # intentionally omitted - e.g. parking lots
        "cycleway",
        "bridleway",
        "pedestrian",
        "steps",
        "footway",
        "footway_green",
        "footway_pedestrian",  # plazas
        "path",
    ],
    min_node_degree=1,
    max_node_degree=1,
    squash_nodes=False,
)
# remove danglers
G = graphs.nx_remove_dangling_nodes(G, despine=40)
# do smaller scale cleaning
max_angle = 120  # rue de nevers in Paris
for dist in (5, 10):
    G = graphs.nx_split_opposing_geoms(
        G,
        buffer_dist=dist,
        squash_nodes=True,
        centroid_by_itx=True,
        osm_hwy_target_tags=[
            # "trunk",  # intentionally omitted
            "primary",
            "primary_link",
            "secondary",
            "secondary_link",
            "tertiary",
            "tertiary_link",
            "residential",
            "living_street",
            "service",
            "cycleway",
            "bridleway",
            "pedestrian",
            # "steps",
            "footway",
            "footway_pedestrian",  # plazas
            "path",
            "unclassified",
        ],
        prioritise_by_hwy_tag=True,
        simplify_by_max_angle=max_angle,
    )
    G = graphs.nx_consolidate_nodes(
        G,
        buffer_dist=dist,
        crawl=True,
        centroid_by_itx=True,
        osm_hwy_target_tags=[
            "trunk",
            "trunk_link",
            "primary",
            "primary_link",
            "secondary",
            "secondary_link",
            "tertiary",
            "tertiary_link",
            "residential",
            "living_street",
            "service",
            "cycleway",
            "bridleway",
            "pedestrian",
            "steps",
            "footway",
            "footway_pedestrian",  # plazas
            "path",
            "unclassified",
        ],
        prioritise_by_hwy_tag=True,
        simplify_by_max_angle=max_angle,
    )
G = graphs.nx_remove_filler_nodes(G)
G = graphs.nx_merge_parallel_edges(
    G, merge_edges_by_midline=True, contains_buffer_dist=50
)
G = graphs.nx_iron_edges(G, min_self_loop_length=100, max_foot_tunnel_length=100)
# do this last to clean up any orphaned sub components
G = graphs.nx_remove_dangling_nodes(G, despine=25)

simple_plot(G, plot_geoms=True)
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 7848/7848 [00:00<00:00, 590914.60it/s]
100%|██████████| 7848/7848 [00:02<00:00, 3915.04it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 6548/6548 [00:00<00:00, 20905.35it/s]
INFO:cityseer.tools.graphs:Removing dangling nodes.
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 5677/5677 [00:00<00:00, 67105.55it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4953/4953 [00:00<00:00, 443935.12it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3772/3772 [00:00<00:00, 126781.32it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4953/4953 [00:00<00:00, 71733.53it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4916/4916 [00:00<00:00, 488328.88it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3772/3772 [00:00<00:00, 11699.42it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4969/4969 [00:00<00:00, 154639.19it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4959/4959 [00:00<00:00, 356223.84it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3772/3772 [00:00<00:00, 47441.73it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4960/4960 [00:00<00:00, 103815.78it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4960/4960 [00:00<00:00, 446394.04it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3772/3772 [00:00<00:00, 28074.91it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4961/4961 [00:00<00:00, 173050.53it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3772/3772 [00:00<00:00, 47360.78it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3772/3772 [00:00<00:00, 120584.40it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4961/4961 [00:00<00:00, 152703.15it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3772/3772 [00:00<00:00, 88422.05it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3721/3721 [00:00<00:00, 61545.70it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3721/3721 [00:00<00:00, 13502.96it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4502/4502 [00:00<00:00, 27979.26it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3399/3399 [00:00<00:00, 134060.91it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3363/3363 [00:00<00:00, 41359.24it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3363/3363 [00:00<00:00, 25477.78it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4317/4317 [00:00<00:00, 19456.19it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3329/3329 [00:00<00:00, 420706.80it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3321/3321 [00:00<00:00, 60348.00it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 3321/3321 [00:00<00:00, 18301.56it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4214/4214 [00:00<00:00, 118935.70it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3252/3252 [00:00<00:00, 322684.57it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 3246/3246 [00:00<00:00, 56495.62it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4201/4201 [00:00<00:00, 415122.06it/s]
INFO:cityseer.tools.graphs:Snapping gapped endings.
100%|██████████| 3246/3246 [00:00<00:00, 8505.20it/s] 
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 4317/4317 [00:00<00:00, 711102.79it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 3246/3246 [00:00<00:00, 5174.40it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 4840/4840 [00:00<00:00, 76564.37it/s]
INFO:cityseer.tools.graphs:Removing dangling nodes.
100%|██████████| 3540/3540 [00:00<00:00, 155781.39it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 3049/3049 [00:00<00:00, 12890.76it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 3644/3644 [00:00<00:00, 744727.56it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 2345/2345 [00:00<00:00, 5276.12it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 3665/3665 [00:00<00:00, 75182.55it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 2345/2345 [00:00<00:00, 55050.75it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 2345/2345 [00:00<00:00, 3595.37it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 3089/3089 [00:00<00:00, 24411.82it/s]
INFO:cityseer.tools.util:Creating edges STR tree.
100%|██████████| 2980/2980 [00:00<00:00, 242708.96it/s]
INFO:cityseer.tools.graphs:Splitting opposing edges.
100%|██████████| 1947/1947 [00:00<00:00, 5731.40it/s]
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 2987/2987 [00:00<00:00, 115945.60it/s]
INFO:cityseer.tools.util:Creating nodes STR tree
100%|██████████| 1947/1947 [00:00<00:00, 51563.78it/s]
INFO:cityseer.tools.graphs:Consolidating nodes.
100%|██████████| 1947/1947 [00:00<00:00, 3773.03it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
100%|██████████| 2622/2622 [00:00<00:00, 33965.44it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 1646/1646 [00:00<00:00, 48946.98it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 50.
100%|██████████| 2475/2475 [00:00<00:00, 66973.13it/s]
INFO:cityseer.tools.graphs:Ironing edges.
100%|██████████| 2457/2457 [00:00<00:00, 14246.93it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 1.
100%|██████████| 2446/2446 [00:00<00:00, 159265.83it/s]
INFO:cityseer.tools.graphs:Removing dangling nodes.
100%|██████████| 1558/1558 [00:00<00:00, 345606.39it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
100%|██████████| 1547/1547 [00:00<00:00, 104237.70it/s]
INFO:cityseer.tools.plot:Preparing graph nodes
INFO:cityseer.tools.plot:Preparing graph edges
100%|██████████| 2404/2404 [00:00<00:00, 24079.75it/s]