Right, let’s talk about making maps. Because sometimes a bar chart just doesn’t cut it when you’re trying to show someone that 80% of your company’s sales come from a single, suspiciously specific zip code in Delaware.

Folium is your go-to here. It’s a Python library that essentially takes the heavy lifting of the JavaScript library Leaflet and wraps it in a Pythonic embrace. The beautiful part? You write Python, and Folium spits out a self-contained HTML file with a fully interactive map. Pan, zoom, click on markers—it’s all there. It feels like magic, but it’s really just clever packaging.

The Absolute Basics: Your First Map

Think of a Folium map as having two fundamental ingredients: a starting location and a starting zoom level. Everything else is garnish. Let’s make a map centered on London, because that’s where the first-time zone was invented, and the world has been both grateful and mildly irritated ever since.

import folium

# Latitude, Longitude, and a starting zoom level. That's it.
london_map = folium.Map(location=[51.5074, -0.1278], zoom_start=13)
london_map.save('my_first_map.html')

Run that. Open the .html file in your browser. Congratulations, you’ve just made a more useful thing than most corporate mission statements. You can pan around, zoom in until you can almost see the Queen’s guards blinking (not really), and zoom out until you see the whole continent.

Why This Actually Works

Folium isn’t rendering these tiles itself; it’s pulling them from a tile server. The default is OpenStreetMap, the Wikipedia of maps. The location parameter is brutally straightforward: it’s [lat, lon]. Not [lon, lat]. I know, I know. GeoJSON uses [lon, lat]. It’s a constant source of fun. Folium uses [lat, lon] because… well, probably because someone made a choice on a Tuesday and we’re all stuck with it. Always double-check this, or you’ll be wondering why your map of Chicago is showing up in the Indian Ocean.

Adding Markers: Because Everything is Somewhere

A map with no points on it is just a pretty picture. Let’s add a marker for the British Museum.

# Create the base map
london_map = folium.Map(location=[51.5074, -0.1278], zoom_start=14)

# Coordinates for the British Museum
british_museum_coords = [51.5194, -0.1269]

# Create a Marker object and add it to the map
folium.Marker(
    location=british_museum_coords,
    popup="The British Museum: Home of piloted artifacts.",
    tooltip="Click me!",
    icon=folium.Icon(color="blue", icon="info-sign"),
).add_to(london_map)

london_map.save('london_with_marker.html')

The popup is what appears when you click the marker. The tooltip appears when you hover over it. Use both. Your users will thank you. The icon parameter lets you choose from a whole suite of color and symbol combinations. color="red" and icon="cloud" are perfectly valid, if you’re making a map of meteorologically-inclined emergency rooms.

The Real Power: Layer Control

Any map worth its salt has different layers. Folium makes this delightfully simple with FeatureGroups and LayerControl.

# Start a new map
map_with_layers = folium.Map(location=[51.5074, -0.1278], zoom_start=13)

# Create two separate feature groups for different categories
landmarks_group = folium.FeatureGroup(name="Landmarks")
food_group = folium.FeatureGroup(name="Food & Drink")

# Add a landmark to the first group
folium.Marker(
    [51.5194, -0.1269],
    popup="British Museum",
    icon=folium.Icon(color='cadetblue')
).add_to(landmarks_group)

# Add a pub to the second group
folium.Marker(
    [51.5155, -0.1272],
    popup="The Sherlock Holmes Pub",
    icon=folium.Icon(color='green', icon='glass')
).add_to(food_group)

# Add the groups to the map (this is a crucial step!)
landmarks_group.add_to(map_with_layers)
food_group.add_to(map_with_layers)

# Finally, add the layer control, which will see the groups we've added
folium.LayerControl().add_to(map_with_layers)

map_with_layers.save('london_with_layers.html')

Now you have a map with a handy toggle in the top right to turn your landmarks and pubs on and off. This is how you stop your map from looking like a bowl of spaghetti thrown at a postcard.

Common Pitfalls and the Tears They Cause

  1. [lat, lon] vs. [lon, lat]: I said it before, I’ll say it again. You will get this wrong. Your data from GeoPandas or a GeoJSON will likely be [lon, lat]. Folium wants [lat, lon]. This is the number one cause of “my map is empty/centered in the ocean” problems.
  2. Saving but not seeing changes: Remember, the .html file is a static snapshot. You must generate the map again and save over the file and then refresh your browser to see any code changes. Your browser is aggressively caching that HTML. Do a hard refresh (Ctrl+F5).
  3. Too many markers: Adding ten thousand markers will crash your browser. It’s a browser, not a supercomputer. For dense data, you need a different approach, like MarkerCluster or heatmaps.
from folium.plugins import MarkerCluster

big_map = folium.Map(location=[40.7128, -74.0060], zoom_start=10)
marker_cluster = MarkerCluster().add_to(big_map)

# Imagine 'df' is a DataFrame with thousands of lat/lon rows
for index, row in df.iterrows():
    folium.Marker(location=[row['lat'], row['lon']]).add_to(marker_cluster)

big_map.save('clustered_map.html')

The MarkerCluster plugin is a lifesaver. It groups nearby markers into a single cluster that splits apart as you zoom in, preventing both visual chaos and browser meltdown.

Folium is one of those libraries that feels almost too easy. You get professional, interactive results for a few lines of code. The key is to think in layers, be meticulous about your coordinate order, and never underestimate the power of a good popup. Now go plot something.