Search code examples
pythongeopandascartopy

add custom tiles to geopandas dataframe


I know I can add custom background maps to a geopandas data frame like below

ax = df_wm.plot(figsize=(10, 10), alpha=0.5, edgecolor='k')
cx.add_basemap(ax, source=cx.providers.Stamen.TonerLite)
ax.set_axis_off()

How could I use other map tiles. For example, USGS topo tiles like those from the national map below? https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/7/46/26


Solution

  • To get webmap tiles for your maps' background from a standard sources, you need to identify url and layer and use them in your code. Here is a demo script that uses cartopy to request the services.

    Map tiles are generally produced in web-mercator projection (ccrs.epsg(3857)). If you want to use them as is you must plot your map on that projection or mercator projection.

    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    import os
    os.environ['USE_PYGEOS'] = '0'
    import geopandas as gpd
    
    url = "https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/WMTS/1.0.0/WMTSCapabilities.xml"
    layer = "USGSTopo"
    
    mercator = ccrs.Mercator()  #ccrs.epsg(3857)
    nonproj  = ccrs.PlateCarree()
    
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1, projection=mercator)
    
    # The requested maps will appear as data that
    #   matplotlib can plot on its `ax`
    ax.add_wmts(url, layer)
    ax.set_extent([20, 25, 35, 40], crs=nonproj)
    
    # Plot a linestring using long/lat in degrees
    ax.plot([20.1, 22.7, 24.5], [35.5, 37.2, 39.2], transform=nonproj ,zorder=15)
    
    # Plot Geopandas cities data
    city_pnts = gpd.read_file(gpd.datasets.get_path("naturalearth_cities"))
    
    # Geometries in Geodataframes have CRS transformed
    #  to Mercator projection and plotted here
    cty2 = city_pnts.to_crs(mercator.proj4_init)
    cty2.plot(ax=ax, color="red", zorder=20)
    
    ax.gridlines(draw_labels=True)
    
    ax.set_title('USGSTopo WMTS')
    plt.show()
    

    wmts