How to Build Interactive Geospatial Dashboards Using Folium with Heatmaps, Choropleths, Time Animation, Marker Clustering, and Advanced Interactive Plugins

by CryptoExpert
fiverr


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 = np.random.randint(1, 100, n_locations)

df_markers = pd.DataFrame({
‘lat’: lats,
‘lon’: lons,
‘value’: values
})

m = folium.Map(location=[37.8, -96], zoom_start=4)

Betfury

marker_cluster = MarkerCluster(
name=”Location Cluster”,
overlay=True,
control=True
).add_to(m)

for idx, row in df_markers.iterrows():
if row[‘value’] < 33:
color=”green”
elif row[‘value’] < 66:
color=”orange”
else:
color=”red”

folium.Marker(
location=[row[‘lat’], row[‘lon’]],
popup=f”Value: {row[‘value’]}”,
tooltip=f”Location {idx}”,
icon=folium.Icon(color=color, icon=’info-sign’)
).add_to(marker_cluster)

folium.LayerControl().add_to(m)

title_html=””‘
<div style=”position: fixed;
top: 10px; left: 50px; width: 350px; height: 60px;
background-color: white; border:2px solid grey; z-index:9999;
font-size:14px; padding: 10px”>
<h4 style=”margin: 0;”>Marker Clustering Demo</h4>
<p style=”margin: 5px 0 0 0; font-size: 12px;”>5000 markers – zoom to see individual points</p>
</div>
”’
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]
]

for i, (lat, lon) in enumerate(path):
timestamp = start_date + timedelta(hours=i*6)

feature = {
‘type’: ‘Feature’,
‘geometry’: {
‘type’: ‘Point’,
‘coordinates’: [lon, lat]
},
‘properties’: {
‘time’: timestamp.isoformat(),
‘popup’: f’Hurricane Position<br>Time: {timestamp.strftime(“%Y-%m-%d %H:%M”)}<br>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=””‘
<div style=”position: fixed;
top: 10px; left: 50px; width: 300px; height: 80px;
background-color: white; border:2px solid grey; z-index:9999;
font-size:14px; padding: 10px”>
<h4 style=”margin: 0;”>Hurricane Path Animation</h4>
<p style=”margin: 5px 0 0 0; font-size: 12px;”>Simulated hurricane tracking<br>
Use controls below to play/pause</p>
</div>
”’
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='<b>NYC</b><br>Try the drawing tools!’,
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”)
except Exception as e:
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]}
}
]
}

earthquakes = []
for feature in earthquake_data[‘features’]:
props = feature[‘properties’]
coords = feature[‘geometry’][‘coordinates’]

earthquakes.append({
‘lat’: coords[1],
‘lon’: coords[0],
‘depth’: 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 (< 4.0)”)
moderate = folium.FeatureGroup(name=”Moderate (4.0-5.0)”)
strong = folium.FeatureGroup(name=”Strong (5.0-6.0)”)
major = folium.FeatureGroup(name=”Major (≥ 6.0)”)

for idx, eq in df_eq.iterrows():
mag = eq[‘magnitude’]

if mag < 4.0:
color=”green”
radius = 3
group = minor
elif mag < 5.0:
color=”yellow”
radius = 6
group = moderate
elif mag < 6.0:
color=”orange”
radius = 9
group = strong
else:
color=”red”
radius = 12
group = major

popup_html = f”””
<div style=”font-family: Arial; width: 250px;”>
<h4 style=”margin: 0; color: {color};”>Magnitude {mag:.1f}</h4>
<hr style=”margin: 5px 0;”>
<p><b>Location:</b> {eq[‘place’]}</p>
<p><b>Depth:</b> {eq[‘depth’]:.1f} km</p>
<p><b>Time:</b> {eq[‘time’].strftime(‘%Y-%m-%d %H:%M:%S’)}</p>
<p><b>Coordinates:</b> {eq[‘lat’]:.4f}, {eq[‘lon’]:.4f}</p>
</div>
“””

folium.CircleMarker(
location=[eq[‘lat’], 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’]] for idx, row in df_eq.iterrows()]
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=””‘
<div style=”position: fixed;
bottom: 50px; right: 50px; width: 200px; height: 180px;
background-color: white; border:2px solid grey; z-index:9999;
font-size:14px; padding: 10px; border-radius: 5px;”>
<h4 style=”margin: 0 0 10px 0;”>Earthquake Magnitude</h4>
<p style=”margin: 5px 0;”><span style=”color: green;”>●</span> Minor (< 4.0)</p>
<p style=”margin: 5px 0;”><span style=”color: yellow;”>●</span> Moderate (4.0-5.0)</p>
<p style=”margin: 5px 0;”><span style=”color: orange;”>●</span> Strong (5.0-6.0)</p>
<p style=”margin: 5px 0;”><span style=”color: red;”>●</span> Major (≥ 6.0)</p>
<hr style=”margin: 10px 0;”>
<p style=”margin: 5px 0; font-size: 11px;”>Data: USGS (Past 30 days)</p>
</div>
”’
m.get_root().html.add_child(folium.Element(legend_html))

title_html=””‘
<div style=”position: fixed;
top: 10px; left: 50px; width: 400px; height: 80px;
background-color: rgba(255, 255, 255, 0.95); border:2px solid grey; z-index:9999;
font-size:14px; padding: 10px; border-radius: 5px;”>
<h3 style=”margin: 0;”>🌍 Global Earthquake Monitor</h3>
<p style=”margin: 5px 0 0 0; font-size: 12px;”>
Real-time earthquake data (M ≥ 2.5)<br>
Click markers for details | Toggle layers to explore
</p>
</div>
”’
m.get_root().html.add_child(folium.Element(title_html))

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

return m

if __name__ == “__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)

for name, map_obj in maps.items():
if map_obj is not None:
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)



Source link

You may also like