基于访问次数实现地图国家颜色渐变的Python技术求助
问题:基于访问次数为地图上的国家设置不同填充色
我用geopandas、folium等Python库制作地图,已实现用单一颜色标记去过的国家,现希望新增功能:根据访问次数为去过的国家设置不同颜色(如台湾1次设为橙色、日本2次设为红色、韩国3次设为紫色等)。参考matplotlib编写的代码无法运行,恳请提供解决建议。
Excel文件结构
Excel文件包含两列:
- A列名为
Country,存储国家名称(如china、japan、germany等) - B列名为
Visits,存储对应国家的访问次数
我的代码
from google.colab import files import pandas as pd import geopandas as gpd import folium import matplotlib.cm as cm import matplotlib.colors as colors # 上传文件 uploaded = files.upload() filename = next(iter(uploaded)) # 读取Excel文件到DataFrame df = pd.read_excel(filename) # 获取世界地图几何数据 world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) # 合并访问数据与世界地图数据 visited = world.merge(df, left_on='name', right_on='Country') # 创建地图 m = folium.Map(location=[0, 0], zoom_start=2) # 绘制所有国家边界 for _, r in world.iterrows(): sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.001) geo_j = folium.GeoJson(data=sim_geo.to_json(), style_function=lambda x: {'color': 'black'}) folium.Popup(r['name']).add_to(geo_j) geo_j.add_to(m) # 根据访问次数设置颜色的函数 def color(visits): # 创建颜色映射 colormap = cm.get_cmap('YlOrRd') # 将访问次数归一化到0-1范围 norm = colors.Normalize(vmin=1, vmax=4) # 获取颜色并转换为十六进制 rgba = colormap(norm(visits), bytes=True) return '#{:02x}{:02x}{:02x}'.format(rgba[0], rgba[1], rgba[2]) # 绘制去过的国家填充色 for _, r in visited.iterrows(): sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.001) geo_j = folium.GeoJson(data=sim_geo.to_json(), style_function=lambda x: {'fillColor': color(r['Visits'])}) folium.Popup(r['name']).add_to(geo_j) geo_j.add_to(m) # 显示地图 m
问题排查与修复方案
1. Lambda函数变量捕获陷阱
循环中使用lambda时,会捕获循环变量r的最终值,导致所有去过的国家都使用最后一个国家的访问次数对应的颜色。修复方法是在lambda中添加默认参数绑定当前循环的r['Visits']:
# 修改绘制填充色的循环代码 for _, r in visited.iterrows(): sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.001) # 用默认参数绑定当前的访问次数 geo_j = folium.GeoJson( data=sim_geo.to_json(), style_function=lambda x, visits=r['Visits']: {'fillColor': color(visits)} ) folium.Popup(f"{r['name']} - 访问{r['Visits']}次").add_to(geo_j) geo_j.add_to(m)
2. 访问次数超出颜色映射范围的处理
如果访问次数大于4,当前代码会得到超出colormap的颜色值,导致颜色异常。可以在color函数中添加范围限制:
def color(visits): colormap = cm.get_cmap('YlOrRd') norm = colors.Normalize(vmin=1, vmax=4) # 将访问次数限制在1-4之间,超过4次的用最深色 clamped_visits = max(1, min(visits, 4)) rgba = colormap(norm(clamped_visits), bytes=True) return '#{:02x}{:02x}{:02x}'.format(rgba[0], rgba[1], rgba[2])
3. 国家名称匹配问题
naturalearth_lowres中的国家名称是首字母大写的格式(如"China"),如果你的Excel中是小写(如"china"),会导致merge时匹配失败。统一大小写即可解决:
# 统一世界地图和Excel中的国家名称为小写 world['name'] = world['name'].str.lower() df['Country'] = df['Country'].str.lower() # 重新合并数据 visited = world.merge(df, left_on='name', right_on='Country')
4. 代码效率优化
无需循环遍历每个国家,可以用folium的GeoJson批量处理,提升效率:
# 绘制所有国家的边界和默认填充 folium.GeoJson( world, style_function=lambda x: {'color': 'black', 'fillColor': '#f0f0f0'}, tooltip=folium.GeoJsonTooltip(fields=['name'], aliases=['国家']) ).add_to(m) # 批量绘制去过的国家的填充色 folium.GeoJson( visited, style_function=lambda x: { 'fillColor': color(x['properties']['Visits']), 'color': 'black', 'weight': 1 }, tooltip=folium.GeoJsonTooltip(fields=['name', 'Visits'], aliases=['国家', '访问次数']) ).add_to(m)
内容的提问来源于stack exchange,提问作者ryan123
相关产品推荐
相关产品推荐

