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
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')
def edge_only(): """Single edge: | | | """ edge = LineString([(0, 0), (0, 2)]) edges = GeoDataFrame([{"geometry": edge}]) return snkit.Network(edges=edges)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
def test_init(): """Should create an empty network""" net = snkit.Network() assert len(net.nodes) == 0 assert len(net.edges) == 0