我遇到了一个奇怪的行为,我不明白它也可能是一个错误。机缘巧合,我发现拉脱维亚和波兰之间的铁路网距离明显高于回程。我对此没有任何解释。
import pandas as pd
import plotly.express as px
from scgraph_data.world_railways import world_railways_geograph
from haversine import haversine, Unit
# Latvia -> Poland
origin_node = {'latitude': 57.44720526589874, 'longitude': 25.349758294373878}
destination_node = {'latitude': 53.19471528057347, 'longitude': 14.658120650544548}
# Poland -> Latvia
# destination_node = {'latitude': 57.44720526589874, 'longitude': 25.349758294373878}
# origin_node = {'latitude': 53.19471528057347, 'longitude': 14.658120650544548}
sp = world_railways_geograph.get_shortest_path(origin_node=origin_node, destination_node=destination_node)
network_distance = sp['length']
direct_distance = haversine((origin_node['latitude'], origin_node['longitude']), (destination_node['latitude'], destination_node['longitude']), unit=Unit.KILOMETERS)
detour_index = round(network_distance / direct_distance, 4)
print('Direct distance:', direct_distance, ', Network distance:', network_distance, ', Detour Index:', detour_index)
# Print route
df = pd.DataFrame(sp['coordinate_path'], columns=['latitude', 'longitude'])
fig = px.scatter_mapbox(df, lat='latitude', lon='longitude', zoom=3, height=400)
fig.update_layout(mapbox_style="open-street-map")
fig.show()
这与 scgraph 如何将任意起点/目的地节点添加到每个地理图中有关。将
node_addition_circuity
增加到更大的值(例如 10)应该可以解决问题。
请参阅文档此处。
默认情况下,源节点被添加到网络中,连接每个象限(ne、nw、se、sw)中最接近的 4 个节点。这被参数化为
node_addition_type
。这允许通过网络更快地搜索路线。
目标节点被添加到网络中,将网络中的所有节点(包括源节点)连接到它。这不是参数化的,也不能更改以确保非连接地理区域的解决方案是可能的。
添加起始节点和目标节点时默认为
node_addition_circuity=4
。这意味着半正弦 * 4 是为了求解目的而计算的到每个节点的距离。求解后,这些距离被修改为 off_graph_circuity
因子,默认为 1(只是半正矢)。这样做的目的是防止不合理的解决方案脱离图形,但仍然允许它并在脱离图形时仍然提供准确的距离。
用例:博洛尼亚 -> 纽约使用海运网络。尽管有港口要求,最短的路径是从意大利西海岸发货,尽管博洛尼亚距离意大利东海岸更近。远离图表旅行比绕意大利一周旅行更好。
替代用例:使用海运网络的宁波 -> 柏林。您不会想完全断开网络直接前往柏林,因为您正在尝试使用海上网络,即使图形路线会更长。
就您而言,拉脱维亚铁路网的数据在叶尔加瓦和里加之间没有连接。这可能是开放街道地图数据的问题(缺少链接/铁路分类错误 - 我们仅将主要商业数据用于世界铁路数据)。
当目的地靠近瓦尔米耶拉时,从叶尔加瓦离开网络直接前往瓦尔米耶拉的时间比通过互联网络一路穿越俄罗斯要短 4 倍多。当出发点位于瓦尔米耶拉附近时,只有 4 个离网选项(4 个象限),因此无法选择一路跳转到叶尔加瓦。
from scgraph_data.world_railways import world_railways_geograph
import folium
# Poland -> Latvia
destination_node = {'latitude': 57.44720526589874, 'longitude': 25.349758294373878}
origin_node = {'latitude': 53.19471528057347, 'longitude': 14.658120650544548}
def adjustArcPath(path):
for index in range(1, len(path)):
x = path[index][1]
prevX = path[index - 1][1]
path[index][1] = x - (round((x - prevX)/360,0) * 360)
return path
def modifyArcPathLong(points, amount):
return [[i[0], i[1]+amount] for i in points]
def getCleanArcPath(path):
path = adjustArcPath(path)
return [
path,
modifyArcPathLong(path, 360),
modifyArcPathLong(path, -360),
modifyArcPathLong(path, 720),
modifyArcPathLong(path, -720)
]
node_addition_circuity=4
(默认):sp4 = world_railways_geograph.get_shortest_path(
origin_node=origin_node,
destination_node=destination_node,
node_addition_circuity=4,
)
# Create a folium map
map4 = folium.Map([55, 20], zoom_start=6)
# Populate it with the path
folium.PolyLine(
getCleanArcPath(sp4['coordinate_path']),
color='green',
weight=5,
opacity=0.5,
popup='Length (KM): ' + str(sp4['length'])
).add_to(map4)
map4
注意路线如何从图表中跳出,并有最后一段是通往目的地的完美直线。
node_addition_circuity=10
:sp10 = world_railways_geograph.get_shortest_path(
origin_node=origin_node,
destination_node=destination_node,
node_addition_circuity=10,
)
# Create a folium map
map10 = folium.Map([55, 20], zoom_start=6)
# Populate it with the path
folium.PolyLine(
getCleanArcPath(sp10['coordinate_path']),
color='green',
weight=5,
opacity=0.5,
popup='Length (KM): ' + str(sp10['length'])
).add_to(map10)
map10
这应该与备用方向路径和距离几乎完全匹配。
还值得注意的是,如果您想避免额外的导出,scgraph 内置了半正弦值。
参见:https://connor-makowski.github.io/scgraph/scgraph/utils.html#haversine
from scgraph.utils import haversine
haversine(
origin=[origin_node['latitude'], origin_node['longitude']],
destination=[destination_node['latitude'], destination_node['longitude']],
units='km',
circuity=1
)