def create_network_from_nodes_and_edges(nodes,
                                        edges,
                                        node_edge_prefix,
                                        by=None):
    edges.columns = map(str.lower, edges.columns)
    if "id" in edges.columns.values.tolist():
        edges.rename(columns={"id": "e_id"}, inplace=True)

    # Deal with empty edges (drop)
    empty_idx = edges.geometry.apply(lambda e: e is None or e.is_empty)
    if empty_idx.sum():
        empty_edges = edges[empty_idx]
        print(f"Found {len(empty_edges)} empty edges.")
        print(empty_edges)
        edges = edges[~empty_idx].copy()

    network = snkit.Network(nodes, edges)
    print("* Done with network creation")

    network = snkit.network.split_multilinestrings(network)
    print("* Done with splitting multilines")

    if nodes is not None:
        network = snkit.network.snap_nodes(network)
        print('* Done with snapping nodes to edges')

        network.nodes = snkit.network.drop_duplicate_geometries(network.nodes)
        print('* Done with dropping same geometries')

        network = snkit.network.split_edges_at_nodes(network)
        print('* Done with splitting edges at nodes')

    network = snkit.network.add_endpoints(network)
    print('* Done with adding endpoints')

    network = snkit.network.split_edges_at_nodes(network, tolerance=1.0e-3)
    print('* Done with splitting edges at nodes')

    network = snkit.network.add_ids(network,
                                    edge_prefix=f"{node_edge_prefix}e",
                                    node_prefix=f"{node_edge_prefix}n")
    network = snkit.network.add_topology(network, id_col='id')
    print('* Done with network topology')

    if by is not None:
        network = snkit.merge_edges(network, by=by)
        print('* Done with merging network')

    network.edges.rename(columns={
        'from_id': 'from_node',
        'to_id': 'to_node',
        'id': 'edge_id'
    },
                         inplace=True)
    network.nodes.rename(columns={'id': 'node_id'}, inplace=True)

    # network.edges.to_file(out_fname, layer='edges', driver='GPKG')
    # network.nodes.to_file(out_fname, layer='nodes', driver='GPKG')

    return network
예제 #2
0
def main(raw_files):
    filtered_files = []
    for fname in tqdm(raw_files):
        print(f"\n{fname}")
        layers = fiona.listlayers(fname)
        out_fname = fname.replace('.gpkg', '_filtered.gpkg')
        filtered_files.append(out_fname)
        try:
            os.remove(out_fname)
        except FileNotFoundError:
            pass

        if 'points' in layers:
            df = process_points(gpd.read_file(fname, layer='points'))
            if not df.empty:
                df.to_file(out_fname, layer='points', driver="GPKG")

        if 'lines' in layers:
            df = process_lines(gpd.read_file(fname, layer='lines'))
            if not df.empty:
                df.to_file(out_fname, layer='lines', driver="GPKG")

        if 'multipolygons' in layers:
            df = process_polygons(gpd.read_file(fname, layer='multipolygons'))
            if not df.empty:
                df.to_file(out_fname, layer='multipolygons', driver="GPKG")

                df = polys_to_points(df)
                df.to_file(out_fname, layer='centroids', driver="GPKG")

    ## Connected network

    for fname in tqdm(filtered_files):
        country = os.path.basename(fname).replace('-rail_filtered.gpkg', '')
        print(country)

        out_fname = os.path.join('data',country,'networks',"rail.gpkg")
        try:
            os.remove(out_fname)
        except FileNotFoundError:
            pass

        nodes = read_nodes(fname)
        edges = read_edges(fname)

        network = snkit.Network(nodes, edges)
        network = snkit.network.snap_nodes(network)
        network = snkit.network.split_edges_at_nodes(network)
        network = snkit.network.add_endpoints(network)
        network = snkit.network.add_ids(
            network,
            edge_prefix=f"rail_{country}",
            node_prefix=f"rail_{country}")
        network = snkit.network.add_topology(network, id_col='id')

        network.edges.to_file(out_fname, layer='edges', driver='GPKG')
        network.nodes.to_file(out_fname, layer='nodes', driver='GPKG')
예제 #3
0
def edge_only():
    """Single edge:
    |
    |
    |
    """
    edge = LineString([(0, 0), (0, 2)])
    edges = GeoDataFrame([{"geometry": edge}])
    return snkit.Network(edges=edges)
예제 #4
0
def nodes_only():
    """Two nodes:
    x

    x
    """
    a = Point((0, 0))
    b = Point((0, 2))
    nodes = GeoDataFrame([{"geometry": a}, {"geometry": b}])
    return snkit.Network(nodes=nodes)
예제 #5
0
def misaligned():
    """Edge with nodes offset:
    b |
      |
      | a
    """
    edge = LineString([(0, 0), (0, 2)])
    a = Point((0.5, 0))
    b = Point((-0.5, 2))
    edges = GeoDataFrame([{"geometry": edge}])
    nodes = GeoDataFrame([{"geometry": a}, {"geometry": b}])
    return snkit.Network(edges=edges, nodes=nodes)
예제 #6
0
def connected():
    """Edge with nodes:
    b
    |
    a
    """
    a = Point((0, 0))
    b = Point((0, 2))
    edge = LineString([a, b])
    edges = GeoDataFrame([{"geometry": edge}])
    nodes = GeoDataFrame([{"geometry": a}, {"geometry": b}])
    return snkit.Network(edges=edges, nodes=nodes)
예제 #7
0
def unsplit():
    """T-junction with nodes, long edge not split:
    b
    |
    |c--d
    |
    a
    """
    a = Point((0, 0))
    b = Point((0, 2))
    c = Point((0, 1))
    d = Point((1, 1))
    ab = LineString([a, b])
    cd = LineString([c, d])
    edges = GeoDataFrame([ab, cd], columns=["geometry"])
    nodes = GeoDataFrame([a, b, c, d], columns=["geometry"])
    return snkit.Network(edges=edges, nodes=nodes)
예제 #8
0
def gap():
    """T-junction with nodes, edges not quite intersecting:
    b
    |
    | c--d
    |
    a
    """
    a = Point((0, 0))
    b = Point((0, 2))
    c = Point((0.1, 1))
    d = Point((1, 1))
    nodes = GeoDataFrame([a, b, c, d], columns=["geometry"])
    ab = LineString([a, b])
    cd = LineString([c, d])
    edges = GeoDataFrame([ab, cd], columns=["geometry"])
    return snkit.Network(edges=edges, nodes=nodes)
예제 #9
0
def split():
    """T-junction with nodes, long edge split:
      b
      |
      c--d
      |
      a
    """
    a = Point((0, 0))
    b = Point((0, 2))
    c = Point((0, 1))
    d = Point((1, 1))
    nodes = GeoDataFrame([a, b, c, d], columns=['geometry'])
    ac = LineString([a, c])
    cb = LineString([c, b])
    cd = LineString([c, d])
    edges = GeoDataFrame([ac, cb, cd], columns=['geometry'])
    return snkit.Network(edges=edges, nodes=nodes)
예제 #10
0
def test_passing_slice():
    """Passing a partial dataframe through add_ids should work fine, resetting index"""
    a = Point((0, 0))
    b = Point((0, 2))
    c = Point((0, 1))
    d = Point((1, 1))
    ac = LineString([a, c])
    cb = LineString([c, b])
    cd = LineString([c, d])
    edges = GeoDataFrame([ac, cb, cd], columns=["geometry"])
    network = snkit.Network(edges=edges[1:])
    with_endpoints = snkit.network.add_endpoints(network)
    with_ids = snkit.network.add_ids(with_endpoints)

    actual = with_ids.edges
    expected = GeoDataFrame([(cb, "edge_0"), (cd, "edge_1")],
                            columns=["geometry", "id"])

    print(actual)
    assert_frame_equal(actual, expected)
예제 #11
0
def bridged():
    """T-junction with nodes, bridged by short edge:
    b
    |
    e-c--d
    |
    a
    """
    a = Point((0, 0))
    b = Point((0, 2))
    c = Point((0.1, 1))
    d = Point((1, 1))
    e = Point((0, 1))
    nodes = GeoDataFrame([a, b, c, d, e], columns=["geometry"])
    ae = LineString([a, e])
    eb = LineString([e, b])
    cd = LineString([c, d])
    ce = LineString([c, e])
    edges = GeoDataFrame([ae, eb, cd, ce], columns=["geometry"])
    return snkit.Network(edges=edges, nodes=nodes)
예제 #12
0
def split_with_ids():
    """T-junction with nodes, long edge split, and node and edge ids:
     b
    2| 3
     c---d
    1|
     a
    """
    a = Point((0, 0))
    b = Point((0, 2))
    c = Point((0, 1))
    d = Point((1, 1))
    nodes = GeoDataFrame(data={
        "geometry": [a, b, c, d],
        "id": ["a", "b", "c", "d"]
    })
    ac = LineString([a, c])
    cb = LineString([c, b])
    cd = LineString([c, d])
    edges = GeoDataFrame(data={"geometry": [ac, cb, cd], "id": [1, 2, 3]})
    return snkit.Network(edges=edges, nodes=nodes)
예제 #13
0
def main():
    edges = geopandas.GeoDataFrame.from_features(ROADS)
    nodes = geopandas.GeoDataFrame.from_features(DISTRIBUTION_POINT + PREMISES)
    network = snkit.Network(nodes, edges)
    print("\n# init\n")
    print(network.nodes)
    print(network.edges)
    plot(network)

    # add endpoints
    network = snkit.network.add_endpoints(network)

    # snap to nearest edge
    print("\n# snap to nearest edge\n")
    network = snkit.network.link_nodes_to_nearest_edge(network)

    # add node ids and edge to_id/from_id
    network = snkit.network.add_ids(network)
    network = snkit.network.add_topology(network)
    print(network.nodes)
    print(network.edges)
    plot(network)

    # approx min tree

    # construct graph
    edges = list(network.edges.iterfeatures())
    nodes = list(network.nodes.iterfeatures())
    graph = networkx.Graph()
    for node in nodes:
        graph.add_node(node['properties']['id'], **node['properties'])
    for edge in edges:
        graph.add_edge(edge['properties']['from_id'],
                       edge['properties']['to_id'],
                       length=line_length(shape(edge['geometry'])))

    source_id = None
    sink_ids = []
    for node in nodes:
        if node['properties']['name'] == 'distribution_point':
            source_id = node['properties']['id']
        if node['properties']['name'] in [
                'premises_1', 'premises_2', 'premises_3'
        ]:
            sink_ids.append(node['properties']['id'])

    # key function - uses shortest paths over network, but deduplicated
    tree = shortest_path_tree(graph, source_id, sink_ids)

    print(tree.nodes)  # node ids
    print(tree.edges)  # edges as from-to node ids

    # recover features
    tree_nodes = [
        node for node in nodes if node['properties']['id'] in tree.nodes
    ]

    tree_edges = []
    for edge in edges:
        a = edge['properties']['from_id']
        b = edge['properties']['to_id']

        if (a, b) in tree.edges or (b, a) in tree.edges:
            tree_edges.append(edge)

    # as gdf again for ease of plotting
    network = snkit.Network(geopandas.GeoDataFrame.from_features(tree_nodes),
                            geopandas.GeoDataFrame.from_features(tree_edges))
    plot(network)
    print(tree_edges)
    print(tree_nodes)
예제 #14
0
def test_init():
    """Should create an empty network"""
    net = snkit.Network()
    assert len(net.nodes) == 0
    assert len(net.edges) == 0