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

如何在Plotly Python的Scatter Mapbox上绘制指定半径的圆形

解决方案

要在你的Scatter Mapbox上绘制以center_point为中心、半径5公里的黑色圆形,可以通过以下步骤实现:

1. 添加生成圆形经纬度点的函数

首先新增一个基于球面三角学的函数,根据中心点经纬度和半径(公里),计算出构成平滑圆形的一系列经纬度坐标:

def get_circle_coords(lat, lon, radius_km):
    # 地球平均半径(公里)
    earth_radius = 6371
    # 将半径转换为弧度单位
    radius_rad = radius_km / earth_radius
    
    coords = []
    # 生成36个点(间隔10度,保证圆形平滑)
    for angle in range(0, 360, 10):
        angle_rad = radians(angle)
        # 计算新纬度
        new_lat = asin(sin(radians(lat)) * cos(radius_rad) + cos(radians(lat)) * sin(radius_rad) * cos(angle_rad))
        # 计算新经度
        new_lon = radians(lon) + atan2(sin(angle_rad) * sin(radius_rad) * cos(radians(lat)), cos(radius_rad) - sin(radians(lat)) * sin(new_lat))
        # 转换回度数格式并存储
        coords.append((degrees(new_lon), degrees(new_lat)))
    # 添加第一个点到末尾,闭合圆形
    coords.append(coords[0])
    return zip(*coords)

注意:需要在顶部导入额外的数学函数,补充代码:

from math import radians, cos, sin, asin, sqrt, atan2, degrees

2. 生成圆形并添加到现有图表

在现有代码逻辑后,生成圆形坐标并通过go.Scattermapbox将圆形轨迹添加到图中:

# 获取圆形的经度、纬度列表
circle_lons, circle_lats = get_circle_coords(lat1, lon1, 5)

# 创建圆形轨迹
circle_trace = go.Scattermapbox(
    lon=list(circle_lons),
    lat=list(circle_lats),
    mode='lines',
    line=dict(color='black', width=2),
    hoverinfo='skip'  # 关闭圆形的悬浮提示,避免干扰数据点
)

# 将圆形轨迹添加到已有的地图图表中
fig_map3.add_trace(circle_trace)

完整修改后的代码

整合所有逻辑后的完整代码如下:

import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
from math import radians, cos, sin, asin, sqrt, atan2, degrees

def haversine(lon1, lat1, lon2, lat2):
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    r = 6371
    return c * r

def get_circle_coords(lat, lon, radius_km):
    earth_radius = 6371
    radius_rad = radius_km / earth_radius
    coords = []
    for angle in range(0, 360, 10):
        angle_rad = radians(angle)
        new_lat = asin(sin(radians(lat)) * cos(radius_rad) + cos(radians(lat)) * sin(radius_rad) * cos(angle_rad))
        new_lon = radians(lon) + atan2(sin(angle_rad) * sin(radius_rad) * cos(radians(lat)), cos(radius_rad) - sin(radians(lat)) * sin(new_lat))
        coords.append((degrees(new_lon), degrees(new_lat)))
    coords.append(coords[0])
    return zip(*coords)

# 替换为你的实际中心坐标输入
long_input = 116.397428
lat_input = 39.90923
# 替换为你的原始数据框
df_latlong = pd.read_csv("your_data.csv")

center_point = pd.DataFrame({'Longitude':[long_input], 'Latitude':[lat_input]})

lat1 = center_point['Latitude'][0]
lon1 = center_point['Longitude'][0]

df_nearest = []
for index, row in df_latlong.iterrows():
    lat2 = row['Latitude']
    lon2 = row['Longitude']
    a = haversine(lon1, lat1, lon2, lat2)
    df_nearest.append(a)

df_latlong['Distance'] = df_nearest
df_radius = df_latlong[df_latlong['Distance'] <= 5] #5公里半径筛选

fig_map3 = px.scatter_mapbox(df_radius, lon='Longitude', lat='Latitude',
                             hover_name='#WELL', zoom=9, width=300, height=500)

# 添加圆形轨迹
circle_lons, circle_lats = get_circle_coords(lat1, lon1, 5)
circle_trace = go.Scattermapbox(
    lon=list(circle_lons),
    lat=list(circle_lats),
    mode='lines',
    line=dict(color='black', width=2),
    hoverinfo='skip'
)
fig_map3.add_trace(circle_trace)

fig_map3.update_layout(mapbox_style='open-street-map', margin={'r':0, 't':0, 'l':0, 'b':0})

fig_map3.show()

关键说明

  • 球面坐标计算:避免了直接偏移经纬度导致的圆形变形,保证在地图上的圆形符合实际公里半径。
  • 样式控制:通过line参数设置黑色线条和宽度,hoverinfo='skip'避免圆形干扰数据点的悬浮交互。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:15:34