如何在Python中绘制椭圆散点图的边界线/最优拟合外框线
如何给大规模散点图绘制包围边界线?
问题背景
我用这段代码从文本文件读取了5个参数:
H, OD, c, b, orc = np.genfromtxt('textfile.txt', unpack = True)
然后用简单的散点绘图代码两两组合这些参数,比如:
plt.plot(H[i], c[i], 'bo')
最终得到了10幅散点图,每幅图有30万个点,图形是实心圆、椭圆或者闭合的实心形状。现在想知道怎么给这些图形加上包围的边界线或者拟合外框线?
实用解决方案
根据你的图形特征,这里有几个靠谱的方法,都能适配30万点的大规模数据集:
1. 凸包(Convex Hull)—— 快速搞定凸形边界
如果你的散点是凸形分布(比如圆、椭圆),凸包是最直接的选择,它能生成包裹所有点的最小凸多边形边界,计算速度快,完全hold住30万点。
代码示例:
import numpy as np import matplotlib.pyplot as plt from scipy.spatial import ConvexHull # 替换成你要处理的参数对,比如H和c x, y = H, c points = np.column_stack((x, y)) # 计算凸包 hull = ConvexHull(points) # 绘制散点(s=1适合大量点,避免重叠) plt.scatter(x, y, c='blue', s=1) # 绘制凸包的闭合边界线 plt.plot(points[hull.vertices, 0], points[hull.vertices, 1], 'k--', linewidth=2) plt.show()
注意:如果你的图形是凹形的,凸包会把凹进去的部分也包裹住,这种情况就需要用下面的方法。
2. DBSCAN聚类+凸包—— 适配凹形/带噪声的图形
如果你的散点是密集的闭合凹形,或者有少量噪声点,可以先用DBSCAN把核心的密集点聚类出来,再对核心点计算凸包,这样就能得到更贴合的边界。
代码示例:
import numpy as np import matplotlib.pyplot as plt from scipy.spatial import ConvexHull from sklearn.cluster import DBSCAN x, y = H, c points = np.column_stack((x, y)) # DBSCAN聚类:eps是邻域半径,min_samples是邻域内最少点数,需要根据你的数据调整 db = DBSCAN(eps=0.1, min_samples=10).fit(points) # 标记核心点(密集区域的点) core_mask = np.zeros_like(db.labels_, dtype=bool) core_mask[db.core_sample_indices_] = True core_points = points[core_mask] # 对核心点计算凸包 hull = ConvexHull(core_points) # 绘图 plt.scatter(x, y, c='blue', s=1) plt.plot(core_points[hull.vertices, 0], core_points[hull.vertices, 1], 'r--', linewidth=2) plt.show()
你可以多调整eps和min_samples的值,直到边界贴合你的图形。
3. 椭圆拟合—— 精准适配椭圆形状
如果你的散点明显是椭圆,直接拟合椭圆会得到最精准的边界线:
代码示例:
import numpy as np import matplotlib.pyplot as plt from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA x, y = H, c points = np.column_stack((x, y)) # 标准化数据,方便PCA分析 scaler = StandardScaler() scaled_points = scaler.fit_transform(points) # 用PCA提取椭圆的主轴和方差 pca = PCA(n_components=2) pca.fit(scaled_points) mean = scaler.inverse_transform(pca.mean_) cov_matrix = pca.get_covariance() # 生成椭圆上的点 theta = np.linspace(0, 2*np.pi, 100) ellipse_points = np.dot(np.array([np.cos(theta), np.sin(theta)]).T, np.linalg.cholesky(cov_matrix).T) ellipse_points = scaler.inverse_transform(ellipse_points) + mean # 绘图 plt.scatter(x, y, c='blue', s=1) plt.plot(ellipse_points[:,0], ellipse_points[:,1], 'g-', linewidth=2) plt.show()
这个方法会生成完美的椭圆边界,非常适合椭圆类的散点分布。
内容的提问来源于stack exchange,提问作者Ehsan
相关产品推荐
相关产品推荐

