Close Menu
  • AI
  • Content Creation
  • Tech
  • Robotics
AI-trends.todayAI-trends.today
  • AI
  • Content Creation
  • Tech
  • Robotics
Trending
  • BottleCap AI Releases ThinkingCap-Qwen3.8-27B: 37.2% Fewer Considering Tokens at a 0.86pp Accuracy Price
  • What if I find an AI agent that is worth the risk?
  • Google’s Gemini Can Now Make Requires You on Pixel Telephones
  • An OpenAI Agent Hacked Australia’s Well being Service. Their Authorities Discovered Out Months Later
  • Vibe Coding for Inexperienced persons — Easy Information for Creators, Entrepreneurs, and Non-technical People
  • Contrastive-LM Releases CLM-8B: An Open System One Mannequin That Scores Agent Actions As much as 9× Quicker Than Jev
  • YouTube doubles down on video procuring with AI-powered ‘Ask YouTube’ function
  • YouTube provides new creator instruments like video A/B testing, dynamic thumbnails, and stay dubbing
AI-trends.todayAI-trends.today
Home»Tech»Learn how to create interactive geospatial dashboards using Folium, including heatmaps, choropleths (time animation), marker clustering and advanced interactive plugins.

Learn how to create interactive geospatial dashboards using Folium, including heatmaps, choropleths (time animation), marker clustering and advanced interactive plugins.

Tech By Gavin Wallace28/02/20269 Mins Read
Facebook Twitter LinkedIn Email
DeepSeek Releases R1-0528: An Open-Source Reasoning AI Model Delivering Enhanced
DeepSeek Releases R1-0528: An Open-Source Reasoning AI Model Delivering Enhanced
Share
Facebook Twitter LinkedIn Email

Here’s what I found Folium We build interactive maps in this tutorial that work with Colab and any Python local setup. Heatmaps are used to visualize spatial density, we explore different basemap styles and design HTML popups for richer markers. Then, we create region-level maps using GeoJSON. We scale up to thousands of locations with marker clustering and use a timestamped overlay. We combine USGS real-world earthquake data, layered heatmaps and legends with fullscreen controls, legends, and layered magnitude buckets to create a dashboard-like global monitoring tool.

import folium
From folium Import Plugins
HeatMap, MarkerCluster (TimestampedGeoJson), MiniMap, Draw or Fullscreen can be imported from folium.plugins.
import pandas as pd
Numpy can be imported as np
Import json
Import requests
Datetime can be imported as timedelta
Import branca.colormap in cm


print(f"Folium version: {folium.__version__}")
print("All imports successful!n")

Import all libraries required, including Folium, Pandas NumPy Requests, Folium plug-ins and Requests. By confirming that the Folium is the latest version and that all dependencies are loaded, we initialize our mapping workflow. This set-up establishes a technical foundation to build interactive maps and integrate external geospatial data sources.

def create_multi_tile_map():
   """Create a map with multiple tile layers"""
   m = folium.Map(
       location=[40.7128, -74.0060],
       zoom_start=12,
       tiles="OpenStreetMap"
   )
  
   folium.TileLayer('cartodbpositron', name="CartoDB Positron").add_to(m)
   folium.TileLayer('cartodbdark_matter', name="CartoDB Dark Matter").add_to(m)
  
   folium.TileLayer(
       tiles="https://tiles.stadiamaps.com/tiles/stamen_terrain/{z}/{x}/{y}.png",
       attr="Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL",
       name="Terrain"
   ).add_to(m)
  
   folium.TileLayer(
       tiles="https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}.png",
       attr="Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL",
       name="Toner"
   ).add_to(m)
  
   folium.TileLayer(
       tiles="https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg",
       attr="Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL",
       name="Watercolor"
   ).add_to(m)
  
   folium.LayerControl().add_to(m)
  
 Return m

Create a base map with multiple layers and set up different tile providers for different visual styles. To switch between different perspectives, we add layers for terrain, darkness, toners, and watercolors. We include a panel to control the layer so we can toggle between map styles dynamically and better explore spatial information.

def create_advanced_markers_map():
   """Create map with custom markers and HTML popups"""
 "Landmarks" = [
       {'name': 'Statue of Liberty', 'lat': 40.6892, 'lon': -74.0445, 'type': 'monument', 'visitors': 4500000},
       {'name': 'Empire State Building', 'lat': 40.7484, 'lon': -73.9857, 'type': 'building', 'visitors': 4000000},
       {'name': 'Central Park', 'lat': 40.7829, 'lon': -73.9654, 'type': 'park', 'visitors': 42000000},
       {'name': 'Brooklyn Bridge', 'lat': 40.7061, 'lon': -73.9969, 'type': 'bridge', 'visitors': 4000000},
       {'name': 'Times Square', 'lat': 40.7580, 'lon': -73.9855, 'type': 'plaza', 'visitors': 50000000}
   ]
  
   m = folium.Map(location=[40.7128, -74.0060], zoom_start=12)
  
   icon_colors = {
       'monument': 'red',
       'building': 'blue',
       'park': 'green',
       'bridge': 'orange',
       'plaza': 'purple'
   }
  
   icon_symbols = {
       'monument': 'star',
       'building': 'home',
       'park': 'tree',
       'bridge': 'road',
       'plaza': 'shopping-cart'
   }
  
 For landmark in landmarks
 HTML = F"""
       

{landmark['name']}


Type: {landmark['type'].title()}

Visitor Numbers: {landmark['visitors']:,}

""" iframe=folium.IFrame (html, width=220 and height=250). popup = folium.Popup(iframe, max_width=220) folium.Marker( location=[landmark['lat']The landmark['lon']], popup=popup, tooltip=landmark['name'], icon=folium.Icon( color=icon_colors[landmark['type']], icon=icon_symbols[landmark['type']], prefix='fa' ) ).add_to(m) folium.CircleMarker( location=[40.7128, -74.0060], radius=20, popup='NYC Center', color="#3186cc", fill=True, fillColor="#3186cc", fillOpacity=0.2 ).add_to(m) Return m

Our map is built with advanced marker and rich HTML popups that represent real world landmarks. To improve the visual clarity of the map and its semantic content, we customize markers, symbols, colors, etc. based on location type. We embed structured HTML into popups to present context-specific information within the interactive map.

Def Create_Heatmap():
   """Create a heatmap showing data density"""
   np.random.seed(42)
   n_incidents = 1000
  
   crime_data = []
 Hotspots = [
       [40.7580, -73.9855],
       [40.7484, -73.9857],
       [40.7128, -74.0060],
   ]
  
 For _, in range (n_incidents),:
 The hotspot is also known as the hotspot[np.random.choice(len(hotspots))]
 Lat = Hotspot[0] + np.random.normal(0, 0.02)
       lon = hotspot[1] + np.random.normal(0, 0.02)
       intensity = np.random.uniform(0.3, 1.0)
       crime_data.append([lat, lon, intensity])
  
   m = folium.Map(location=[40.7128, -74.0060], zoom_start=12)
  
   HeatMap(
       crime_data,
       min_opacity=0.2,
       max_zoom=18,
       max_val=1.0,
       radius=15,
       blur=25,
       gradient={
           0.0: 'blue',
           0.3: 'lime',
           0.5: 'yellow',
           0.7: 'orange',
           1.0: 'red'
       }
   ).add_to(m)
  
   title_html=""'
                

Heatmap of NYC Crime Density

Simulation of incident data

''' m.get_root().html.add_child(folium.Element(title_html)) Return m

We use synthetic spatial data to generate heatmaps that visualize patterns in density. In order to uncover spatial concentration patterns, we use gradient-based visualization of intensity and clustered coordinates. This density layer is superimposed on the map to reveal how different events are distributed across regions.

def create_choropleth_map():
   """Create a choropleth map showing data across regions"""
   us_states_url="https://raw.githubusercontent.com/python-visualization/folium/master/examples/data/us-states.json"
  
   try:
       us_states = requests.get(us_states_url).json()
   except:
       print("Warning: Could not fetch GeoJSON data. Using offline sample.")
 Return No
  
   state_data = {
       'Alabama': 5.1, 'Alaska': 6.3, 'Arizona': 4.7, 'Arkansas': 3.8, 'California': 5.3,
       'Colorado': 3.9, 'Connecticut': 4.3, 'Delaware': 4.1, 'Florida': 3.6, 'Georgia': 4.0,
       'Hawaii': 2.8, 'Idaho': 2.9, 'Illinois': 5.0, 'Indiana': 3.5, 'Iowa': 3.1,
       'Kansas': 3.3, 'Kentucky': 4.3, 'Louisiana': 4.6, 'Maine': 3.2, 'Maryland': 4.0,
       'Massachusetts': 3.6, 'Michigan': 4.3, 'Minnesota': 3.2, 'Mississippi': 5.2,
       'Missouri': 3.7, 'Montana': 3.5, 'Nebraska': 2.9, 'Nevada': 4.8, 'New Hampshire': 2.7,
       'New Jersey': 4.2, 'New Mexico': 5.0, 'New York': 4.5, 'North Carolina': 4.0,
       'North Dakota': 2.6, 'Ohio': 4.2, 'Oklahoma': 3.4, 'Oregon': 4.2, 'Pennsylvania': 4.4,
       'Rhode Island': 4.0, 'South Carolina': 3.5, 'South Dakota': 2.9, 'Tennessee': 3.6,
       'Texas': 4.0, 'Utah': 2.8, 'Vermont': 2.8, 'Virginia': 3.3, 'Washington': 4.6,
       'West Virginia': 5.1, 'Wisconsin': 3.4, 'Wyoming': 3.6
   }
  
   df = pd.DataFrame(list(state_data.items()), columns=['State', 'Unemployment'])
  
   m = folium.Map(location=[37.8, -96], zoom_start=4)
  
   folium.Choropleth(
       geo_data=us_states,
       name="choropleth",
       data=df,
       columns=['State', 'Unemployment'],
       key_on='feature.properties.name',
       fill_color="YlOrRd",
       fill_opacity=0.7,
       line_opacity=0.5,
       legend_name="Unemployment Rate (%)"
   ).add_to(m)
  
   style_function = lambda x: {Style_function = Lambda x 'fillColor: #fffffff,
                               'color':'#000000',
                               'fillOpacity': 0.1,
                               'weight': 0.1}
   highlight_function = lambda x: {highlight_function = lambda'x': "fillColor: #000000'
                                   'color':'#000000',
                                   'fillOpacity': 0.50,
                                   'weight': 0.1}
  
   NIL = folium.features.GeoJson(
       us_states,
       style_function=style_function,
       control=False,
       highlight_function=highlight_function,
       tooltip=folium.features.GeoJsonTooltip(
           fields=['name'],
           aliases=['State:'],
           style=("background-color: white; color: #333333; font-family: arial; font-size: 12px; padding: 10px;")
       )
   )
   m.add_child(NIL)
   m.keep_in_front(NIL)
  
   folium.LayerControl().add_to(m)
  
 Return m

GeoJSON boundary information is combined with structured numerical attribute to create a Choropleth Map. Mapping unemployment rates onto geographic regions, we use gradients of color to show statistical differences. We can use tooltips and hover interactions to view data for specific regions directly on the map.

def create_marker_cluster_map():
   """Create a map with marker clustering for large datasets"""
   np.random.seed(123)
   n_locations = 5000
  
   lats = np.random.uniform(25, 49, n_locations)
   lons = np.random.uniform(-125, -65, n_locations)
 values = random.randint(1), 100, location(n)
  
   df_markers = pd.DataFrame({
       'lat': lats,
       'lon': lons,
 "Value": Values
   })
  
   m = folium.Map(location=[37.8, -96], zoom_start=4)
  
   marker_cluster = MarkerCluster(
       name="Location Cluster",
       overlay=True,
       control=True
   ).add_to(m)
  
 Row in df_markers.iterrows for the idx():
 If row['value'] 
                

Marker Clustering Demo

Zoom in to view individual markers

”’
m.get_root().html.add_child(folium.Element(title_html))

Return m

def create_time_series_map():
“””Create an animated map showing data changes over time”””
start_date = datetime(2024, 8, 1)
Features = []

Path = [
[25.0, -70.0], [26.5, -72.0], [28.0, -74.5], [29.5, -76.5],
[31.0, -78.0], [32.5, -79.5], [34.0, -80.5], [35.5, -81.0]
]

If i is (lat or lon) then enumerate the path.Meaning of feature:
timestamp = start_date + timedelta(hours=i*6)

feature = {
’type’: ‘Feature’,
‘geometry’: {
’type’: ‘Point’,
‘coordinates’: [lon, lat]
},
‘properties’: {
’time’: timestamp.isoformat(),
‘popup’: f’Hurricane Position
Time: {timestamp.strftime(“%Y-%m-%d %H:%M”)}
Category: {min(5, i//2 + 1)}’,
‘icon’: ‘circle’,
‘iconstyle’: {
‘fillColor’: [‘yellow’, ‘orange’, ‘red’, ‘darkred’, ‘purple’][min(4, i//2)],
‘fillOpacity’: 0.8,
‘stroke’: ’true’,
‘radius’: 8 + i * 2
}
}
}
features.append(feature)

m = folium.Map(
location=[30.0, -75.0],
zoom_start=5,
tiles=”CartoDB Positron”
)

TimestampedGeoJson(
{’type’: ‘FeatureCollection’, ‘features’: features},
period=’PT6H’,
add_last_point=True,
auto_play=True,
loop=True,
max_speed=2,
loop_button=True,
date_options=”YYYY-MM-DD HH:mm”,
time_slider_drag_update=True
).add_to(m)

title_html=””‘

Hurricane Path Animation

Hurricane tracking simulation
You can play/pause the video by using the buttons below.

”’
m.get_root().html.add_child(folium.Element(title_html))

Return m

def create_interactive_plugins_map():
“””Create a map with multiple interactive plugins”””
m = folium.Map(
location=[40.7128, -74.0060],
zoom_start=12,
tiles=”OpenStreetMap”
)

minimap = MiniMap(toggle_display=True)
m.add_child(minimap)

draw = Draw(
export=True,
filename=”drawn_shapes.geojson”,
position=’topleft’,
draw_options={
‘polyline’: True,
‘polygon’: True,
‘circle’: True,
‘rectangle’: True,
‘marker’: True,
‘circlemarker’: True
},
edit_options={‘edit’: True}
)
m.add_child(draw)

Fullscreen(
position=’topright’,
title=”Expand map”,
title_cancel=”Exit fullscreen”,
force_separate_button=True
).add_to(m)

plugins.MeasureControl(
position=’bottomleft’,
primary_length_unit=”kilometers”,
secondary_length_unit=”miles”,
primary_area_unit=”sqkilometers”,
secondary_area_unit=”acres”
).add_to(m)

plugins.MousePosition(
position=’bottomright’,
separator=” | “,
empty_string=’NaN’,
lng_first=True,
num_digits=20,
prefix=’Coordinates:’,
).add_to(m)

plugins.LocateControl(
auto_start=False,
position=’topleft’
).add_to(m)

folium.Marker(
[40.7128, -74.0060],
popup=’NYC
Draw with the tools you have!’,
icon=folium.Icon(color=”red”, icon=’info-sign’)
).add_to(m)

Return m

def create_earthquake_map():
“””Create comprehensive earthquake visualization using real USGS data”””
url=”https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson”

try:
Response = Requests.get(URL)
earthquake_data = response.json()
print(f”Successfully loaded {len(earthquake_data[‘features’])} earthquakes”)
Only Exceptions as follows:
print(f”Error fetching data: {e}”)
earthquake_data = {
‘features’: [
{
‘properties’: {‘mag’: 5.2, ‘place’: ‘Sample Location 1′, ’time’: 1640000000000},
‘geometry’: {‘coordinates’: [-122.0, 37.0, 10]}
},
{
‘properties’: {‘mag’: 6.1, ‘place’: ‘Sample Location 2′, ’time’: 1640100000000},
‘geometry’: {‘coordinates’: [140.0, 35.0, 20]}
}
]
}

Seismological earthquakes []
For feature in earthquake_data[‘features’]:
Props = feature[‘properties’]
Coords = feature[‘geometry’][‘coordinates’]

earthquakes.append({
“Lat”: coordinates[1],
Coords[0],
Coords[2],
‘magnitude’: props.get(‘mag’, 0),
‘place’: props.get(‘place’, ‘Unknown’),
’time’: datetime.fromtimestamp(props.get(’time’, 0) / 1000)
})

df_eq = pd.DataFrame(earthquakes)

print(f”nEarthquake Statistics:”)
print(f”Total earthquakes: {len(df_eq)}”)
print(f”Magnitude range: {df_eq[‘magnitude’].min():.1f} – {df_eq[‘magnitude’].max():.1f}”)
print(f”Depth range: {df_eq[‘depth’].min():.1f} – {df_eq[‘depth’].max():.1f} km”)

m = folium.Map(
location=[20, 0],
zoom_start=2,
tiles=”CartoDB dark_matter”
)

minor = folium.FeatureGroup(name=”Minor (

Magnitude {mag:.1f}


Location: {eq[‘place’]}

Depth: {eq[‘depth’]:.1f} km

Time: {eq[’time’].strftime(‘%Y-%m-%d %H:%M:%S’)}

Coordinates: {eq[‘lat’]:.4f}, {eq[‘lon’]:.4f}

“””

folium.CircleMarker(
location=[eq[‘lat’]The eq[‘lon’]],
radius=radius,
popup=folium.Popup(popup_html, max_width=270),
tooltip=f”M{mag:.1f} – {eq[‘place’]}”,
color=color,
fill=True,
fillColor=color,
fillOpacity=0.7,
weight=2
).add_to(group)

minor.add_to(m)
moderate.add_to(m)
strong.add_to(m)
major.add_to(m)

heat_data = [[row[‘lat’]Row[‘lon’]Row[‘magnitude’]The row number in df_eq.iterrows is ] for the idx.()]
heatmap = folium.FeatureGroup(name=”Density Heatmap”, show=False)
HeatMap(
heat_data,
min_opacity=0.3,
radius=15,
blur=20,
gradient={0.4: ‘blue’, 0.6: ‘cyan’, 0.7: ‘lime’, 0.8: ‘yellow’, 1: ‘red’}
).add_to(heatmap)
heatmap.add_to(m)

folium.LayerControl(position=’topright’, collapsed=False).add_to(m)

legend_html=””‘

Earthquake Magnitude

● Minor

● Modest (4.0 to 5.0)

● Strong (5.0-6.0).

● Major (≥ 6.0)


USGS data (last 30 days).

”’
m.get_root().html.add_child(folium.Element(legend_html))

title_html=””‘

🌍 Global Earthquake Monitor

Real-time earthquake data (M ≥ 2.5)
You can click on markers to see more details.| Toggle layers to explore

”’
m.get_root().html.add_child(folium.Element(title_html))

Fullscreen(position=’topright’).add_to(m)

Return m

If the __name__ equalsMaps = “__main__”:
print(“=” * 80)
print(“ADVANCED FOLIUM TUTORIAL – ALL EXAMPLES”)
print(“=” * 80)
print(“nGenerating all maps…n”)

maps = {
‘multi_tile_map’: create_multi_tile_map(),
‘advanced_markers_map’: create_advanced_markers_map(),
‘heatmap’: create_heatmap(),
‘choropleth_map’: create_choropleth_map(),
‘marker_cluster_map’: create_marker_cluster_map(),
’time_series_map’: create_time_series_map(),
‘interactive_plugins_map’: create_interactive_plugins_map(),
‘earthquake_map’: create_earthquake_map()
}

print(“n” + “=” * 80)
print(“SAVING MAPS TO HTML FILES”)
print(“=” * 80)

Name map_obj when using maps.items():
If map_obj does not equal None, then:
Filename = F”{name}.html”
map_obj.save(filename)
print(f”✓ Saved: {filename}”)
else:
print(f”✗ Skipped: {name} (map generation failed)”)

print(“n” + “=” * 80)
print(“ALL MAPS GENERATED SUCCESSFULLY!”)
print(“=” * 80)
print(“nYou can now:”)
print(“1. Open any HTML file in your browser to view the interactive map”)
print(“2. Access the map objects in code using the ‘maps’ dictionary”)
print(“3. Display maps in Jupyter/Colab by returning the map object”)
print(“nExample: To display the earthquake map in a notebook, just run:”)
print(” maps[‘earthquake_map’]”)
print(“n” + “=” * 80)

animation ar ETH van
Share. Facebook Twitter LinkedIn Email
Avatar
Gavin Wallace

Related Posts

BottleCap AI Releases ThinkingCap-Qwen3.8-27B: 37.2% Fewer Considering Tokens at a 0.86pp Accuracy Price

24/09/2026

Contrastive-LM Releases CLM-8B: An Open System One Mannequin That Scores Agent Actions As much as 9× Quicker Than Jev

24/09/2026

A Coding Information to TypeSafe AI Jev: Typed Choices, Calibrated Confidence, and Speculative Fan-Out with a System One Mannequin

24/09/2026

Google Releases Gemini 3.8 Flash TTS and Flash-Lite TTS With Immediate-Primarily based Voice Design

23/09/2026
Top News

A New AI Documentary Puts CEOs in the Hot Seat—but Goes Too Easy on Them

Meta and Mercor Pause Work After Breach of Data Puts AI Industry Secrets in Danger

The WIRED roundup: Full Demon Mode for ChatGPT

OpenAI Is Developing a ‘Persistent’ AI Agent

Bernie Sanders foresaw this Coming

Load More
AI-Trends.Today

Your daily source of AI news and trends. Stay up to date with everything AI and automation!

X (Twitter) Instagram
Top Insights

OpenAI Introduces Dawn: A Cybersecurity Initiative That Places Codex Safety on the Middle of Vulnerability Detection and Patch Validation

12/05/2026

OpenAI Creates a New Framework to Disclose Dangerous AI Habits

16/09/2026
Latest News

BottleCap AI Releases ThinkingCap-Qwen3.8-27B: 37.2% Fewer Considering Tokens at a 0.86pp Accuracy Price

24/09/2026

What if I find an AI agent that is worth the risk?

24/09/2026
X (Twitter) Instagram
  • Privacy Policy
  • Contact Us
  • Terms and Conditions
© 2026 AI-Trends.Today

Type above and press Enter to search. Press Esc to cancel.