如何使用Folium实现鼠标悬停高亮国家边界?
在Folium中实现鼠标悬停高亮国家边界的方案
你目前用Plotly实现了可运行的人口 choropleth 地图,想切换到Folium实现鼠标悬停高亮单个国家边界的功能对吧?Folium本身没有直接封装好的一键函数,但通过GeoJson图层配合自定义样式函数,完全可以实现这个交互效果,下面是具体的实现步骤和代码示例:
核心思路
Folium的GeoJson图层支持两个关键函数来控制交互样式:
style_function:定义地图元素的默认显示样式(包括choropleth的颜色映射)highlight_function:定义鼠标悬停时的高亮样式(比如加粗边界、改变填充透明度)
另外可以配合GeoJsonTooltip实现悬停时显示国家名称、人口等自定义信息。
完整代码示例(结合你的数据处理逻辑)
首先保留你原有的数据处理部分,然后替换Plotly的可视化代码为以下Folium代码:
# 保留你原有的数据处理代码(从import到df生成的部分) import urllib.request import json import numpy as np import pandas as pd import csv import itertools import folium from folium.features import GeoJsonTooltip, GeoJsonPopup # --- 你的原有数据处理代码 --- with urllib.request.urlopen("http://api.population.io:80/1.0/countries") as url: api_data = json.loads(url.read().decode()) twoD_data = np.array(list(api_data.values())) all_countries = twoD_data.ravel() country_and_countryCodes_csv = pd.read_csv("http://kejser.org/wp-content/uploads/2014/06/Country.csv", delimiter='|') country_and_countryCodes = country_and_countryCodes_csv[["CountryName","Alpha3Code"]] chained_country_list = set(itertools.chain.from_iterable(country_and_countryCodes.values.tolist())) & set(all_countries) country_ready_for_fetch = [] for country in chained_country_list: try: if '/' not in country: j = country.replace(" ","%20") country_ready_for_fetch.append(j) except AttributeError: pass year = "/2013" date = year + '-01-01' country_population = [] for country in country_ready_for_fetch: url = "http://api.population.io:80/1.0/population/" with urllib.request.urlopen(url + country + date) as url: data = json.loads(url.read().decode()) country_population.append(country) country_population.append(data) result = {} for i in range(0, len(country_population), 2): result[country_population[i]] = country_population[i+1]['total_population']['population'] result = {key.replace('%20', ' '): value for key, value in result.items()} l = np.array(country_and_countryCodes).tolist() for i in l: i.append(result.get(i[0])) df = pd.DataFrame(l) df.columns = ['Country','CountryCode','Population'] df['CountryCode'] = df['CountryCode'].str.upper() # --- 以下是Folium可视化部分 --- # 1. 初始化地图 m = folium.Map(location=[20, 0], zoom_start=2) # 2. 加载国家边界GeoJSON(确保ISO3代码匹配你的数据) geojson_url = "https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json" with urllib.request.urlopen(geojson_url) as url: country_geojson = json.loads(url.read().decode()) # 3. 定义颜色映射函数(实现choropleth效果) def get_color(population): if population is None: return '#cccccc' elif population < 10000000: return '#fee5d9' elif population < 50000000: return '#fcae91' elif population < 200000000: return '#fb6a4a' else: return '#cb181d' # 4. 定义默认样式函数 def style_function(feature): # 匹配当前国家的人口数据 country_code = feature['id'] pop = df.loc[df['CountryCode'] == country_code, 'Population'].values pop = pop[0] if len(pop) > 0 else None return { 'fillColor': get_color(pop), 'color': '#333333', 'weight': 1, 'fillOpacity': 0.7 } # 5. 定义悬停高亮样式函数 def highlight_function(feature): return { 'weight': 3, 'color': '#000000', 'fillOpacity': 0.9 } # 6. 添加GeoJson图层到地图 folium.GeoJson( country_geojson, style_function=style_function, highlight_function=highlight_function, tooltip=GeoJsonTooltip( fields=['name'], aliases=['国家名称:'], localize=True ), popup=GeoJsonPopup( fields=['name'], aliases=['国家:'], localize=True, max_width=300, labels=True ) ).add_to(m) # 7. 保存或显示地图(Jupyter Notebook中直接运行m即可显示) m.save('population_map.html') # 在Jupyter中显示地图 # m
关键部分说明
- GeoJSON数据匹配:示例中用的GeoJSON以ISO3代码作为
id,正好和你的df['CountryCode']匹配,这样才能正确关联人口数据。如果你的GeoJSON用的是其他标识(比如国家名称),需要调整匹配逻辑。 - 样式函数:
style_function负责根据人口值设置填充色,实现choropleth效果;highlight_function在鼠标悬停时加粗边界、提高填充透明度,达到高亮效果。 - 交互信息:
GeoJsonTooltip实现悬停时的轻量信息展示,GeoJsonPopup则是点击时的弹窗信息,你可以根据需要添加Population字段到tooltip或popup中。
额外提示
- 如果需要更精细的颜色映射,可以用
branca.colormap模块来生成连续的颜色渐变,比如:
然后在from branca.colormap import LinearColormap colormap = LinearColormap(colors=['#fee5d9', '#fcae91', '#fb6a4a', '#cb181d'], vmin=df['Population'].min(), vmax=df['Population'].max())style_function中调用colormap(pop)获取颜色。 - 确保你的GeoJSON数据完整,部分小型国家可能在基础GeoJSON中没有包含,需要调整数据源。
内容的提问来源于stack exchange,提问作者Maksymilian
相关产品推荐
相关产品推荐

