Sitemap

Creating an Interactive Map in Python to Visualise Survey Respondents

4 min readDec 20, 2024

--

Introduction

Understanding geographical trends in survey data can provide valuable insights for decision-making. For example, mapping survey respondents by their location helps organisations better allocate resources, design targeted outreach strategies, and identify underserved areas.

In this article, we’ll explore how to create an interactive map using Python to visualise the geographical distribution of survey participants. This project was inspired by a need to analyse survey data from Brampton, Ontario for one of my clients. Although the original dataset cannot be disclosed due to confidentiality agreements, we’ll simulate a similar scenario using generated data and postal code mapping files.

By the end of this article, you’ll learn how to:

  1. Prepare and clean survey data by validating Canadian postal codes.
  2. Map postal codes to latitude/longitude coordinates using a reference file.
  3. Generate an interactive map with dynamic markers sized by respondent density using folium.

The Use Case

In the original project, the goal was to visualise where survey respondents were located in Brampton, Ontario, based on their postal codes. The interactive map provided:

  • A clear understanding of respondent density across neighbourhoods.
  • Insights into high-response areas to improve planning and outreach.
  • Dynamic exploration for stakeholders to interact with the map and data.

This method is versatile and can be applied to customer location analysis, delivery hotspots, or survey responses.

Tools and Libraries

To create the map, we’ll use:

  1. pandas: For data manipulation and cleaning.
  2. folium: To generate an interactive map and add circle markers.
  3. re: For validating and formatting postal codes.

You can install the required libraries using:

pip install pandas folium

Code Walkthrough

Step 1: Clean and Validate Postal Codes

Before we create the map, we ensure postal codes are clean and in a valid format.

import pandas as pd
import re
def clean_postal_codes(df, column_name):
"""Clean and validate postal codes."""
def clean_postal(postal):
if pd.isna(postal):
return None
# Remove spaces, convert to uppercase, and remove invalid characters
postal = re.sub(r"[^A-Z0-9]", "", postal.upper().strip())
# Reformat valid postal codes: A1A1A1 -> A1A 1A1
if re.match(r"^[A-Z]\d[A-Z]\d[A-Z]\d$", postal):
return postal[:3] + " " + postal[3:]
return None # Invalid postal code
df[column_name] = df[column_name].apply(clean_postal)
return df

Step 2: Map Postal Codes to Latitude/Longitude

Using a postal code reference file (e.g., CanadianPostalCodes202403.csv), we map cleaned postal codes to their respective latitude and longitude.

Note:
I downloaded the Canadian Postal Codes from the ServiceObjects website. In order to download the data file, you would just need to disclose the use of the codes. The file includes a mapping of Canadian Postal Codes to their Latitude and Longitude, which will be required for the map visual.

def map_postal_codes(df, postal_code_col, postal_mapping_path):
"""Map postal codes to latitude and longitude using a reference file."""
# Load the postal mapping file
postal_mapping = pd.read_csv(postal_mapping_path, on_bad_lines='skip')

# Merge cleaned postal codes with latitude/longitude data
df = df.merge(postal_mapping, how="left", left_on=postal_code_col, right_on="POSTAL_CODE")

# Group by postal code and coordinates, then count occurrences
grouped = df.groupby([postal_code_col, "LATITUDE", "LONGITUDE"]).size().reset_index(name="count")
return grouped

Step 3: Generate the Interactive Map

Once we have the cleaned and aggregated data, we use the folium library to generate the map. The markers' size reflects the count of respondents for each postal code.

import folium
# Initialize the map centered on Brampton, Ontario
map_center = [43.7315, -79.7604]
brampton_map = folium.Map(location=map_center, zoom_start=11)
# Add circle markers to the map
for _, row in postal_summary.iterrows():
folium.CircleMarker(
location=[row['LATITUDE'], row['LONGITUDE']],
radius=row['count'] * 2, # Marker size scales with count
color='blue',
fill=True,
fill_opacity=0.5,
popup=f"<b>Postal Code:</b> {row['postal_code']}<br><b>Count:</b> {row['count']}"
).add_to(brampton_map)
# Save the map
brampton_map.save("brampton_map.html")
print("Interactive map saved as 'brampton_map.html'")

How It All Comes Together

Here’s the complete workflow:

Get Masego’s stories in your inbox

Join Medium for free to get updates from this writer.

Load and Clean Survey Data:

  • Postal codes are cleaned and reformatted to match Canadian standards.

Map Postal Codes to Coordinates:

  • Reference data containing latitude/longitude values for postal codes is merged with the survey data.

Create an Interactive Map:

  • Circle markers are added to the map. Marker sizes reflect the number of responses for each postal code.
  • The map is saved as an HTML file, which can be viewed in any browser.

Final Output: Interactive Map

When you run the script, you’ll get an HTML file (brampton_map.html) containing an interactive map. You can:

  • Zoom and pan across Brampton to explore response densities.
  • Click on a circle marker to view the postal code and the response count.
Press enter or click to view image in full size
Screenshot of interactive map
Video Demonstration of Interactive Map output

Benefits of This Visualisation

  1. Engagement: Interactive maps are more engaging and easier to understand for stakeholders.
  2. Geographical Insights: Visualising data spatially uncovers patterns not visible in tables.
  3. Shareability: Maps can be saved and shared as HTML files, making them accessible to anyone.

Key Takeaways:

  • Data Cleaning is essential for ensuring accurate results and postal code mapping.
  • Postal Code Mapping allows you to visualise geographical data.
  • Interactive Maps make data engaging and easy to explore.

Conclusion

In this article, we demonstrated how to create an interactive map to visualise survey respondent locations using Python. By cleaning postal codes, mapping them to coordinates, and leveraging folium, we built a dynamic and insightful visualisation of respondent density.

The approach is versatile and can be extended to other geographical datasets like customer locations, sales hotspots, or delivery zones based on postal codes.

You can find the full code and project details in the GitHub repository. Give it a try, and adapt it for your own use case! 🚀

--

--