微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

OSMNX + NetworkX graph_from_gdfs 使用 nx.ego_graph

如何解决OSMNX + NetworkX graph_from_gdfs 使用 nx.ego_graph

尝试将地理包边和节点图层加载为 NetworkX Graph,但在使用“nx.ego_graph”时未能获得返回的正确节点。使用版本 OSMNX 1.0,NetworkX 2.5。

在之前的 question G 波音公司协助使用 Geopackage to Graph 功能

我现在有一个 Graph 对象,但分析似乎不像使用 True Graph 对象时那样工作,例如G = ox.graph_from_point((53.956748,-1.081676)).

我想为不同的旅行时间创建等时线,并重复使用波音先生在此 example 中已经完成的聪明工作。我想主要使用 'buffer' 选项 - 而不是凸包。

当使用 G = ox.graph_from_point((53.956748,-1.081676),dist=2000,dist_type='network') 即动态下载 osm 数据时,上面示例中的分析目前工作正常,但我有一个特定的工作流程,其中我将数据导出到地理包并进行编辑、添加一些节点和边以表示可能的新道路。

即使不编辑 Geopackage 数据,我也无法进行分析,不同旅行时间返回的节点出现错误。 10 分钟行程时间的等时线多边形与 5 分钟行程时间相同。而且我不相信 5 分钟旅行时间多边形是正确的,因为它是一个非常小的区域。

Isochrone polygon seems wrong

如果您运行下面的脚本,您已经可以看到在设置节点颜色时存在问题,因为行程时间 5 和 10 返回相同的确切节点(子图 = nx.ego_graph(G=G,n=origin_node,radius =trip_time,distance='time')).

有谁知道这是否表明在使用'ox.graph_from_gdfs'时可能没有正确生成Graph对象?或者是否需要进行更改?

我尝试在 nx.ego_graph 中使用 'undirected=True' 并返回......可能是颜色设置部分中的正确节点,但在生成多边形时,我收到此错误:>

edge_lookup = G.get_edge_data(n_fr,n_to)[0].get('geometry',Linestring([f,t]))
KeyError: 0

在测试中我发现:

  • 使用缓冲区等时线方法和 nx.ego_graph: undirected=True - 给出上面的错误
  • 使用缓冲区等时线方法和 nx.ego_graph: undirected=False - 给出了最奇异的梨形多边形,它覆盖了北欧的一半(应该是英国的一个站点
  • 使用凸包等时线方法和 nx.ego_graph: undirected=False- 为每次旅行提供相同的多边形,并且这两个多边形的形状都不正确 - 太小了
  • 使用凸包等时线方法和 nx.ego_graph: undirected=True- 为每次旅行提供正确的多边形,10 分钟大于 5 分钟等

再次参见 example 以了解凸包方法

希望有人知道如何纠正错误

代码

geopPath = "Transport_Analysis.gpkg"
geopPath2 = "Transport_Analysis2.gpkg"

yG = 53.9582559586775  # epsg:4326 Geographic
xG = -1.07662649048548 # epsg:4326 Geographic
yP = 451746.474534685  # epsg:27700 Projected
xP = 460685.875721401  # epsg:27700 Projected

distance = 2000
network_type = 'walk'
trip_times = [5,10,15,20,25,30]
travel_speed = 4.5

trip_times = trip_times[0:2]  # limit to just first 2 for testing

usewgs84 = True # True False Choose to use Geographic or Projected Coordinates

if usewgs84 == True:
    epsg = 4326
    orig = (yG,xG) # epsg:4326
    print("Using Geographic coords: {},{}".format(xG,yG))
    graph_attrs = {'crs': 'epsg:4326','simplified': True}
else:
    epsg = 27700 # for my project site in the UK
    orig = (yP,xP) # epsg:27700
    print("Using Projected coords: {},{}".format(xP,yP))
    graph_attrs = {'crs': 'epsg:{}'.format(epsg),'simplified': True}

download = 0
if download == 1:
    print("Downloading OSMNX")
    G = ox.graph_from_point(orig,dist=distance,dist_type='network')
    origin_node = ox.get_nearest_node(G,orig)
    print("Downloaded OSMNX")                       
    ox.io.save_graph_geopackage(G,filepath=geopPath2,encoding='utf-8')
    geopPath = geopPath2
else:
    print("Using existing geopackage: {}".format(geopPath))

# geopPath edges and nodes in native osm epsg:4326
# load GeoPackage as node/edge GeoDataFrames indexed as described in OSMnx docs
gdf_nodes = gpd.read_file(geopPath,layer='nodes').set_index('osmid')
gdf_edges = gpd.read_file(geopPath,layer='edges').set_index(['u','v','key'])                
assert gdf_nodes.index.is_unique and gdf_edges.index.is_unique

print("### Loading Existing geopackage road edges and nodes as Graph")
# convert the node/edge GeoDataFrames to a MultiDiGraph
G = ox.graph_from_gdfs(gdf_nodes,gdf_edges,graph_attrs)

if usewgs84 != True:  # choose to use projected coordinates for origin/graph instead of geographic
    crsObj = CRS.from_user_input(epsg)
    # Finally converting graph to projected CRS
    G = ox.project_graph(G,to_crs=crsObj)  

origin_node = ox.get_nearest_node(G,orig)
print("closest node to coordinate: {} (coord Y,X: {})".format(origin_node,orig))

# add an edge attribute for time in minutes required to traverse each edge
meters_per_minute = travel_speed * 1000 / 60 #km per hour to m per minute
for u,v,k,data in G.edges(data=True,keys=True):
    #print(data['time'])
    data['time'] = data['length'] / meters_per_minute
iso_colors = ox.plot.get_colors(n=len(trip_times),cmap='plasma',start=0,return_hex=True)

# color the nodes according to isochrone then plot the street network
node_colors = {}
for trip_time,color in zip(sorted(trip_times,reverse=False),iso_colors):
    subgraph = nx.ego_graph(G=G,radius=trip_time,undirected=True,distance='time') # 
    print("Trip time: {}. Subgraph.nodes: {}. Subnodes: {}".format(trip_time,len(subgraph.nodes()),subgraph.nodes()))
    for node in subgraph.nodes():
        node_colors[node] = color

tripReverse = False

edge_buff=25
node_buff=0
infill=False
isochrone_polys = []

#trip_times = list(trip_times)

for trip_time in sorted(trip_times,reverse=tripReverse):  #,undirected=True
    subgraph = nx.ego_graph(G=G,distance='time')

    node_points = [Point((data['x'],data['y'])) for node,data in subgraph.nodes(data=True)]
    nodes_gdf = gpd.GeoDataFrame({'id': list(subgraph.nodes())},geometry=node_points)
    nodes_gdf = nodes_gdf.set_index('id')
    
    print("Trip time: {}. Nodes: {}".format(trip_time,len(node_points)))
    #print("node_points: {}".format(node_points))
    edge_lines = []
    for n_fr,n_to in subgraph.edges():
        f = nodes_gdf.loc[n_fr].geometry
        t = nodes_gdf.loc[n_to].geometry
        edge_lookup = G.get_edge_data(n_fr,t]))
        edge_lines.append(edge_lookup)

    n = nodes_gdf.buffer(node_buff).geometry
    e = gpd.GeoSeries(edge_lines).buffer(edge_buff).geometry
    all_gs = list(n) + list(e)
    new_iso = gpd.GeoSeries(all_gs).unary_union
    
    # try to fill in surrounded areas so shapes will appear solid and blocks without white space inside them
    if infill:
        new_iso = polygon(new_iso.exterior)
    isochrone_polys.append(new_iso)
    #print("new_iso: {}".format(new_iso))

        

iso_df = pd.DataFrame({'trip_times_mins':trip_times[::-1],'color':colors,'geom':polys[::-1]})
iso_df = gpd.GeoDataFrame(iso_df,crs='epsg:{}'.format(epsg),geometry='geom')
# export isochrones to geopackage 
iso_df.to_file(geopPath,driver='GPKG',layer='isochrone_{}'.format(network_type))
print("Written isochrone")

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。