Making an Interactive Web Map in Python with Folium: Part 2— Map-Makery
By: Noah Christiansen
Tags: Python, Data Science, Mapping, Folium

Ok, so I left off my last post with a simple plot of a GeoDataFrame containing fire incident data that I’d geocoded for a project. Since that plot vaguely resembled the five boroughs of New York City, it looks like the data is in good shape to actually be mapped.

First things first, I need to import the libraries I’ll be using to make the map. I’ll include the libraries I imported last time, but I’ll also add a new one: folium.

Next, I’ll subset my data to only include the points I’m interested in mapping. While this would normally be all of the points in the dataset, folium has some issues when rendering more than 1000 points on a map (I’m still figuring out a workaround for this), so for now I’ll select only those incidents that were registered with fire codes in the 201–299 range: overpressure ruptures, explosions, or overheats (no fire). This subset includes 432 incidents from the dataset, so enough that the map will look populated, but not so many that folium becomes overloaded.

To make this subset, I’ll select only the rows in the GeoDataFrame where the incident type number (incident_type_num) is greater than 200 (the dataset only includes 100-level and 200-level fire codes). Remember that here incidents_gdf refers to the GeoDataFrame of the incident data.

explosions = incidents_gdf[incidents_gdf[‘incident_type_num’] > 200].reset_index(drop = True)

So now explosions is just a subset of the original dataset with fire codes greater than 200. Then I want to subset that dataset even further in order to create separate layers on the map for each type of incident. Here I can use a trick I talked about in an earlier post about using dictionaries to store dataframes.

I first need to instantiate an empty dictionary (type_dict) to store all the subsets of the dataframe. Then I can use a for loop to subset the explosions dataset by each incident type, and store them in the dictionary using the incident type as the key.

Then, I can make a color dictionary to color the points according to the incident type. This can be done manually, by choosing a color and creating a dictionary where the key is the incident type and the value is a color (either the color name, hex code, or RGB values). However, I wanted to make this a little more generalized, so I can reuse this code to assign colors to other types of incidents I may include later. To do this, I made a function that takes a number n and a matplotlib colormap name and returns that colormap segmented into n colors. I then used this function to create a dictionary (color_dict) where the keys were the incident types (same keys as type_dict) and the values were each color from the color map.

Since the RGB values came out on a scale of 0 to 1, I multiplied all the values by 256 and formatted them as RGB(red,green,blue) in order to make them easier to use. This is how color_dict ended up:

Now we have everything in place to actually make the map.

I start by instantiating the folium map object with folium.map(). Then I use a for loop to iterate through type_dict, the dictionary that contains all of the subsets of the explosions dataframe. For each subset, I call a function, pointcolors, that assigns the color from color_dict which corresponds to the incident type in that subset to all the values in that subset.

Then I instantiate two folium features that will make the map more legible: MarkerCluster and FeatureGroupSubGroup. MarkerCluster will cluster points that are close together and indicate the number of points being clustered at different zoom levels, reducing the clutter on the map when there are a lot of points in one place or when you’re zoomed out. FeatureGroupSubGroup will make a separate layer of for each incident type so I can add the points for that incident type to that layer instead of adding them directly to the map, and then I can add the full layer to the map (this allows the user to select which layers of points they want to appear on the map).

Then for each point in that subset, I create a CircleMarker and assign it some popup text, and then I add that CircleMarker to the FeatureGroupSubGroup. After all of the points for that subset have been added to the FeatureGroupSubGroup, the FeatureGroupSubGroup itself is added to the map. Then, after all of the subsets have been added to the map, I add folium.map.LayerControl() to the map to allow for layer selection. Then all that’s left to do is call the map itself to see how it looks (I also include a line here to save the map as an html file to it can be opened later without having to rerun all this code).

Screenshot of the map (download the html file from github to open in your browser)

Here’s a link to my github repo with all of this code, data, and the html map file: https://github.com/NoahChristiansen/folium-FireMap