0

I'm trying to add a contextily basemap to a Matplotlib figure containing a GeoPandas data frame. When I just plot the data frame using df.plot the map extent is calculated correctly.

However, when I try adding a contextily basemap the map extent (and zoom level) is calculated wrongly and the following warning is shown:

UserWarning: The inferred zoom level of 27 is not valid for the current tile provider (valid zooms: 0 - 20).

I'm trying to execute the following code:

df = gpd.read_file('linz/StatBez_Linz_EPSG_4326.gml')
df = df.to_crs(epsg=3857)

fig = plt.figure(figsize=(16,9))
ax = plt.subplot()
ctx.add_basemap(ax = ax, source=ctx.providers.Stamen.Toner, crs=df.crs.to_string())
df.plot(color='none',edgecolor='green', ax = ax)

The output of df.tail() can be seen here:

enter image description here

The gml file is from data.gv.at

tuesday
  • 582
  • 1
  • 7
  • 14

1 Answers1

1

The GML file of Linz is based on Gauss-Krüger system M31-5Mio (EPSG:31255). Here is runnable code that demonstrates all the steps to produce a plot of the GML with basemap requested from webmap tiles' provider of choice.

import contextily as ctx
import geopandas
import matplotlib.pyplot as plt

# Read GML
linz_districts = geopandas.read_file('./data/StatBez_Linz.gml')

# The coordinates are in the Gauss-Krüger system M31-5Mio. 
# CRS is EPSG:31255
# Set proper coordinate system to the geoDataFrame
linz_31255 = linz_districts.set_crs(31255)

# Convert CRS to Web-Mercator to match basemap layer
linz_3857 = linz_31255.to_crs('epsg:3857')

# plot Linz
ax = linz_3857.plot(figsize=(9, 16), zorder=10, ec='gray', alpha=0.4)

# plot basemap (it uses 'epsg:3857')
src_basemap = ctx.providers.Stamen.Terrain
ctx.add_basemap( ax, source=src_basemap, alpha=0.6, zorder=8 )

# Also possible with
#ctx.add_basemap( ax, source='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' )

# manipulate xticks, use format
ax.set_xticklabels(['{:,.0f}'.format(x) for x in ax.get_xticks()]);
ax.set_yticklabels(['{:,.0f}'.format(y) for y in ax.get_yticks()]);

The output plot:

linz-map

swatchai
  • 17,400
  • 3
  • 39
  • 58
  • 1
    Thanks a lot for the example code (even with my data!). Turns out the only change that was needed to fix it was to first plot the df on the axis, and add the basemap afterwards. – tuesday Nov 10 '20 at 08:36
  • @tuesday The axes `ax` is returned by the data plot, thus, plot extent is determined and attached with it. – swatchai Nov 10 '20 at 09:26