Search code examples
pythongeospatialgeopandasshapelyosmnx

Plot polylines on top of OSMnx map


Using the OSMnx library, I'm trying to draw lines as polygons on top of a base map (with per-defined coordinates not adhering to the underlying network), but with no luck. I'm certain that the coordinates I have are inside of the boundary, and I get no error when adding them.

Here's my current code, which generates the base map and also adds a multi polygon layer below the network. So it's possible to add polygons, which makes me think there might a projection issue with my coordinates, but I haven't had any luck setting different projections.

Any help would be much appreciated!

import matplotlib.pyplot as plt
from descartes import PolygonPatch
from shapely.geometry import Polygon, MultiPolygon
import osmnx as ox
ox.config(log_console=True, use_cache=True)
ox.__version__

def plot(geometries):
  # get the place shape
  gdf = ox.gdf_from_place('Copenhagen Municipality,Denmark')
  gdf = ox.project_gdf(gdf)

  # get the street network, with retain_all=True to retain all the disconnected islands' networks
  G = ox.graph_from_place('Copenhagen Municipality,Denmark', network_type='drive', retain_all=True)
  G = ox.project_graph(G)  

  fig, ax = ox.plot_graph(G, fig_height=10, show=False, close=False, edge_color='#777777')

  # Add shape from gdf
  for geometry in gdf['geometry'].tolist():
    if isinstance(geometry, (Polygon, MultiPolygon)):
      if isinstance(geometry, Polygon):
        geometry = MultiPolygon([geometry])
      for polygon in geometry:
        patch = PolygonPatch(polygon, fc='#cccccc', ec='k', linewidth=3, alpha=0.1, zorder=-1)
        ax.add_patch(patch)  

  # Add lines:
  for geometry in geometries:
    if isinstance(geometry, (Polygon, MultiPolygon)):
      if isinstance(geometry, Polygon):
        geometry = MultiPolygon([geometry])
        for polygon in geometry:
          patch = PolygonPatch(polygon, fc='#148024', ec='#777777', linewidth=10, alpha=1, zorder=2)
          ax.add_patch(patch)

  plt.savefig('images/cph.png', alpha=True, dpi=300)

plot(geometries)

geometries is a list which contains polygons like these:

POLYGON ((55.6938796 12.5584122, 55.6929711 12.5585957, 55.6921317 12.5579927, 55.6916918 12.5564539, 55.6909246 12.5553629, 55.6901215 12.554119, 55.6891181 12.5531433, 55.6881469 12.5526575, 55.687502 12.5538862, 55.6866445 12.5530816, 55.6856769 12.5524416, 55.6848185 12.5515929, 55.6838506 12.551074, 55.6829915 12.5504047, 55.6821492 12.5498124, 55.6812104 12.5492503, 55.680311 12.5486803, 55.6792187 12.547724, 55.6783172 12.5472156, 55.6774282 12.5466767, 55.6765291 12.5461124, 55.6755652 12.5453961, 55.6747743 12.5445313, 55.6738159 12.5439029, 55.673417 12.5454132, 55.6733398 12.5470051, 55.6731045 12.5486561, 55.6726013 12.5501493, 55.6727833 12.5520672, 55.6716717 12.5525378, 55.6706619 12.5528382, 55.6698239 12.5521737))
POLYGON ((55.6693768 12.5509383, 55.6684025 12.5511539, 55.6677405 12.5500371, 55.6668188 12.5501435, 55.6658323 12.550075, 55.665264 12.5487917, 55.6649187 12.5473085, 55.6645313 12.5457653))

Solution

  • In geopandas dataframes, the geo-coordinates are (longitude, latitude). Here is a simple demonstration code that plots some sample data.

    import geopandas as gpd
    import pandas as pd
    import matplotlib.pyplot as plt
    import osmnx as ox
    from shapely import wkt  #need wkt.loads
    
    # simple plot of OSM data
    gdf = ox.gdf_from_place('Copenhagen Municipality,Denmark')
    gdf = gpd.GeoDataFrame(gdf, crs={'init': 'epsg:4326'})  #set CRS
    ax1 = gdf.plot(color='lightgray')  # grab axis as `ax1` for reuse
    
    # prep the polygons to plot on the axis `ax1`
    # use (longitude latitude), and the last point must equal the 1st
    pgon1 = "POLYGON((12.5584122 55.6938796, 12.5585957 55.6929711, 12.5579927 55.6921317, 12.5564539 55.6916918, 12.5553629 55.6909246, 12.554119 55.6901215, 12.5531433 55.6891181, 12.5526575 55.6881469, 12.5538862 55.687502, 12.5530816 55.6866445, 12.5524416 55.6856769, 12.5515929 55.6848185, 12.551074 55.6838506, 12.5504047 55.6829915, 12.5498124 55.6821492, 12.5492503 55.6812104, 12.5486803 55.680311, 12.547724 55.6792187, 12.5472156 55.6783172, 12.5466767 55.6774282, 12.5461124 55.6765291, 12.5453961 55.6755652, 12.5445313 55.6747743, 12.5439029 55.6738159, 12.5454132 55.673417, 12.5470051 55.6733398, 12.5486561 55.6731045, 12.5501493 55.6726013, 12.5520672 55.6727833, 12.5525378 55.6716717, 12.5528382 55.6706619, 12.5521737 55.6698239, 12.5584122 55.6938796))"
    pgon2 = "POLYGON((12.5509383 55.6693768, 12.5511539 55.6684025, 12.5500371 55.6677405, 12.5501435 55.6668188, 12.550075 55.6658323, 12.5487917 55.665264, 12.5473085 55.6649187, 12.5457653 55.6645313, 12.5509383 55.6693768))"
    
    # create dataframe of the 2 polygons
    d = {'col1': [1, 2], 'wkt': [pgon1, pgon2]}
    df = pd.DataFrame( data=d )
    
    # make geo-dataframe from it
    geometry = [wkt.loads(pgon) for pgon in df.wkt]
    gdf2 = gpd.GeoDataFrame(df, \
                       crs={'init': 'epsg:4326'}, \
                       geometry=geometry)
    
    # plot it as red polygons
    gdf2.plot(ax=ax1, color='red', zorder=5)
    

    The output plot:

    enter image description here