Creating a Map with XYZ Tiles using Geopandas, Matplotlib, Contextily, and XYZServices


In this blog post, we will explore how to create an matplotlib map (2D map) with XYZ tiles using Python libraries such as Geopandas, Matplotlib, Contextily, and XYZServices. The script provided below demonstrates the step-by-step process of generating a map and overlaying it with XYZ tiles.

Prerequisites: Before you start, make sure you have the required Python libraries installed. You can install them using the following:

pip install geopandas matplotlib contextily xyzservices cartopy

Understanding the Script: Let's break down the provided script line by line:

# Import necessary libraries
import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx
from shapely.geometry import box
import xyzservices.providers as xyz
from xyzservices import TileProvider
from cartopy import crs as ccrs
  • geopandas: Library for working with geospatial data.
  • matplotlib: Plotting library for creating visualizations.
  • contextily: Library for adding basemaps to Matplotlib plots.
  • shapely: Used for working with geometric objects.
  • xyzservices: Provides access to XYZ tile services.
  • cartopy: Library for cartographic projections and geospatial data visualization.
# Function to create a map with a basemap using xyzservices.TileProvider
def create_map(tile_provider, bbox, zoom='auto'):
    # Create a GeoDataFrame with a bounding box polygon
    bbox_polygon = gpd.GeoDataFrame(geometry=[box(*bbox)], crs="EPSG:4326")
  • create_map: Function that takes a tile provider, bounding box (bbox), and optional zoom level as input. It creates a GeoDataFrame containing a bounding box polygon.
    # Create a map with PlateCarree projection
    fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})
  • Creates a Matplotlib figure and axis using PlateCarree projection.
    # Add the bounding box polygon to the map
    bbox_polygon.boundary.plot(ax=ax, color='black', linewidth=1)
  • Plots the bounding box polygon on the map.
    # Add the bounding box polygon to the map
        # Add XYZ tiles using contextily and xyzservices.TileProvider
    ctx.add_basemap(ax, source=tile_provider, zoom=zoom,crs="EPSG:4326")
  • Adds XYZ tiles as a basemap using Contextily and XYZServices.
    # Add gridlines and parallels
    ax.gridlines(draw_labels=True, linestyle='--', color='black', alpha=0.5)
    ax.set_xlabel('Longitude')
    ax.set_ylabel('Latitude')
  • Adds gridlines and labels to the map for better orientation.
    # Customize the map
    ax.set_title('Map with XYZ Tiles (xyzservices.TileProvider)')

    # Show the map
    plt.show()
  • Sets the map title and displays the map.
# Define the bounding box
# (min_longitude, min_latitude, max_longitude, max_latitude)
bbox = (78, 26, 89, 30)  
  • Sets the bounding box coordinates.
# Define the XYZ Tile Provider
tile_provider = TileProvider({ "url":'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
    "name":"",
    "attribution":"",
    "cross_origin":"Anonymous"}
)
  • Defines the XYZ Tile Provider with a specific tile URL.
# Create and display the map
create_map(tile_provider, bbox)
  • Calls the create_map function with the specified tile provider and bounding box.

Conclusion:

By understanding each line of the script, you can easily customize the map creation process with different XYZ tile providers and bounding boxes. This script serves as a foundation for building maps in various geospatial applications. Feel free to experiment with different tile providers, map styles, and data overlays to create visually appealing and informative maps.

Full Script

Certainly! Below is the complete script that you can use to create a map with XYZ tiles using Geopandas, Matplotlib, Contextily, and XYZServices:

# Import necessary libraries
import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx
from shapely.geometry import box
import xyzservices.providers as xyz
from xyzservices import TileProvider
from cartopy import crs as ccrs

# Function to create a map with a basemap using xyzservices.TileProvider
def create_map(tile_provider, bbox, zoom='auto'):
    # Create a GeoDataFrame with a bounding box polygon
    bbox_polygon = gpd.GeoDataFrame(geometry=[box(*bbox)], crs="EPSG:4326")

    # Create a map with PlateCarree projection
    fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})

    # Add the bounding box polygon to the map
    bbox_polygon.boundary.plot(ax=ax, color='black', linewidth=1)

    # Add XYZ tiles using contextily and xyzservices.TileProvider
    ctx.add_basemap(ax, source=tile_provider, zoom=zoom, crs="EPSG:4326")

    # Add gridlines and parallels
    ax.gridlines(draw_labels=True, linestyle='--', color='black', alpha=0.5)
    ax.set_xlabel('Longitude')
    ax.set_ylabel('Latitude')

    # Customize the map
    ax.set_title('Map with XYZ Tiles (xyzservices.TileProvider)')

    # Show the map
    plt.show()

# Define the bounding box
bbox = (78, 26, 89, 30)  # (min_longitude, min_latitude, max_longitude, max_latitude)

# Define the XYZ Tile Provider
tile_provider = TileProvider({
    "url": 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
    "name": "",
    "attribution": "",
    "cross_origin": "Anonymous"}
)

# Create and display the map
create_map(tile_provider, bbox)