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

如何在Plotly正射投影图上叠加绘制形状?

在Plotly正射投影地球图上绘制Az-El基准覆盖形状的解决方案

核心思路:坐标转换+形状叠加

要实现需求,关键是完成两次坐标转换,再将生成的形状顶点叠加到目标scattergeo点的3D坐标上,最终用fig.add_mesh3d绘制。

1. 地理坐标转3D笛卡尔坐标

先把scattergeo点的经纬度转成地球表面的(x,y,z),作为形状的中心点:

import numpy as np

def latlon_to_xyz(lat, lon, R=1):
    # R取Plotly geo场景的等效半径,默认用1即可适配正射投影
    lat_rad = np.radians(lat)
    lon_rad = np.radians(lon)
    x = R * np.cos(lat_rad) * np.cos(lon_rad)
    y = R * np.cos(lat_rad) * np.sin(lon_rad)
    z = R * np.sin(lat_rad)
    return x, y, z

2. Az-El坐标转局部3D形状顶点

以圆锥为例,根据方位角、仰角、圆锥半角、高度生成局部坐标的顶点,再转换到全局坐标:

def azel_to_cone_points(az, el, cone_half_angle, height, num_points=50):
    # 转换为弧度
    az_rad = np.radians(az)
    el_rad = np.radians(el)
    # 圆锥指向的单位向量
    dir_x = np.cos(el_rad) * np.sin(az_rad)
    dir_y = np.cos(el_rad) * np.cos(az_rad)
    dir_z = np.sin(el_rad)
    
    # 生成圆锥底面的圆周点
    theta = np.linspace(0, 2*np.pi, num_points)
    base_radius = height * np.tan(np.radians(cone_half_angle))
    
    # 计算局部坐标:底面点围绕指向向量旋转
    local_x = dir_x * height + base_radius * (np.cos(theta)*np.cos(el_rad)*np.cos(az_rad) - np.sin(theta)*np.sin(az_rad))
    local_y = dir_y * height + base_radius * (np.cos(theta)*np.cos(el_rad)*np.sin(az_rad) + np.sin(theta)*np.cos(az_rad))
    local_z = dir_z * height + base_radius * np.cos(theta)*np.sin(el_rad)
    
    # 加入圆锥顶点(局部原点)
    return np.vstack([[0,0,0], np.column_stack([local_x, local_y, local_z])])

3. 将形状居中到scattergeo点

拿到目标点的(x0,y0,z0)后,把局部顶点加上这个偏移量,再用add_mesh3d绘制:

# 假设你有一个scattergeo点的经纬度:target_lat, target_lon
x0, y0, z0 = latlon_to_xyz(target_lat, target_lon)

# 定义圆锥参数:方位角30°,仰角45°,半角20°,高度0.2(相对于地球半径)
cone_local_points = azel_to_cone_points(az=30, el=45, cone_half_angle=20, height=0.2)

# 转换为全局3D坐标
global_x = x0 + cone_local_points[:,0]
global_y = y0 + cone_local_points[:,1]
global_z = z0 + cone_local_points[:,2]

# 添加到已有图表
fig.add_mesh3d(
    x=global_x, y=global_y, z=global_z,
    opacity=0.3, color='rgba(255, 0, 0, 0.5)',
    showscale=False
)

4. 半球绘制的类似逻辑

如果要画半球,只需生成以Az-El方向为中心轴的半球表面点,再做坐标旋转和全局偏移:

def azel_hemisphere_points(az, el, radius, num_points=100):
    az_rad = np.radians(az)
    el_rad = np.radians(el)
    
    # 生成半球的球面坐标(只取仰角>=el_rad的部分)
    theta = np.linspace(el_rad, np.pi/2, num_points//2)
    phi = np.linspace(0, 2*np.pi, num_points)
    theta, phi = np.meshgrid(theta, phi)
    
    # 局部坐标(默认z轴向上)
    local_x = radius * np.sin(theta) * np.cos(phi)
    local_y = radius * np.sin(theta) * np.sin(phi)
    local_z = radius * np.cos(theta)
    
    # 旋转矩阵:把局部z轴转到Az-El方向
    rot_x = np.array([[1,0,0],
                      [0,np.cos(-el_rad), -np.sin(-el_rad)],
                      [0,np.sin(-el_rad), np.cos(-el_rad)]])
    rot_z = np.array([[np.cos(az_rad), -np.sin(az_rad), 0],
                      [np.sin(az_rad), np.cos(az_rad), 0],
                      [0,0,1]])
    rot_matrix = rot_z @ rot_x
    
    # 应用旋转并返回
    local_points = np.column_stack([local_x.flatten(), local_y.flatten(), local_z.flatten()])
    return local_points @ rot_matrix.T

参考文档建议

  • 直接查Plotly官方的mesh3dAPI文档:重点关注顶点输入、三角面定义(i/j/k参数)和透明度、颜色等视觉配置
  • 了解Plotly正射投影的坐标系统:确保地球半径的缩放值和你转换时用的R参数匹配,避免形状偏移

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:55:30