“Momepy 是一个用于城市形态定量分析的库 - 城市形态计量学。它是 PySAL(Python 空间分析库)的一部分,构建在 GeoPandas、其他 PySAL 模块和 networkX 之上。” momepy 文档
使用 Fleischmann、Martin、Alessandra Feliciotti 和 William Kerr 的代码(下面的相关部分)。“城市模式的演变:城市形态学作为一种开放的可重复数据科学。” 地理分析,2021 年 7 月 15 日,gean.12302。https://doi.org/10.1111/gean.12302。
我正在使用 OSM 数据来检查美国伊利诺伊州中部四个小城市的形态特征。由于某种我无法理解的原因,我只在一个城市中遇到了计算形态镶嵌单元的问题。我已经包含了一个指向下面镶嵌单元图像的链接(我不允许嵌入照片)。
感谢您的任何帮助!
%%capture --no-stdout
for i, coords in cases.origin.iteritems():
s = time()
"""
donwload and process elements of urban form
"""
# download buildings from OSM
point = tuple(map(float, coords[1:-1].split(', ')))[::-1]
buildings = osmnx.geometries.geometries_from_point(point, dist=1000, tags={'building':True})
buildings = osmnx.projection.project_gdf(buildings)
buildings = buildings[buildings.geom_type.isin(['Polygon', 'MultiPolygon'])]
buildings = buildings.reset_index(drop=True).explode().reset_index(drop=True)
buildings = buildings[["geometry"]]
# download streets from OSM
streets_graph = osmnx.graph_from_point(point, 1250, network_type='drive')
streets_graph = osmnx.get_undirected(streets_graph)
streets_graph = osmnx.projection.project_graph(streets_graph)
streets = osmnx.graph_to_gdfs(streets_graph, nodes=False, edges=True,
node_geometry=False, fill_edge_geometry=True)
streets = streets[["geometry"]]
# check CRS
assert buildings.crs.equals(streets.crs)
# generate tessellation
buildings['uID'] = range(len(buildings))
tessellation = mm.Tessellation(buildings, "uID", limit=box(*buildings.total_bounds), verbose=False).tessellation
"""
measure morphometric characters
"""
# cell area
tessellation['cell_area'] = tessellation.area
# building area
buildings['blg_area'] = buildings.area
# coverage area ratio
tessellation["car"] = mm.AreaRatio(tessellation, buildings, "cell_area", buildings.area, "uID").series
# segment length
streets["length"] = streets.length
# segment linearity
streets["linearity"] = mm.Linearity(streets, verbose=False).series
# street profile
profile = mm.StreetProfile(streets, buildings, distance=3)
streets["width"] = profile.w
streets["width_deviation"] = profile.wd
streets["openness"] = profile.o
# perimeter wall
buildings["wall"] = mm.PerimeterWall(buildings, verbose=False).series
# generate binary contiguity-based W objects of first order and inclusive order 3
W1 = libpysal.weights.Queen.from_dataframe(tessellation, ids="uID")
W3 = mm.sw_high(k=3, weights=W1)
# building adjacency
buildings["adjacency"] = mm.BuildingAdjacency(buildings, W3, "uID", verbose=False).series
# interbuilding distance
buildings['neighbour_distance'] = mm.NeighborDistance(buildings, W1, 'uID', verbose=False).series
# generate networkx.MultiGraph object
G = mm.gdf_to_nx(streets)
# meshedness
G = mm.meshedness(G, verbose=False)
# convert networkx.MultiGraph to geopandas.GeoDataFrames
nodes, edges = mm.nx_to_gdf(G)
"""
link all characters to tessellation cells
"""
# merge street network edges based on proximity
edges["nID"] = range(len(edges))
buildings["nID"] = mm.get_network_id(buildings, edges, "nID", 500, verbose=False)
buildings = buildings.merge(edges.drop(columns="geometry"), on="nID", how="left")
# merge nodes based on edge ID and proximity
buildings["nodeID"] = mm.get_node_id(buildings, nodes, edges, "nodeID", "nID", verbose=False)
buildings = buildings.merge(nodes.drop(columns="geometry"), on="nodeID", how="left")
# merge buildings based on a shared attribute
tessellation = tessellation.merge(buildings.drop(columns="geometry"), on="uID", how="left")
"""
save all to GeoPackage
"""
tessellation.to_file(f"~/work/{cases.loc[i, 'case']}.gpkg", layer="tessellation", driver="GPKG")
buildings.to_file(f"~/work/{cases.loc[i, 'case']}.gpkg", layer="buildings", driver="GPKG")
edges.to_file(f"~/work/{cases.loc[i, 'case']}.gpkg", layer="edges", driver="GPKG")
nodes.to_file(f"~/work/{cases.loc[i, 'case']}.gpkg", layer="nodes", driver="GPKG")
print(f"{cases.loc[i, 'case']} done in {time() - s} seconds.")