首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >osmnx get_nearest_edges函数的结果不清楚是哪个键

osmnx get_nearest_edges函数的结果不清楚是哪个键
EN

Stack Overflow用户
提问于 2020-04-29 19:32:50
回答 1查看 1K关注 0票数 0

python映射包osmnx中的get_nearest_edges函数似乎只根据节点u和v返回结果。在某些情况下,地图下载函数返回两个节点之间的多个边。如何辨别这些边中的哪条边最接近该点?

例如,使用下图中的数据:

代码语言:javascript
运行
复制
G = ox.graph_from_point((38.75,-77.15), distance=(5*1609.34),distance_type='bbox',simplify=True, network_type='drive', retain_all=True,truncate_by_edge=True,clean_periphery=True)

并在结果网络中拉入节点G63441180,它显示具有关键点1和2的两条边以及不同的几何图形(如果绘制几何图形,它将显示为循环的两个独立部分)。下面是节点:

代码语言:javascript
运行
复制
AtlasView({1: {'osmid': 8808231, 'name': 'Fort Hunt Park Loop', 'highway': 'unclassified', 'oneway': False, 'length': 1698.8920000000003, 'geometry': <shapely.geometry.linestring.LineString object at 0x7f1250b8e3c8>}, 2: {'osmid': 8808231, 'name': 'Fort Hunt Park Loop', 'highway': 'unclassified', 'oneway': False, 'length': 289.381, 'geometry': <shapely.geometry.linestring.LineString object at 0x7f1250b8e320>}})

但是,如果我要搜索最接近点列表的边,我得到的结果只有u和v,因此不要告诉我这两个点之间的哪条边(即哪个关键字)是正确的。

我是不是遗漏了什么?或者这是一个bug?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-30 01:08:49

更新:正如gboeing在上面的评论中指出的那样,该库的最新版本已经修复了这个错误。

随着进一步的研究,在我看来这可能确实是一个bug。因此,我在https://github.com/gboeing/osmnx/issues/435上的库中为此打开了一个问题。任何想要跟踪这一进程的人都可以在那里这样做。

正如这里所提到的,我还为自己的目的编写了一个临时修复程序,以便正确地获取这些信息,除非/直到库被更改(或者我对这种情况的理解被纠正)。代码如下所示,还包括使函数正常工作所需的额外导入。然而,与它相关的文档尚未更新。

代码语言:javascript
运行
复制
from shapely.geometry import Point
from osmnx import redistribute_vertices
import logging as lg
from osmnx.utils import log
import time
from scipy.spatial import cKDTree
from sklearn.neighbors import BallTree

def get_nearest_edge(G, point,return_key=False):
    """
    Return the nearest edge to a pair of coordinates. Pass in a graph and a tuple
    with the coordinates. We first get all the edges in the graph. Secondly we compute
    the euclidean distance from the coordinates to the segments determined by each edge.
    The last step is to sort the edge segments in ascending order based on the distance
    from the coordinates to the edge. In the end, the first element in the list of edges
    will be the closest edge that we will return as a tuple containing the shapely
    geometry and the u, v nodes.
    Parameters
    ----------
    G : networkx multidigraph
    point : tuple
        The (lat, lng) or (y, x) point for which we will find the nearest edge
        in the graph
    Returns
    -------
    closest_edge_to_point : tuple (shapely.geometry, u, v)
        A geometry object representing the segment and the coordinates of the two
        nodes that determine the edge section, u and v, the OSM ids of the nodes.
    """
    start_time = time.time()

    gdf = graph_to_gdfs(G, nodes=False, fill_edge_geometry=True)
    if return_key:
        graph_edges = gdf[["geometry", "u", "v","key"]].values.tolist()
    else:
        graph_edges = gdf[["geometry", "u", "v"]].values.tolist()


    edges_with_distances = [
        (
            graph_edge,
            Point(tuple(reversed(point))).distance(graph_edge[0])
        )
        for graph_edge in graph_edges
    ]

    edges_with_distances = sorted(edges_with_distances, key=lambda x: x[1])
    closest_edge_to_point = edges_with_distances[0][0]

    if return_key:
        geometry, u, v,key = closest_edge_to_point
    else:
        geometry, u, v = closest_edge_to_point

    log('Found nearest edge ({}) to point {} in {:,.2f} seconds'.format((u, v), point, time.time() - start_time))

    if return_key:
        return geometry, u, v, key
    else:
        return geometry, u, v


def get_nearest_edges(G, X, Y, method=None, dist=0.0001,return_key=False):
    """
    Return the graph edges nearest to a list of points. Pass in points
    as separate vectors of X and Y coordinates. The 'kdtree' method
    is by far the fastest with large data sets, but only finds approximate
    nearest edges if working in unprojected coordinates like lat-lng (it
    precisely finds the nearest edge if working in projected coordinates).
    The 'balltree' method is second fastest with large data sets, but it
    is precise if working in unprojected coordinates like lat-lng. As a
    rule of thumb, if you have a small graph just use method=None. If you 
    have a large graph with lat-lng coordinates, use method='balltree'.
    If you have a large graph with projected coordinates, use 
    method='kdtree'. Note that if you are working in units of lat-lng,
    the X vector corresponds to longitude and the Y vector corresponds
    to latitude.
    Parameters
    ----------
    G : networkx multidigraph
    X : list-like
        The vector of longitudes or x's for which we will find the nearest
        edge in the graph. For projected graphs, use the projected coordinates,
        usually in meters.
    Y : list-like
        The vector of latitudes or y's for which we will find the nearest
        edge in the graph. For projected graphs, use the projected coordinates,
        usually in meters.
    method : str {None, 'kdtree', 'balltree'}
        Which method to use for finding nearest edge to each point.
        If None, we manually find each edge one at a time using
        osmnx.utils.get_nearest_edge. If 'kdtree' we use
        scipy.spatial.cKDTree for very fast euclidean search. Recommended for
        projected graphs. If 'balltree', we use sklearn.neighbors.BallTree for
        fast haversine search. Recommended for unprojected graphs.
    dist : float
        spacing length along edges. Units are the same as the geom; Degrees for
        unprojected geometries and meters for projected geometries. The smaller
        the value, the more points are created.
    Returns
    -------
    ne : ndarray
        array of nearest edges represented by their startpoint and endpoint ids,
        u and v, the OSM ids of the nodes.
    Info
    ----
    The method creates equally distanced points along the edges of the network.
    Then, these points are used in a kdTree or BallTree search to identify which
    is nearest.Note that this method will not give the exact perpendicular point
    along the edge, but the smaller the *dist* parameter, the closer the solution
    will be.
    Code is adapted from an answer by JHuw from this original question:
    https://gis.stackexchange.com/questions/222315/geopandas-find-nearest-point
    -in-other-dataframe
    """
    start_time = time.time()

    if method is None:
        # calculate nearest edge one at a time for each (y, x) point
        ne = [get_nearest_edge(G, (y, x),return_key) for x, y in zip(X, Y)]
        if return_key:
            ne = [(u, v,k) for _, u, v,k in ne]
        else:
            ne = [(u, v) for _, u, v in ne]

    elif method == 'kdtree':

        # check if we were able to import scipy.spatial.cKDTree successfully
        if not cKDTree:
            raise ImportError('The scipy package must be installed to use this optional feature.')

        # transform graph into DataFrame
        edges = graph_to_gdfs(G, nodes=False, fill_edge_geometry=True)

        # transform edges into evenly spaced points
        edges['points'] = edges.apply(lambda x: redistribute_vertices(x.geometry, dist), axis=1)

        # develop edges data for each created points
        extended = edges['points'].apply([pd.Series]).stack().reset_index(level=1, drop=True).join(edges).reset_index()

        # Prepare btree arrays
        nbdata = np.array(list(zip(extended['Series'].apply(lambda x: x.x),
                                   extended['Series'].apply(lambda x: x.y))))

        # build a k-d tree for euclidean nearest node search
        btree = cKDTree(data=nbdata, compact_nodes=True, balanced_tree=True)

        # query the tree for nearest node to each point
        points = np.array([X, Y]).T
        dist, idx = btree.query(points, k=1)  # Returns ids of closest point
        eidx = extended.loc[idx, 'index']
        if return_key:
            ne = edges.loc[eidx, ['u', 'v','key']]
        else:
            ne = edges.loc[eidx, ['u', 'v']]

    elif method == 'balltree':

        # check if we were able to import sklearn.neighbors.BallTree successfully
        if not BallTree:
            raise ImportError('The scikit-learn package must be installed to use this optional feature.')

        # transform graph into DataFrame
        edges = graph_to_gdfs(G, nodes=False, fill_edge_geometry=True)

        # transform edges into evenly spaced points
        edges['points'] = edges.apply(lambda x: redistribute_vertices(x.geometry, dist), axis=1)

        # develop edges data for each created points
        extended = edges['points'].apply([pd.Series]).stack().reset_index(level=1, drop=True).join(edges).reset_index()

        # haversine requires data in form of [lat, lng] and inputs/outputs in units of radians
        nodes = pd.DataFrame({'x': extended['Series'].apply(lambda x: x.x),
                              'y': extended['Series'].apply(lambda x: x.y)})
        nodes_rad = np.deg2rad(nodes[['y', 'x']].values.astype(np.float))
        points = np.array([Y, X]).T
        points_rad = np.deg2rad(points)

        # build a ball tree for haversine nearest node search
        tree = BallTree(nodes_rad, metric='haversine')

        # query the tree for nearest node to each point
        idx = tree.query(points_rad, k=1, return_distance=False)
        eidx = extended.loc[idx[:, 0], 'index']
        if return_key:
            ne = edges.loc[eidx, ['u', 'v','key']]
        else:
            ne = edges.loc[eidx, ['u', 'v']]

    else:
        raise ValueError('You must pass a valid method name, or None.')

    log('Found nearest edges to {:,} points in {:,.2f} seconds'.format(len(X), time.time() - start_time))

    return np.array(ne)```
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61500820

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档