Holoviews+Bokeh标准差椭圆方向设置问题求助
解决Holoviews椭圆方向不匹配的问题
你的代码存在几个关键错误,导致椭圆方向无法和散点数据的分布对齐,下面逐一修正并说明:
1. 角度计算逻辑错误
你当前的角度计算代码np.arctan2(eigenvectors[1, order], eigenvectors[1, order])完全无效——这相当于计算arctan2(a,a),结果永远是π/4,根本没用到特征向量的x分量。正确的做法是取对应特征向量的y分量和x分量来计算与水平方向的夹角:
angle = np.arctan2(eigenvectors[1, order], eigenvectors[0, order])
2. 特征向量排序与宽高对应错误
你当前取的是最小特征值对应的特征向量,但椭圆的长轴应该对应最大特征值的方向,同时Holoviews的Ellipse参数是直径,需要用特征值的平方根(即对应轴的标准差)乘以2:
# 按特征值从大到小排序,取最大特征值的索引 order = eigenvalues.argsort()[::-1][0] # 宽高对应长轴和短轴的直径 w = nstd * np.sqrt(eigenvalues[order]) * 2 h = nstd * np.sqrt(eigenvalues[eigenvalues.argsort()[::-1][1]]) * 2
3. 坐标变换冗余且错误
你手动做的坐标变换不仅冗余,还没对数据做中心化(减去均值),导致标准差计算偏差。实际上直接用特征值计算宽高即可,无需额外变换。
修正后的完整代码
import numpy as np import holoviews as hv hv.extension('bokeh') def create_plot(x, y, nstd=5): x, y = np.asarray(x), np.asarray(y) cov_matrix = np.cov([x, y]) eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # 取最大特征值对应的特征向量(长轴方向) order = eigenvalues.argsort()[::-1][0] # 计算特征向量与水平方向的逆时针弧度角 angle = np.arctan2(eigenvectors[1, order], eigenvectors[0, order]) x0 = np.mean(x) y0 = np.mean(y) # 用特征值计算椭圆宽高(Holoviews要求传入直径,故乘以2) w = nstd * np.sqrt(eigenvalues[order]) * 2 h = nstd * np.sqrt(eigenvalues[eigenvalues.argsort()[::-1][1]]) * 2 # 直接传入计算出的角度即可,无需取负 return hv.Ellipse(x0, y0, (w, h), orientation=angle) * hv.Scatter((x, y)) c2x = np.random.normal(loc=-2, scale=0.6, size=200) c2y = np.random.normal(loc=-2, scale=0.1, size=200) combined = create_plot(c2x, c2y) combined.opts(shared_axes=False, hv.Ellipse(fill_alpha=0.2, color='red'), hv.Scatter(size=5))
核心说明
- Holoviews的
orientation参数定义是宽度对应的轴与水平方向的逆时针弧度角,和特征向量计算出的角度完全匹配,不需要取负。 - 特征值的平方根就是对应轴方向的标准差,直接用它计算椭圆宽高比手动坐标变换更准确高效。
- 椭圆的宽高参数是直径,因此需要将标准差乘以2(标准差是中心到边缘的距离,直径为该值的两倍)。
内容的提问来源于stack exchange,提问作者F_B
相关产品推荐
相关产品推荐

