Context geo-tiles in Python for retrieving and working with basemap tiles from the internet
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Functions for adding web or local basemaps to existing matplotlib axes with automatic coordinate handling, provider support, and custom styling options. These functions are the core of contextily's matplotlib integration.
Add web or local tile basemaps to matplotlib axes with comprehensive customization options including zoom levels, tile sources, coordinate transformations, and visual styling.
def add_basemap(ax, zoom='auto', source=None, interpolation='bilinear',
attribution=None, attribution_size=8, reset_extent=True,
crs=None, resampling=Resampling.bilinear, zoom_adjust=None,
**extra_imshow_args):
"""
Add a (web/local) basemap to ax.
Parameters:
- ax: AxesSubplot - Matplotlib axes object (extent assumed to be EPSG:3857 unless crs specified)
- zoom: int or 'auto' - Level of detail for basemap, calculated automatically if 'auto'
- source: TileProvider, str, or None - Tile source (web provider, URL, or local file path)
- interpolation: str - Interpolation algorithm for imshow ('bilinear', 'nearest', etc.)
- attribution: str or None - Attribution text (defaults to source attribution)
- attribution_size: int - Font size for attribution text (default 8)
- reset_extent: bool - Whether to reset axes extent to original bounds
- crs: str or CRS - Target coordinate reference system for warping
- resampling: Resampling - Resampling method for warping operations
- zoom_adjust: int - Adjustment to automatically calculated zoom level (-1 to 1 recommended)
- **extra_imshow_args: Additional parameters passed to matplotlib's imshow
Returns:
None (modifies axes in-place)
"""Usage Examples:
import contextily as ctx
import matplotlib.pyplot as plt
import geopandas as gpd
# Add basemap to existing plot (data must be in Web Mercator EPSG:3857)
gdf = gpd.read_file('data.shp').to_crs(epsg=3857)
ax = gdf.plot(figsize=(10, 10), alpha=0.5, color='red')
ctx.add_basemap(ax, source=ctx.providers.Stamen.Toner)
plt.show()
# Use custom zoom level and different provider
ax = gdf.plot(figsize=(10, 10), alpha=0.5)
ctx.add_basemap(ax, zoom=12, source=ctx.providers.CartoDB.Positron)
plt.show()
# Add basemap with coordinate transformation (data in different CRS)
gdf_4326 = gpd.read_file('data.shp') # WGS84 data
ax = gdf_4326.plot(figsize=(10, 10))
ctx.add_basemap(ax, crs=gdf_4326.crs, source=ctx.providers.OpenStreetMap.HOT)
plt.show()
# Use local raster file as basemap
ctx.add_basemap(ax, source='path/to/local_basemap.tif')
# Custom styling with additional imshow parameters
ctx.add_basemap(ax, alpha=0.7, cmap='gray', vmin=0, vmax=255)Add or customize attribution text on matplotlib plots to properly credit tile providers and data sources.
def add_attribution(ax, text, font_size=8, **kwargs):
"""
Add attribution text to matplotlib axes.
Parameters:
- ax: AxesSubplot - Matplotlib axes object
- text: str - Attribution text to display
- font_size: int - Font size for attribution text (default 8)
- **kwargs: Additional keyword arguments passed to matplotlib's text method
Returns:
matplotlib.text.Text - Text object added to the plot
"""Usage Examples:
import contextily as ctx
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(10, 8))
# Add basemap without automatic attribution
ctx.add_basemap(ax, attribution=False)
# Add custom attribution
ctx.add_attribution(ax, "© Custom Data Source 2024", font_size=10)
# Add attribution with custom styling
ctx.add_attribution(ax, "Map data © OpenStreetMap contributors",
font_size=12, color='blue', weight='bold')
plt.show()Access pre-configured tile providers through the providers object (re-exported from xyzservices):
# Popular basemap providers
ctx.providers.OpenStreetMap.HOT # Humanitarian OpenStreetMap
ctx.providers.Stamen.Toner # Black and white map
ctx.providers.Stamen.Terrain # Terrain with labels
ctx.providers.CartoDB.Positron # Light colored basemap
ctx.providers.CartoDB.DarkMatter # Dark themed basemap
ctx.providers.ESRI.WorldImagery # Satellite imagery# Custom tile URL (placeholders: {x}, {y}, {z})
custom_url = "https://tiles.example.com/{z}/{x}/{y}.png"
ctx.add_basemap(ax, source=custom_url)
# TileProvider object for advanced configuration
from xyzservices import TileProvider
provider = TileProvider(
url="https://tiles.example.com/{z}/{x}/{y}.png",
attribution="© Example Tiles",
name="ExampleTiles"
)
ctx.add_basemap(ax, source=provider)
# Local raster file
ctx.add_basemap(ax, source="/path/to/local/basemap.tif")By default, add_basemap assumes axes are in Web Mercator (EPSG:3857):
# Data must be in EPSG:3857 for automatic handling
gdf_3857 = gdf.to_crs(epsg=3857)
ax = gdf_3857.plot()
ctx.add_basemap(ax) # Works automaticallyUse the crs parameter to work with data in other coordinate systems:
# Data in WGS84 (EPSG:4326)
gdf_4326 = gpd.read_file('data.shp')
ax = gdf_4326.plot()
ctx.add_basemap(ax, crs=gdf_4326.crs) # Handles transformation automatically
# Data in custom projection
gdf_custom = gdf.to_crs(epsg=32633) # UTM Zone 33N
ax = gdf_custom.plot()
ctx.add_basemap(ax, crs='EPSG:32633')# Let contextily calculate optimal zoom
ctx.add_basemap(ax, zoom='auto')
# Fine-tune automatic zoom calculation
ctx.add_basemap(ax, zoom='auto', zoom_adjust=1) # One level higher detail
ctx.add_basemap(ax, zoom='auto', zoom_adjust=-1) # One level lower detail
# Manual zoom for performance control
ctx.add_basemap(ax, zoom=10) # Fixed zoom levelTiles are automatically cached per Python session. Use set_cache_dir() for persistent caching:
import contextily as ctx
# Set persistent cache directory
ctx.set_cache_dir('/path/to/cache')
# Now basemaps will use persistent cache
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.HOT)Common issues and solutions:
# Handle missing tiles gracefully
try:
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.HOT)
except Exception as e:
print(f"Basemap failed: {e}")
# Fallback to different provider or no basemap
# Check data CRS before adding basemap
if gdf.crs != 'EPSG:3857':
print(f"Data CRS: {gdf.crs}, converting for basemap")
gdf = gdf.to_crs(epsg=3857)Install with Tessl CLI
npx tessl i tessl/pypi-contextily