如何使用Plotly绘制贴合倾斜/旋转线条轴线的椭球
根因分析
你当前的调用代码中固定给ellipse函数传入了旋转角为π/2的轴向向量,没有匹配实际数据线条的倾斜方向,导致生成的椭圆和线条无法贴合。原ellipse函数本身的逻辑是正确的,只需要调整调用时的轴向参数,或者给函数增加自动适配点集轴向的能力即可。
修改方案
步骤1:新增计算点集主轴方向的函数
通过主成分分析(PCA)提取离散点序列的第一主成分方向,作为椭圆长轴的指向:
import numpy as np from sklearn.decomposition import PCA import plotly.graph_objects as go # 原ellipse函数保持不变 def ellipse(x_center=0, y_center=0, ax1 = [1, 0], ax2 = [0,1], a=1, b =1, N=100): if np.linalg.norm(ax1) != 1 or np.linalg.norm(ax2) != 1: raise ValueError('ax1, ax2 must be unit vectors') if abs(np.dot(ax1, ax2)) > 1e-06: raise ValueError('ax1, ax2 must be orthogonal vectors') t = np.linspace(0, 2*np.pi, N) xs = a * np.cos(t) ys = b * np.sin(t) R = np.array([ax1, ax2]).T xp, yp = np.dot(R, [xs, ys]) x = xp + x_center y = yp + y_center return x, y # 新增:计算点集的主轴方向角 def get_axis_angle(points): # points为shape=(n,2)的数组,存储x、y坐标 pca = PCA(n_components=2) pca.fit(points) # 第一主成分的方向向量 main_axis = pca.components_[0] # 计算方向角 theta = np.arctan2(main_axis[1], main_axis[0]) return theta
步骤2:调整调用逻辑,使用点集实际方向角生成椭圆
# 读取数据(你原有的读取逻辑不变) x22 = tw2_df['x'] z22 = tw2_df['z'] x5 = tw5_df['x'] z5 = tw5_df['z'] # 创建画布 fig = go.Figure() # 绘制原始点 fig.add_trace(go.Scatter(x=x22, y=z22, name="line-2", mode="markers", marker_color='gray')) fig.add_trace(go.Scatter(x=x5, y=z5, name="line-3", mode="markers", marker_color='gray')) # 处理well-2椭圆 h2=540.05 k2=-54.75 a2=36.67 b2=577.62 # 计算well2点集的主轴方向角 theta2 = get_axis_angle(np.column_stack((x22, z22))) # 用实际方向角生成轴向向量 ax1_2 = [np.cos(theta2), np.sin(theta2)] ax2_2 = [-np.sin(theta2), np.cos(theta2)] x_e2, y_e2 = ellipse(x_center=h2, y_center=k2, ax1=ax1_2, ax2=ax2_2, a=a2, b=b2) fig.add_scatter(x=x_e2, y=y_e2, mode = 'lines', name='well-2椭圆') # 处理well-5椭圆 h5=550.28 k5=-246.58 a5=43.17 b5=590.69 # 计算well5点集的主轴方向角 theta5 = get_axis_angle(np.column_stack((x5, z5))) ax1_5 = [np.cos(theta5), np.sin(theta5)] ax2_5 = [-np.sin(theta5), np.cos(theta5)] x_e5, y_e5 = ellipse(x_center=h5, y_center=k5, ax1=ax1_5, ax2=ax2_5, a=a5, b=b5) fig.add_scatter(x=x_e5, y=y_e5, mode = 'lines', name='well-5椭圆') fig.update_layout(showlegend=True) fig.show()
补充说明
如果你的数据点本身已经是沿直线分布的,也可以直接用首尾点计算方向角代替PCA,逻辑如下:
def get_axis_angle_by_endpoints(points): dx = points[-1,0] - points[0,0] dy = points[-1,1] - points[0,1] theta = np.arctan2(dy, dx) return theta
内容的提问来源于stack exchange,提问作者Ramy Abdallah
相关产品推荐
相关产品推荐

