Python osmnx get_nearest_Edge函数结果不清楚在哪个键上
python映射包osmnx中的get_nearest_edges函数似乎只返回基于节点u和v的结果。但在某些情况下,地图下载功能会在两个节点之间返回多条边。如何判断该点最接近的边是哪条边 例如,使用下图中的数据:Python osmnx get_nearest_Edge函数结果不清楚在哪个键上,python,osmnx,Python,Osmnx,python映射包osmnx中的get_nearest_edges函数似乎只返回基于节点u和v的结果。但在某些情况下,地图下载功能会在两个节点之间返回多条边。如何判断该点最接近的边是哪条边 例如,使用下图中的数据: G = ox.graph_from_point((38.75,-77.15), distance=(5*1609.34),distance_type='bbox',simplify=True, network_type='drive', retain_all=True,truncat
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)
并拉入生成的网络节点G[63441180][63441059],它显示了带有键1和键2的两条边以及不同的几何图形(如果绘制几何图形,它似乎是循环的两个独立部分)。以下是节点:
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>}})
AtlasView({1:{'osmid':8808231,'名称':'亨特堡公园环路','高速公路':'未分类','单向':False,'长度':1698.89200000000003,'几何体':},2:{'osmid':8808231,'名称':'亨特堡公园环路','高速公路':'未分类','单向':False,'长度':289.381,'几何体':})
如果我要搜索最接近点列表的边,但是我得到的结果只有u和v,因此不要告诉我这两个点之间的哪条边(即哪个关键点)是正确的
我错过什么了吗?或者这是一个bug?更新:正如gboeing在上面的评论中所指出的,库的最新版本已经修复了这个bug 随着进一步的研究,在我看来,这可能确实是一个bug。因此,我已经在图书馆为这本书发行了一期。任何想了解这一进程的人都可以在那里这样做 正如上面提到的,我还为自己的目的编写了一个临时修复程序,以便在库发生更改(或我对情况的理解得到纠正)之前正确地发布这些信息。下面是代码,还包括使函数正确运行所需的附加导入。但是,随附的文档尚未更新
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)```
此错误已在最新版本中修复。