如何在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
相关产品推荐
相关产品推荐

