Data Viz – Interactive Map

In this article, you will discover how you can implement an interactive data visualization on a map.

To start, you need to install the following packages Pandas for DataFrame manipulation and Folium.

What is Folium? Folium is a Python library for visualizing geospatial data. Folium is a Python wrapper for Leafleft.js, an open-source Javascript library used for an interactive map. You will see that plotting interactive maps will be easy with Folium. Make sure that Pandas and Folium libraries are installed on your machine. You can use the pip install command in your terminal to install packages.

Kenya – Photo taken by me

This article is divided into 3 parts :

  • Input data loading and pre-processing
  • Creation of a map with few markers
  • Construction of the dynamic data in the time

As seen in the DataFrame – Input & Output article, you can import your Excel database with the read_excel function of pandas.

Here, we load a database of the Airport Traffic in the USA impacted by the Covid 19 during 2020. This table of data comes from the Kaggle site. You can quickly visualize this DataFrame.

import pandas as pd

# initialisation input file data  xlsx
path_file_database = "/Users/Name/Documents/Python/Data_viz/covid_impact_on_airport_traffic.xlsx"
df_data = pd.read_excel(path_file_database, "DATA", index_col=None)

# keep only useful columns
df_data = df_data[["AirportName", "Latitude", "Longitude", "Date", "PercentOfBaseline"]]

This DataFrame contains 13 columns and 7248 rows.

We need to do some pre-processing in our DataFrame. Before plotting the map we need to bring our data into a well format. Your data need a column for Latitude and Longitude in decimal format, we will convert these columns as float. We will also check the quality of data if we have NaN or null values. To not have any issue, we will also convert the Date column format.

# pre processing data
df_data["Latitude"] = df_data["Latitude"].astype(float)
df_data["Longitude"] = df_data["Longitude"].astype(float)
df_data["Date"] = df_data["Date"].dt.strftime("%d/%m/%y")
df_data["PercentOfBaseline"] = df_data["PercentOfBaseline"] / 100  # create a weight

Now, we need to create a map using the Folium package. The map is centered at the mean latitude and mean longitude of our data. You can configure the zoom start and the title in the map. Several choices are possible for tiles as OpenStreetMap or CartoDB Positron for example. You can consult the following link for more details about arguments.

# initialisation of a new map
map_draw = folium.Map(location=[df_data.Latitude.mean(), df_data.Longitude.mean()],
                      zoom_start=3, control_scale=True, tiles="CartoDB positron")

Now, our map is produced, we will add marker location. Marker corresponds to items used for marking locations on a map. You can call the Folium Marker class with the location of the marker, a description, and an icon. These markers will be based on the latitude and longitude data.

# add the marker of a new map
for index, location_info in df_data.iterrows():
    folium.Marker([location_info["Latitude"], location_info["Longitude"]],
                  popup=str(location_info["AirportName"]),
                  icon=folium.Icon(color="darkblue", icon_color="#FFFFF", icon="cloud", prefix="fa")).add_to(map_draw)

The interactive part starts here. How to draw dynamic data on the map?
To do it, you will use a Folium plugin. It exists several Folium plugins ad AntPath, MeasureControl, or Draw. Import the plugin :

import folium
from folium.plugins import MeasureControl
from folium import plugins

To use the HeatMapWithTime class you need a list of data with the latitude, longitude, and weight of each point. It will be a list of lists, with each inside list at a similar date.

To construct this list, you can use the following loop on the data frame Groupby date :

# draw dynamic HeatMap in time, based on a list comprehension to make out list of list
list_heat_data = []
for _, d in df_data.groupby("Date"):
    list_heat_data.append([[row["Latitude"], row["Longitude"], row["PercentOfBaseline"]] for _, row in d.iterrows()])

You now have the list of data and use the HeatMapWithTime function. Then, you can use your map to add information.

# draw the list of data for the index in the map
list_date = list(df_data["Date"].unique())

heatmap_data_time = plugins.HeatMapWithTime(data=list_heat_data, auto_play=True, max_opacity=0.8, radius = 20, speed_step=1, display_index=True, min_speed=5, index=list_date)

heatmap_data_time.add_to(map_draw)

You can save your map by using the save function. Then, save the map object in an Html file. Open your Html file in a browser. It will open a web page with your map, markers, and dynamic data.

# add the plugin measurement
map_draw.add_child(MeasureControl())

name_output_file = "HeatMap_time_airport.html"
map_draw.save(name_output_file)
COVID 19 Impact USA Airport Traffic, 2020

You now have all elements to understand Folium and create your interactive maps.

Below, all the codes:

import pandas as pd
import folium
from folium.plugins import MeasureControl
from folium import plugins

# initialisation input file data  xlsx
path_file_database = "/Users/Name/Documents/Python/Data_viz/covid_impact_on_airport_traffic.xlsx"
df_data = pd.read_excel(path_file_database, "DATA", index_col=None)

# keep only useful columns
df_data = df_data[["AirportName", "Latitude", "Longitude", "Date", "PercentOfBaseline"]]

# pre processing data
df_data["Latitude"] = df_data["Latitude"].astype(float)
df_data["Longitude"] = df_data["Longitude"].astype(float)
df_data["Date"] = df_data["Date"].dt.strftime("%d/%m/%y")
df_data["PercentOfBaseline"] = df_data["PercentOfBaseline"] / 100  # create a weight

# initialisation of a new map
map_draw = folium.Map(location=[df_data.Latitude.mean(), df_data.Longitude.mean()],
                      zoom_start=3, control_scale=True, tiles="CartoDB positron")

# draw dynamic HeatMap in time, based on a list comprehension to make out list of list
list_heat_data = []
for _, d in df_data.groupby("Date"):
    list_heat_data.append([[row["Latitude"], row["Longitude"], row["PercentOfBaseline"]] for _, row in d.iterrows()])

# draw the list of data for the index in the map
list_date = list(df_data["Date"].unique())

heatmap_data_time = plugins.HeatMapWithTime(data=list_heat_data, auto_play=True, max_opacity=0.8, radius = 20,
                                            speed_step=1, display_index=True, min_speed=5, index=list_date)

heatmap_data_time.add_to(map_draw)

# add the plugin measurement
map_draw.add_child(MeasureControl())

name_output_file = "HeatMap_time_airport.html"
map_draw.save(name_output_file)