Python实现聚类大小随数据点数量变化并标注聚类数量
解决方案:手动聚类后实现按需可视化
你的问题核心在于:Plotly的自动聚合(cluster=dict(enabled=True))只是视觉上合并点,但size参数绑定的是原始单个数据点的字段值,而非聚类内的总点数。要实现「聚类大小随内部点数变化+标注点数」的需求,必须先手动完成聚类计算,再基于聚类结果绘图。以下提供两种适配学术论文场景的方案:
方案一:静态学术图(Matplotlib + Cartopy + Scikit-learn)
适合需要无交互、可直接插入论文的静态地图,Cartopy是地理绘图的专业工具,Scikit-learn负责聚类计算。
代码示例
import pandas as pd import matplotlib.pyplot as plt import cartopy.crs as ccrs from sklearn.cluster import DBSCAN import numpy as np # 1. 加载数据 df = pd.read_csv( "https://raw.githubusercontent.com/plotly/datasets/master/2011_february_us_airport_traffic.csv" ) coords = df[['lat', 'long']].values # 2. 地理点聚类(DBSCAN,适合密度聚类,适配WGS84经纬度) coords_rad = np.radians(coords) # eps=0.01 对应约1110米的聚类半径(可根据需求调整),min_samples=2表示至少2个点成簇 db = DBSCAN(eps=0.01, min_samples=2, metric='haversine').fit(coords_rad) df['cluster_label'] = db.labels_ # 3. 计算每个聚类的统计量:中心经纬度、点数 cluster_stats = df.groupby('cluster_label').agg( lat_center=('lat', 'mean'), lon_center=('long', 'mean'), point_count=('lat', 'count') ).reset_index() # 过滤噪声点(label=-1) cluster_stats = cluster_stats[cluster_stats['cluster_label'] != -1] # 4. 绘制静态地图 plt.figure(figsize=(12, 8)) # 用PlateCarree投影适配WGS84坐标系 ax = plt.axes(projection=ccrs.PlateCarree()) ax.coastlines() ax.stock_img() # 添加基础地图底图 # 绘制聚类:大小与点数正相关(这里乘以50是缩放系数,可调整) scatter = ax.scatter( cluster_stats['lon_center'], cluster_stats['lat_center'], s=cluster_stats['point_count'] * 50, c='red', alpha=0.7, transform=ccrs.PlateCarree() ) # 标注聚类点数 for idx, row in cluster_stats.iterrows(): ax.text( row['lon_center'], row['lat_center'], str(row['point_count']), fontsize=10, ha='center', va='center', transform=ccrs.PlateCarree() ) plt.title('Airport Traffic Clusters (Point Count-Sized)', fontsize=14) plt.tight_layout() plt.savefig('cluster_map.png', dpi=300, bbox_inches='tight') # 导出高清图用于论文 plt.show()
关键说明
- 用DBSCAN密度聚类:适合地理数据,能自动识别不同密度的簇,无需预设簇数量;若需固定簇数,可替换为
KMeans - 聚类大小通过
s=cluster_stats['point_count'] * 缩放系数直接绑定点数,完全可控 - 导出的PNG/SVG可直接用于学术论文,无交互依赖
方案二:Plotly静态导出方案(先聚类再绘图)
若偏好Plotly的视觉风格,可先手动聚类,再绘制聚类中心,最后导出为静态图。
代码示例
import plotly.express as px import pandas as pd from sklearn.cluster import DBSCAN import numpy as np px.set_mapbox_access_token(open(".mapbox_token").read()) df = pd.read_csv( "https://raw.githubusercontent.com/plotly/datasets/master/2011_february_us_airport_traffic.csv" ) # 1. 同方案一:完成聚类计算 coords = df[['lat', 'long']].values coords_rad = np.radians(coords) db = DBSCAN(eps=0.01, min_samples=2, metric='haversine').fit(coords_rad) df['cluster_label'] = db.labels_ cluster_stats = df.groupby('cluster_label').agg( lat_center=('lat', 'mean'), lon_center=('long', 'mean'), point_count=('lat', 'count') ).reset_index() cluster_stats = cluster_stats[cluster_stats['cluster_label'] != -1] # 2. 绘制聚类中心,size绑定点数,text标注点数 fig = px.scatter_mapbox( cluster_stats, lat="lat_center", lon="lon_center", size="point_count", text="point_count", zoom=3, size_max=100, # 限制最大点大小,避免过度放大 color_discrete_sequence=["red"] ) fig.update_traces(textposition='middle center') fig.update_layout(mapbox_style='carto-positron') # 学术风格的简洁底图 # 导出为静态PNG/SVG用于论文(需提前安装kaleido:pip install kaleido) fig.write_image('plotly_cluster_map.png', scale=3) fig.show()
关键说明
- 放弃Plotly的自动聚类功能,改用手动聚类结果,确保
size参数绑定的是聚类总点数 - 用
write_image导出高清静态图,满足学术论文需求
内容的提问来源于stack exchange,提问作者César Leblanc
相关产品推荐
相关产品推荐

