如何在 Python 中用 OSMnx 填充水体

How to fill water bodies with OSMnx in Python

我目前在一个项目中使用OSMnx 来绘制一个区域的道路网络。

我现在想添加水体,以便我们可以清楚地看到一个区域的哪些部分是水和陆地。

到目前为止,我已经能够使用 OSMnx 图形函数的 custom_filter 参数来识别水体。然后我可以使用 plot_graph 函数勾勒出水体轮廓。

理想情况下,我想填充水体(而不是只勾勒出它们的轮廓)。我觉得这应该是可能的,因为在 OpenStreetMap 中水体被填满了,但我不知道如何用 OSMnx 做到这一点。有人有什么想法吗?

这是我目前拥有的:

import osmnx as ox

# Get water bodies map of the New York City area
G = ox.graph_from_bbox(40.9666,40.4362,-73.6084,-74.3254, custom_filter='["natural"~"water|coastline"]', retain_all = True)

# Plot the graph in blue on a white background
ox.plot_graph(G, bgcolor='white', node_size=0, equal_aspect=True, edge_color='blue')

生成这张图片的:

我是否需要以某种方式将地理数据框与 PlotShape 一起使用?或者 plot_footprints 是我需要的吗?我没能找到人们绘制水体的例子。似乎GDF通常用于绘制一个地方的地图,而脚印用于建筑物。虽然这些都是面向多边形的图,但我觉得这可能是正确的方法。

这并不完美,但它让你接近成功:

import osmnx as ox
ox.config(log_console=True, use_cache=True)

# add more items here to get all the landforms you want
places = ['Manhattan, NY, USA', 'Brooklyn, NY, USA', 'Queens, NY, USA', 'Bronx, NY, USA']
land = ox.geocode_to_gdf(places)

# get the water bodies
left, bottom, right, top = land.total_bounds
bbox = top, bottom, right, left
poly = ox.utils_geo.bbox_to_poly(*bbox)
water = ox.geometries_from_polygon(poly, tags={'natural': 'water'})

# constrain the plotting window as desired
c = land.unary_union.centroid
bbox = ox.utils_geo.bbox_from_point((c.y, c.x), dist=12000)

water_color = 'blue'
land_color = '#aaaaaa'
fig, ax = ox.plot_footprints(water, bbox=bbox,
                             color=water_color, bgcolor=water_color,
                             show=False, close=False)
ax = land.plot(ax=ax, zorder=0, fc=land_color)

关键问题是,我目前不清楚是否可以持续查询 OSM 以获取直接的陆地多边形与水多边形(在我的研究中,我通常不使用 land/water 边界)。 places可能是政治边界,可能与现实生活中的水域重叠。您可能想在这里 query/plot 尝试陆地与水的对比。

为了我的一个小项目,我已经为此奋斗了一段时间。公认的解决方案是在 water_color 背景上绘制获取的土地,并添加使用标签 {'natural':'water'} 获取的闭合多边形。仅当 land 覆盖整个视野时,这才有效。如果你只保留列表中的一个地方(比如'Manhattan, NY, USA'),那么你就只有这个选定的蓝色海洋中的土地。

好吧,如果这是你想要的。

我想做的,我怀疑 OP 也想要的(因为他们从边界框获取信息),是要有 all water-land 接口在边界框内。如果需要的是等高线,包括海岸线就可以完成这项工作,但海岸线不是封闭的多边形(它们位于不同的线段)所以没有简单的方法可以做到这一点。

我开始研究使用 osmnx.geometries.linemerge 然后 osmnx.geo_utils.split 沿着海岸线打断多边形,但我终于发现有人已经完成了所有工作:

https://osmdata.openstreetmap.de/contact.html

此存储库将所有海岸线连接成多边形(在水边或陆地边)。 github 回购是 https://github.com/fossgis .

所以我想说的是,按照 OP 的要求,最简洁的方法是下载并使用这些 shapefile。假设水多边形文件已经在工作目录中解压,这是一个工作示例:

import osmnx as ox
import geopandas as gpd
# Bounding box
bN, bS, bE, bW = 40.9666, 40.4362, -73.6084, -74.3254
# Fetch water
G = ox.geometries.geometries_from_bbox(bN, bS, bE, bW, tags={"natural": "water"})
# Load coastline polygons
water = gpd.read_file('water-polygons-split-4326/water_polygons.shp', bbox=(bW, bN, bE, bS))
# Plot
fig, ax = ox.plot_footprints(water, bbox=(bN, bS, bE, bW),
                             color=water_color, bgcolor=land_color,
                             show=False, close=False)
ax = G.plot(ax=ax, fc=water_color, markersize=0)