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

Plotly Python如何给go.Scattermapbox添加ff.create_quiver风矢轨迹并正常显示

问题原因
  • 核心问题是ff.create_quiver生成的是普通笛卡尔坐标系的轨迹,不属于Plotly的*mapbox系列轨迹,无法匹配Mapbox的经纬度坐标系,也不会渲染在地图视图层上方,所以要么位置完全偏离可视区域,要么被地图层完全覆盖。
  • 其次你的矢量网格坐标是0-2的数值,没有和实际经纬度范围做映射,就算坐标系兼容也无法对应到地图的正确位置。
解决方案
  1. 先将你的矢量网格坐标映射到实际数据集的经纬度范围,同时将风分量u、v换算为经纬度的偏移量(注意1度纬度对应约111km,1度经度对应约111*cos(纬度)km,保证矢量方向比例正确)
  2. 手动构造每个风箭头的路径,使用go.Scattermapbox类型的轨迹绘制,确保可以渲染在地图上方。
  3. 调整轨迹层级,后添加的风矢量轨迹默认会在最早添加的散点轨迹上方,也可以通过layer参数指定显示层级。

修改后的代码示例:

import plotly.graph_objects as go
import numpy as np
import pandas as pd

# 假设你的df已存在,先计算经纬度范围
lon_min, lon_max = df['lon'].min(), df['lon'].max()
lat_min, lat_max = df['lat'].min(), df['lat'].max()

# 生成网格并映射到经纬度范围
x_grid, y_grid = np.meshgrid(np.arange(0,2,.2), np.arange(0,2,.2))
# 映射x到经度,y到纬度
lon_grid = lon_min + (x_grid / 2) * (lon_max - lon_min)
lat_grid = lat_min + (y_grid / 2) * (lat_max - lat_min)

# 计算风分量
u = np.cos(x_grid) * y_grid
v = np.sin(x_grid) * y_grid

# 风矢量缩放系数,可根据实际显示效果调整
scale = 0.1 
# 存储所有箭头的坐标,None用于分隔不同箭头的路径
arrow_lons = []
arrow_lats = []

for i in range(lon_grid.shape[0]):
    for j in range(lon_grid.shape[1]):
        # 起点经纬度
        start_lon = lon_grid[i,j]
        start_lat = lat_grid[i,j]
        # 终点经纬度,换算经度偏移时乘以cos(纬度)保证比例正确
        end_lon = start_lon + u[i,j] * scale / np.cos(np.radians(start_lat))
        end_lat = start_lat + v[i,j] * scale
        
        # 添加箭身路径
        arrow_lons.extend([start_lon, end_lon, None])
        arrow_lats.extend([start_lat, end_lat, None])
        
        # 可选:添加箭头尖,可根据需要调整角度和长度
        arrow_size = 0.02
        angle = np.arctan2(v[i,j], u[i,j])
        # 箭头左侧
        left_lon = end_lon - arrow_size * np.cos(angle + np.pi/6) / np.cos(np.radians(end_lat))
        left_lat = end_lat - arrow_size * np.sin(angle + np.pi/6)
        # 箭头右侧
        right_lon = end_lon - arrow_size * np.cos(angle - np.pi/6) / np.cos(np.radians(end_lat))
        right_lat = end_lat - arrow_size * np.sin(angle - np.pi/6)
        arrow_lons.extend([end_lon, left_lon, end_lon, right_lon, None])
        arrow_lats.extend([end_lat, left_lat, end_lat, right_lat, None])

fig = go.Figure()

# 先添加原始散点
fig.add_trace(go.Scattermapbox(
    mode = "markers",
    lon = df['lon'],
    lat = df['lat'],
    marker = {'size': 5, 'color':'black'},
))

# 再添加风矢量箭头,后添加的轨迹层级更高
fig.add_trace(go.Scattermapbox(
    mode = "lines",
    lon = arrow_lons,
    lat = arrow_lats,
    line = {'width': 1, 'color': 'red'},
    hoverinfo = 'skip'
))

fig.update_layout(
    margin={"l": 0, "r": 0, "t": 15, "b": 0},
    mapbox={
        "style": "carto-positron",
        "zoom": 5,
        "center": {
            "lon": df['lon'].mean(),
            "lat": df['lat'].mean(),
        },
    },
)
fig.show()

可根据实际显示效果调整scale(风矢量长度)和arrow_size(箭头大小)参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:54:05