Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fill water bodies with OSMnx in Python

I currently use OSMnx for a project to draw road networks in an area.

I'd now like to add water bodies so that we can clearly see which parts of an area are water and land.

So far, I've been able to identify waterbodies using the custom_filter argument to OSMnx's graph functions. I can then outline the waterbodies using the plot_graph function.

Ideally, I'd want to fill the waterbodies in (rather than only outline them). I feel like this should be possible, as in OpenStreetMap water bodies are filled, but I can't figure out how to do this with OSMnx. Does anybody have any ideas?

Here's what I have currently:

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')

Which produces this image:

NYC Water Bodies Image

Do I need to somehow use a geodataframe with PlotShape? Or is plot_footprints what I need? I haven't been able to find examples of people plotting waterbodies. It seems the GDF is generally used for plotting the map of a place, and footprints is used for buildings. Though as those are both polygon-oriented plots, I feel that might be the right way.

like image 493
Michael Toth Avatar asked Dec 11 '25 17:12

Michael Toth


1 Answers

I have been fighting with this for a while for a little project I have. What the accepted solution does is plot the fetched land on top of a water_color background, and adds the closed polygons fetched with the tag {'natural':'water'}. This works fine only if land covers the whole field of view. If you keep only one of the places in the list (say 'Manhattan, NY, USA'), then you have only this selected land in a sea of blue.

Fine if that's what you want.

What I wanted to do, and what I suspect the OP also wanted (since they fetched info from a bounding box), was to have all water-land interfaces within the bounding box. Including coastline does the job if what is needed is the contours, but coastlines are not closed polygons (and they come in separate segments) so there is no easy way to do that.

I started looking into using osmnx.geometries.linemerge and then osmnx.geo_utils.split to break a polygon along the coastlines, but I finally found that someone had done all the job already:

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

This repository has all coastlines joined into polygons (either on the water side or the land side). The github repo is https://github.com/fossgis .

So I would say that the clean way of doing what the OP asks is to download and use these shapefiles. Assuming that the water polygons file has been unzipped in the working directory, this is a working example:

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)

Output figure

like image 138
pthibault Avatar answered Dec 13 '25 05:12

pthibault



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!