Creating Interactive Maps: The Easy way with Python, Folium and Leaflet.js
Read data with geopandas, create and add markers for each location on your map.
Many times, as a data scientist, you will come across data with coordinates and geospatial features. It sure would be bang if you can build a nice map to gain insights into the general spread of data.
In this brief tutorial, we will be designing an interactive map even without deep knowledge of Folium or Shapefiles.
Getting started
Requirements
- Python 3.7 or higher
- Geopandas
- Folium 0.12.0 or higher
Our data
The data we’ll be working with is Commodity Processing Points from the World Bank Data Catalog.
It holds information on the locations of commodity processing points in Nigeria; both existing and potential processors.
What you need to know
A shapefile is a geospatial, non-topological vector format for storing the geometric location and geographic features. Most geospatial analysis -including ours today, involves data in this format.
Folium is a powerful Python library that helps you create several types of Leaflet maps. It makes it easy to visualize and bind data that’s been manipulated in Python on an interactive leaflet map.
Leaflet is an open-source JavaScript library for simple, efficient, mobile friendly and interactive maps. It is loved for its plugins, and uncomplicated API. For a bunch of interesting leaflet tutorials, click here
Let the coding begin !
Importing geopandas and folium
import geopandas as gpd
import folium
Getting our data
aqua_data = gpd.read_file("data/commodity_processing_pts/Aquaculture.shp")
cassava_data = gpd.read_file("data/commodity_processing_pts/Cassava.shp")
cocoa_data = gpd.read_file("data/commodity_processing_pts/Cocoa.shp")
cotton_data = gpd.read_file("data/commodity_processing_pts/Cotton.shp")
oil_data = gpd.read_file("data/commodity_processing_pts/Palm_oil.shp")
rice_data = gpd.read_file("data/commodity_processing_pts/Rice.shp")
sorghum_data = gpd.read_file("data/commodity_processing_pts/Sorghum.shp")
Next step is to concatenate the datasets to a more comprehensive one processing_pts
processing_pts = pd.concat([aqua_data, cassava_data, cocoa_data, cotton_data, oil_data, rice_data, sorghum_data], axis= 0)
processing_pts = processing_pts.reset_index().drop(["index","Id"],axis=1)
processing_pts.head()
Now we can have a better look
As we know it, real-world data is almost never perfect, now we get to some cleaning : )
#Fixing the inconsistencies in the descript column
processing_pts["descript"].replace("Potential State","Potential processor", inplace=True)
processing_pts["descript"].replace(["Existing Processor", "Existing processor",
"Existing processors", "Existing Processors"],
"Existing processor", inplace=True)
The geometry
column keeps track of the underlying GEOS geometry in form of coordinate points. To plot the map we have unzip the geometric points into LATITUDE
and LONGITUDE
columns
processing_pts['LATITUDE'] = processing_pts.geometry.y
processing_pts['LONGITUDE'] = processing_pts.geometry.x
Now we can initialize our map
my_map = folium.Map(location = [processing_pts['LATITUDE'].mean(), processing_pts['LONGITUDE'].mean()],
zoom_start = 6.2, control_scale = True)
my_map
Although I used a zoom_scale 6.2x, you are free to modify and adjust the view of the map.
Setting up point markers and a nice popup
for index, location_info in processing_pts.iterrows():
folium.Marker([location_info["LATITUDE"], location_info["LONGITUDE"]],
popup = "<span style='font-size:1.9rem; color: green;'>%s</span><br><b>Status: </b>%s<br><b>Coordinates: </b>(%f, %f)" %(location_info["Commodity"], location_info["descript"], location_info["LONGITUDE"], location_info["LATITUDE"]),
icon = folium.Icon(color="green")).add_to(my_map)
my_map
Adding layers to our map using folium.raster_layers
folium.raster_layers.TileLayer('Open Street Map').add_to(my_map)
folium.raster_layers.TileLayer('Stamen Terrain').add_to(my_map)
folium.raster_layers.TileLayer('Stamen Toner').add_to(my_map)
folium.raster_layers.TileLayer('Stamen Watercolor').add_to(my_map)
# add layer control to show different maps
folium.LayerControl().add_to(my_map)
And voila !
my_map
Saving your masterpiece !
my_map.save("All food processing points.html")
Conclusion
Folium is easily one of the best libraries for map building, because with just a few lines of code, a whole lot can be done. Check out the documentation
To view the Jupyter Notebook here. To check out a live version of the map