Level Up Your Visualizations: Make Interactive Maps with Python and Bokeh
By: Conner Brew
Tags: Analysis, Maps, Dashboard, Data Science, Python

Level Up Your Visualizations: Make Interactive Maps with Python and Bokeh

Let’s face it, fellow data scientists: our clients LOVE dashboards. Why wouldn’t they? Visualizing our data helps us tell a story. Visualization turns thousands of rows of data into a compelling and beautiful narrative. In fact, dashboard visualizations have become so commonplace that virtually every resume features at least one (maybe several) dashboard projects. How can you make yours stand out? Bar charts and time-series line graphs aren’t going to cut it.

Maps help us tell a story!

Enter: geographic data.What is geographic data? Broadly speaking, it’s anything you can put on a map. Does it have lat/lon coordinates? Does it exist in geographic space? That’s geographic data.

Maps help us tell stories. Think to some of your favorite novels — how many of them have maps in their pages? Maps immerse us in the environment of the story; in this case, the story of your client’s data.

This article will teach you to deal with three types of maps: heatmaps, bubble maps, and categorical maps. By the end of this tutorial, you’ll be a spatial data wizard ready to set your dashboard visualizations apart from the rest. Let’s dive in!

Notebook

For the complete code associated with this project and to see the interactive legend and hover tool-tips in action, see the Jupyter Notebook associated with this project!

Our Data

For the purpose of this tutorial, we’ll be using data from the Armed Conflict Location Event Database (ACLED). I urge you to try and use your own data on this project! If that sounds too complex for you, you can get the data I used from the github repo associated with this article.

A Brief Disclaimer:

This article won’t go over exploratory analysis of the dataset; I’ll be operating under the assumption that you are already familiar with basic visualization techniques and terminology as well as basic concepts associated with the Bokeh, Numpy, and Pandas libraries. To view my exploratory analysis of the data, see this notebook.

If this is your first time using Bokeh, try a few beginner tutorials from their user guide.

Let’s dive in!

Import Modules

We’ll be using all of Bokeh, Pandas, and Numpy in this project.

Load the Data

You can access the data used for this project here. Import the data using pandas ‘read_csv()’ method. You’ll need the latitude and longitude columns to be float types so that we can convert them to web mercator units later on. Whatever column you choose to define the radius of your bubble map should be an int or float type. In this demonstration, it’s the fatalities column.

Initialize the Map Object

Like many Python libraries, Bokeh is very object-oriented. Before we can plot our data, we must initialize a map object in the form of a Bokeh plotting figure. One important consideration when using Bokeh for map-making is that Bokeh uses mercator units for plotting. Most of your spatial data likely comes in the form of lat/long coordinates (commonly known as wgs84). First, we will convert these coordinates to mercator and then we will initialize the plot object for our data.

To initialize the plotting object, we have to define the x and y range, or extent, for the map visibility. I want the extents of the map to have a constant proportion to the size of hexbins and bubbles that I will visualize later, so I establish the map scale using a variable. The number chosen for this is arbitrary — I simply played around with a few different numbers until I was happy with the zoom level. Setting it as one variable makes it very easy to change later!

Additionally, you will have to select a tile provider for your map. I prefer Open Street Maps (OSM), but you can find a complete list of Bokeh’s supported map tiles here. Set the map level to ‘underlay’ and use the ‘output_notebook()’ method to display the plot in-line if you’re using a Jupyter notebook.

Create Map Generation Functions

First we will create a function for the hexbin map. Hexbins are mathematically more accurate than most standard heatmaps, especially for data that is presented elliptically or has a lower range of geographic precision. They also have the additional benefit of being visually appealing! You will also note that I created a hover tool that will display the count of items in each hex as well as the q,r coordinates associated with each hexagon.

Next, we will write a function to create a bubble map. Bubble maps are useful for depicting scale of events. In this case, the radius of bubbles will be proportionate to the amount of fatalities caused by each event — this type of map is also great for depicting weather events, pandemic cases, and other scalar datasets.

Let’s See Our Work!

Now simply input your parameters into the function you created! Note that in the functions I wrote, I set a few default parameters to make calling the function easier.

Once your plot appears in the window, try hovering over it with your mouse! You should see the map data change color as you hover over it in addition to informative tool-tips. Try clicking entries in the legend to toggle map layers on and off!

Why Functions?

We used functions to create our maps for ease of re-use. In the future, if we have data that we want to plot using a bubble map or heatmap, we can re-use these same functions rather than completely rewriting code. Using functions for common tasks is a good habit to get into, especially if you work on a team where team members may frequently use eachother’s code!

Interactive Legends for Categorical Data

You may have noticed in our above map that you can toggle layer visibility by clicking items in the legend. How can we make better use of this feature? Next, we will display our data categorically. For this data, I will be using event_type. Note that the code that follows is not designed for maximum efficiency or re-usability; but rather for readability. A beginner should be able to read and understand the next few steps. If you’re more advanced, try writing a function to make this plot more re-usable!

First, let’s initialize a new plot object.

There are many ways to accomplish this next step, but each factor of the categorical variable will need to be plotted separately to its own level. In this code, I initialized empty lists for each factor and will append the information associated with each type.

For each empty list, an iterator searches the dataframe for events of that type and appends the list with information such as x and y coordinates, lat/lon coordinates, and other descriptive information. If you choose this method, you will have to do this for each empty list. You can also nest iterators together to accomplish this, but for demonstration purposes I chose to write each separate block for code readability — nested iterators are often difficult to understand without extensive use of comments.

Once the lists are populated with the information associated with each category, each list gets plotted iteratively as a separate layer to the plotting object we created earlier. The reason we do this, as opposed to plotting all the data at once, is to enhance the toggle capability of the interactive legend. Now, in the resulting map plot, users can click different categories in the legend to filter the data by event type.

Use the ‘show(row())’ method from Bokeh to display both maps simultaneously on a dashboard. Admire your work! Try hovering over map entries to get more information, and clicking the legend to filter the display. That’s it!

Summary

Now you can plot maps in Bokeh and create useful interactions that will allow your clients or customers to gain maximum insight from their spatial data. You learned how to create hexbin heatmaps, bubble maps, and interactive categorical maps. By combining these skills with other data visualization techniques, you will be ready to create visually stunning and useful dashboard visualizations for your next data science project!