如何用Geopandas和Matplotlib为地图添加带渐变色的贸易流箭头?
解决地图贸易流箭头展示的技术方案
一、在国家图层上添加双向箭头
Geopandas本身不直接支持箭头绘制,通常结合Matplotlib的patches模块实现。核心思路是先获取国家中心坐标,再在中心附近绘制双向箭头(可通过两个反向箭头或双向样式模拟)。
步骤1:加载地理与贸易数据
import geopandas as gpd import matplotlib.pyplot as plt from matplotlib.patches import FancyArrowPatch from matplotlib.colors import Normalize from matplotlib.cm import ScalarMappable # 加载世界国家地理数据(使用Geopandas自带数据集) world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) # 模拟贸易数据:键为国家名,值为(贸易额, 贸易伙伴) trade_data = { 'China': (1500, 'US'), 'US': (1500, 'China'), 'Germany': (800, 'France'), 'France': (800, 'Germany') }
步骤2:基于国家中心绘制箭头
fig, ax = plt.subplots(figsize=(12, 8)) # 绘制基础国家图层 world.plot(ax=ax, color='lightgray', edgecolor='white') # 箭头参数配置 arrow_length = 0.5 # 箭头长度(地理坐标单位) arrow_size = 20 # 箭头头部大小 for country_name, (value, partner) in trade_data.items(): country = world[world.name == country_name] if not country.empty: # 获取国家几何中心坐标 centroid = country.geometry.centroid.iloc[0] x, y = centroid.x, centroid.y # 绘制双向箭头(用<->样式直接生成双向箭头) arrow = FancyArrowPatch((x - arrow_length, y), (x + arrow_length, y), arrowstyle='<->', mutation_scale=arrow_size, linewidth=2) ax.add_patch(arrow)
提示:若需根据贸易伙伴位置调整箭头方向,可通过伙伴国家的中心坐标计算角度,用
math.atan2获取方位后修改箭头的起点/终点坐标。
二、为箭头添加渐变色并生成数值图例
通过将贸易值映射到颜色映射表(colormap),实现箭头颜色随数值渐变,再生成对应图例。
步骤1:建立数值-颜色映射关系
# 提取所有贸易值,创建归一化器(将值映射到0-1区间) trade_values = [v for v, _ in trade_data.values()] norm = Normalize(vmin=min(trade_values), vmax=max(trade_values)) # 选择颜色映射(比如'viridis',可替换为'coolwarm'等) cmap = plt.get_cmap('viridis')
步骤2:绘制带渐变色的箭头
修改箭头绘制逻辑,加入颜色映射:
fig, ax = plt.subplots(figsize=(12, 8)) world.plot(ax=ax, color='lightgray', edgecolor='white') for country_name, (value, partner) in trade_data.items(): country = world[world.name == country_name] if not country.empty: centroid = country.geometry.centroid.iloc[0] x, y = centroid.x, centroid.y # 根据贸易值获取对应颜色 arrow_color = cmap(norm(value)) arrow = FancyArrowPatch((x - arrow_length, y), (x + arrow_length, y), arrowstyle='<->', mutation_scale=arrow_size, linewidth=2, facecolor=arrow_color, edgecolor=arrow_color) ax.add_patch(arrow)
步骤3:生成数值对应图例
# 创建颜色映射辅助对象,用于生成颜色条 sm = ScalarMappable(norm=norm, cmap=cmap) sm.set_array([]) # 无需绑定数据,仅需颜色映射规则 # 添加垂直颜色条图例 cbar = plt.colorbar(sm, ax=ax, orientation='vertical', pad=0.02) cbar.set_label('Trade Value (USD billion)') plt.title('Country-to-Country Trade Flow') plt.show()
进阶:结合Cartopy实现精准投影
如果需要更专业的地理投影支持,可搭配Cartopy:
import cartopy.crs as ccrs fig, ax = plt.subplots(figsize=(12, 8), subplot_kw={'projection': ccrs.PlateCarree()}) # 绘制带投影的国家图层 world.plot(ax=ax, transform=ccrs.PlateCarree(), color='lightgray', edgecolor='white') ax.coastlines() # 箭头绘制逻辑(需指定投影转换) for country_name, (value, partner) in trade_data.items(): country = world[world.name == country_name] if not country.empty: centroid = country.geometry.centroid.iloc[0] x, y = centroid.x, centroid.y arrow_color = cmap(norm(value)) arrow = FancyArrowPatch((x - arrow_length, y), (x + arrow_length, y), arrowstyle='<->', mutation_scale=arrow_size, linewidth=2, facecolor=arrow_color, edgecolor=arrow_color, transform=ccrs.PlateCarree()) ax.add_patch(arrow) # 添加颜色条 sm = ScalarMappable(norm=norm, cmap=cmap) sm.set_array([]) cbar = plt.colorbar(sm, ax=ax, orientation='vertical', pad=0.02) cbar.set_label('Trade Value (USD billion)') plt.title('Country-to-Country Trade Flow') plt.show()
内容的提问来源于stack exchange,提问作者hbstha123
相关产品推荐
相关产品推荐

