You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于访问次数实现地图国家颜色渐变的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 00:35:01