Free base-maps for static maps using Geopandas and Contextily | by Wathela Hamed | Towards Data Science

Contextily is a package for contextual tiles in Python. In this quick tutorial, I am going to show you how to use contextily along with Geopandas in Jupyter Notebook to produce some nice maps. First of all, we need to make sure these packages are installed, go to your anaconda prompt and type:
conda install -c conda-forge geopandasconda install -c conda-forge contextily
I am assuming you already have matplotlib package installed, if not make sure you install it first.
conda install -c conda-forge matplotlib
Now we need to import our packages into a notebook:
import geopandas as gpdimport contextily as ctximport matplotlib.pyplot as plt
In this tutorial, I am going to use a conflict points data from North Darfur State/Sudan and its boundary shape-files, this data and the full code for this tutorial can be found at Github.
# Read in the conflict points and the boundary shape files using geopandasconf_data = gpd.read_file("NorthDarfurConf.shp")ND_Boundary = gpd.read_file("NorthDarfurBoundary.shp")
For a quick exploration of the data, you can simply print the head of the geo-dataframes to see what columns they have.
conf_data.columns
ND_Boundary.columns
We only need the event_type column from the conflict geo-dataframe which contains the type of the recorded event. It’s only one line of code to show this data:
# we specify the column that is going to be used for the symbologyconf_data.plot(column = 'event_type');
To make it a bit nicer, some parameters need to be set, also we going to use the boundary geo-dataframe as well to show the boundary of the state. But first of all, we need to customize the colors of the plot (if you have realized it was randomly generated). Simply we will create a dictionary for our unique values in the even_type column and assign each value a unique custom color code.
# get the uniques values in event_type columncategories = conf_data.event_type.unique()# create a list for our custom colorsc = ['m', 'k', 'g', 'r', 'y', 'c']# create a dictionary to combine both lists, categories are keys and # color codes are valuescolorDict = dict(zip(categories,c))print(colorDict)
To plot our points with our custom colors we will need to group the conf_data geo-dataframe by the event_type column so each unique event type gets its assigned color from the color dictionary.
# plot the state's boundary with black edge color only and line width of 2ax = ND_Boundary.geometry.boundary.plot(figsize = (10,15), color = None, edgecolor = 'K', linewidth=2)# Loop through each event type group for eventType, data in conf_data.groupby('event_type'):    color  = colorDict[eventType]    data.plot(ax = ax,  color = color, label = eventType)
Now we are ready to explore contextily and see how we can use it to include a base-map in our map. Contextily has a whole list of providers. They are all stored as dictionaries so you can easily explore and switch between them in python:
print(ctx.providers.keys())
To see which tile each provider contains, you use the provider name to print its tiles. For example let’s see what tiles does Open Street Map provider has:
print(ctx.providers.OpenStreetMap.keys())
To add a base-map to our previous map we only need to add one line of code to the previous code, where we specify:
Axis: To make sure we plotting everything together.
Coordinate reference system (crs): For the crs, will use the same crs of conf_data or ND_Boundary (both have the same crs) otherwise it won’t work.
Provider: for instance the Open Street Map with Mapnik tile.
# add open street map basemapctx.add_basemap(ax, crs = ND_Boundary.crs, url = ctx.providers.OpenStreetMap.Mapnik)
Finally, will add a legend and title to our map:
ax.legend(bbox_to_anchor = (0.31,1), prop={'size':10}) # set legend's position and sizeax.set(title="Conflict in North Darfur/Sudan (1997-2020)") # add a title to the mapax.set_axis_off() # remove the axis ticks plt.tight_layout() # adjust the padding between figure edgesplt.savefig('norhtDarfur_conf_OSM_Map.png')# Save the map as an imageplt.show()
Here are some other providers: