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

如何用Python Plotly绘制平滑无断裂的渐变颜色跨国贸易路线?

解决Plotly绘制渐变贸易路线时的断裂问题

你的问题根源在于直接对经纬度做线性插值:地球是球面,平面坐标系下的线性插值路径,在地图投影(比如你用的equirectangular)里会呈现出断裂的折线,跨半球的长距离路线(比如巴西到中国)这个问题尤其突出。要实现平滑的渐变贸易路线,得先计算球面大圆航线的插值点,再基于这些点来做颜色渐变分段。

解决方案步骤

  1. 替换原来的线性插值函数,改用大圆航线插值:把经纬度转成弧度,计算球面上的最短路径点,再转回度数,这样得到的路线在地图上是平滑的曲线。
  2. 基于大圆插值点,分段设置从红到蓝的渐变颜色,保持原来的线宽逻辑。

修改后的完整代码

import numpy as np
import plotly.graph_objects as go
import matplotlib.colors as mcolors
import pandas as pd

# 计算大圆航线的插值点(球面最短路径)
def interpolate_great_circle(lon1, lat1, lon2, lat2, num_points=10):
    # 转成弧度
    lon1_rad = np.radians(lon1)
    lat1_rad = np.radians(lat1)
    lon2_rad = np.radians(lon2)
    lat2_rad = np.radians(lat2)
    
    # 计算大圆航线的中间点
    delta_lon = lon2_rad - lon1_rad
    a = np.sin((lat2_rad - lat1_rad)/2)**2 + np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(delta_lon/2)**2
    c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a))
    
    # 生成插值比例
    fractions = np.linspace(0, 1, num_points)
    lons_rad = []
    lats_rad = []
    
    for f in fractions:
        A = np.sin((1-f)*c) / np.sin(c)
        B = np.sin(f*c) / np.sin(c)
        x = A * np.cos(lat1_rad) * np.cos(lon1_rad) + B * np.cos(lat2_rad) * np.cos(lon2_rad)
        y = A * np.cos(lat1_rad) * np.sin(lon1_rad) + B * np.cos(lat2_rad) * np.sin(lon2_rad)
        z = A * np.sin(lat1_rad) + B * np.sin(lat2_rad)
        
        lat_rad = np.arctan2(z, np.sqrt(x**2 + y**2))
        lon_rad = np.arctan2(y, x)
        
        lons_rad.append(lon_rad)
        lats_rad.append(lat_rad)
    
    # 转回度数
    lons = np.degrees(lons_rad)
    lats = np.degrees(lats_rad)
    return lons, lats

# 测试用数据
Def_trade_Kastner = pd.DataFrame({
    'Producer country': ['Brazil', 'Indonesia'],
    'Consumer country': ['China', 'United States'],
    'Relative Emissions': [10, 2.047066],
    'start_lat': [-10.333333, -2.483383],
    'start_lon': [-53.200000, 117.890285],
    'end_lat': [35.000074, 39.78373],
    'end_lon': [104.999927, -100.445882]
})

# 创建图表
fig = go.Figure()

num_segments = 5  # 渐变分段数
colors = [mcolors.to_hex(c) for c in np.linspace(mcolors.to_rgba('red'), mcolors.to_rgba('blue'), num_segments)]

for i in range(len(Def_trade_Kastner)):
    lon1, lat1 = Def_trade_Kastner['start_lon'][i], Def_trade_Kastner['start_lat'][i]
    lon2, lat2 = Def_trade_Kastner['end_lon'][i], Def_trade_Kastner['end_lat'][i]
    # 用大圆插值替换线性插值
    lons, lats = interpolate_great_circle(lon1, lat1, lon2, lat2, num_points=num_segments)
    
    for j in range(num_segments - 1):
        fig.add_trace(
            go.Scattergeo(
                lon=[lons[j], lons[j + 1]],
                lat=[lats[j], lats[j + 1]],
                mode='lines',
                line=dict(width=Def_trade_Kastner['Relative Emissions'][i],
                          color=colors[j]),
                showlegend=False
            )
        )

fig.update_layout(
    title_text='Deforestation',
    showlegend=False,
    geo=dict(
        visible=False,
        showcountries=True,
        projection_type='equirectangular',
        landcolor='rgb(243, 243, 243)',
        countrycolor='rgb(204, 204, 204)',
    ),
    autosize=False,
    width=1200,
    height=700,
)

fig.show()

关键说明

  • interpolate_great_circle函数:通过球面三角学计算大圆航线的中间点,确保路线符合地球球面的最短路径,在地图上显示为平滑曲线。
  • 渐变逻辑保持不变:把大圆路径分成num_segments段,每段对应从红到蓝的一个颜色值,实现起点到终点的渐变效果。
  • 线宽依然使用Relative Emissions字段,保持原有的数据映射逻辑。

内容的提问来源于stack exchange,提问作者Ep1c1aN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:54:52