Shapely :不带逗号的元组与 LineString

Shapely : tuples without commas with LineString

这很复杂,但长话短说:我已经使用了几个像 OSMNx 这样的库来绘制城市多个地点之间的路线。现在我将其转换为 shp 文件。

路由是一个充满节点id的列表。然后这些id被用来提取每个节点的纬度和经度。我制作了元组来连接每个节点的坐标(一个开始,一个到达)和一个 for 循环,就像这样:

journey = [] 
# previous list will contain tuples with coordinates of each node

for node1, node2 in zip(route[:-1], route[1:]):
    parcours.append(tuple((G.node[noeud1]['x'], G.node[noeud1]['y']))) # we create a tuple with coordinates of start's node
    parcours.append(tuple((G.node[noeud2]['x'], G.node[noeud2]['y']))) # then we make the same for the arrival node

这是循环结束时 print(journey) 的结果:

[(6.15815, 48.6996136), (6.1629696, 48.7007431), (6.1629696, 48.7007431), [...], (6.1994411, 48.6768434), (6.1994411, 48.6768434), (6.1995322, 48.6767583)]

每个元组都正确显示。但是当我想在一个匀称的 LineString 中转换旅程时......它 returns 这个 :

from shapely.geometry import LineString
final_journey = LineString(journey)
print(final_journey)
LINESTRING (6.15815 48.6996136, 6.1629696 48.7007431, 6.1629696 48.7007431, 6.1630717 48.7002871, [...], 6.1991794 48.677085, 6.1994411 48.6768434, 6.1994411 48.6768434, 6.1995322 48.6767583)

因此,我无法使用 fiona 在 shp 中转换它:

import fiona
schema = {
    'geometry': 'Polygon',
    "properties": {'id': 123}
}

with fiona.open('test.shp', 'w', 'ESRI Shapefile', schema) as c:
    c.write({
        'geometry': mapping(trace)
    })

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) in () 4 } 5 ----> 6 with fiona.open('test.shp', 'w', 'ESRI Shapefile', schema) as c: 7 c.write({ 8 'geometry': mapping(trace)

/usr/local/lib/python3.5/dist-packages/fiona/init.py in open(path, mode, driver, schema, crs, encoding, layer, vfs, enabled_drivers, crs_wkt) 173 c = Collection(path, mode, crs=crs, driver=driver, schema=this_schema, 174 encoding=encoding, layer=layer, vsi=vsi, archive=archive, --> 175 enabled_drivers=enabled_drivers, crs_wkt=crs_wkt) 176 else: 177 raise ValueError(

/usr/local/lib/python3.5/dist-packages/fiona/collection.py in init(self, path, mode, driver, schema, crs, encoding, layer, vsi, archive, enabled_drivers, crs_wkt, **kwargs) 154 elif self.mode in ('a', 'w'): 155 self.session = WritingSession() --> 156 self.session.start(self, **kwargs) 157 except IOError: 158 self.session = None

fiona/ogrext.pyx in fiona.ogrext.WritingSession.start (fiona/ogrext2.c:16207)()

TypeError: argument of type 'int' is not iterable

我不明白为什么转换元组时纬度和经度之间没有逗号。此外,有几个重复(第三行的第二个坐标是第四行的第一个坐标,等等...),这可能是未来 shp 的错误来源。

提前致谢!

我不认为获取节点坐标然后将它们连接在一起是您能做的最好的事情。如果街道不直怎么办? OSMnx 为您提供街道的精确几何形状。提取节点的几何形状,解释了更好的解决方案 。但是你需要街道的几何形状。由于两个节点之间可能有不止一条边,因此这并不总是很容易做到。我相信 ox.get_route_edge_attributes() 应该能够做到这一点,而且如果您要求另一个属性(例如 highway),它确实会很好用,但不能提取边缘的 geometry。原因(我猜)是并非 G 中的所有边都有 geometry,但是如果你得到网络的 gdf_edges,那么你总是有每条边的几何形状。以下是我发现的解决方法:

gdf_nodes, gdf_edges = ox.graph_to_gdfs(G)
path = nx.shortest_path(G, G.nodes()[0], G.nodes()[1])

获取路径中节点的GeoDataFrame:

output_points = gdf_nodes.loc[path]
output_points.plot(color='red')

为了获取边的几何形状,首先将 u、v 值的元组设置为 gdf_edges 的索引,然后 loc 到 select 路径的 GeoDataFrame:

gdf_edges.index = gdf_edges.apply(lambda row: (row.u, row.v), axis=1)
output_lines = gdf_edges.loc[list(zip(path[:-1], path[1:]))]
output_lines.plot(color='red')

然后您可以将其保存到 shapefile:

output_edges.to_file()

一个重要的评论:正如我已经说过的,两个节点之间可以有不止一条边。这意味着要唯一标识一条边,uv(边的开始和结束)是不够的,您还需要 key,它由 OSMnx 自动添加,您可以在图形和每个边的 gdf_edges 中找到它。所以如果你使用上面的代码,请注意它会给你 all 节点之间的边缘(如果有多个)。快速检查是:len(np.nonzero(output_edges['key'])[0])。如果没有平行边,这肯定为零。如果不是,则说明存在平行边。

更新

OSMnx 具有从 GeoDataFrame 保存 shapefile 的功能:

p = '/path/to/destination/'
ox.save_gdf_shapefile(output_lines, 'output', p)

to_file() 添加模式似乎也有效:

sch = {'geometry': 'LineString',
       'properties': {'key': 'int',
                        'u': 'int',
                        'v': 'int'}}

test = gpd.GeoDataFrame(output_lines[['u', 'v', 'key']], 
                        geometry=output_lines['geometry'], crs='+init=EPSG:3740')

test.to_file('/path/to/destination/test.shp', schema=sch)