python 画scatter_matrix时,y轴坐标标签重叠

博客提出了y轴标签重叠的问题,目前处于待解决状态,聚焦于信息技术领域中可能涉及可视化方面的标签显示问题。

问题:y轴标签重叠

待解决:

我正在编辑【python】代码,遇到了 【raise RuntimeError("Another Axes already grabs mouse input") RuntimeError: Another Axes already grabs mouse input Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits.】 ,请帮我检查并改正错误点。我的原始代码如下: 【# 主函数 def main(): # 创建光滑轨迹 md_smooth, tvd_smooth, north_smooth, east_smooth = create_smooth_trajectory(md, tvd, north, east) # 创建深度转换插值器 md_to_tvd, tvd_to_md = create_depth_interpolators(md_smooth, tvd_smooth) # 计算对应的垂深值 valid_md, multi_arm_tvd = calculate_corresponding_tvd(arm_md, md_to_tvd) arm_md0 = get_3d_coordinates_by_md(valid_md, md_smooth, east_smooth, north_smooth, tvd_smooth) arm1_3d = get_3d_coordinates_by_md(arm_md1, md_smooth, east_smooth, north_smooth, tvd_smooth) arm2_3d = get_3d_coordinates_by_md(arm_md2, md_smooth, east_smooth, north_smooth, tvd_smooth) print('arm_md0', arm_md0) diff_arm = arm1_3d - arm2_3d sq_diff = diff_arm ** 2 sum_sq = np.sum(sq_diff, axis=1) distances = np.sqrt(sum_sq) angle_x = np.divide(diff_arm[:,0], distances) angle_y = np.divide(diff_arm[:,1], distances) angle_z = np.divide(diff_arm[:,2], distances) print('angle', angle_x, '\n', angle_y, '\n',angle_z) # 建立坐标变换矩阵 trans_matrix = np.zeros((len(angle_x), 3, 3)) for i in range(len(angle_x)): trans_matrix[i, 0, 0] = - angle_y[i]/np.sqrt(angle_x[i] ** 2 + angle_y[i] ** 2) trans_matrix[i, 0, 1] = angle_x[i] * angle_z[i]/np.sqrt(angle_x[i] ** 2 + angle_y[i] ** 2) trans_matrix[i, 0, 2] = angle_x[i] trans_matrix[i, 1, 0] = angle_x[i]/np.sqrt(angle_x[i] ** 2 + angle_y[i] ** 2) trans_matrix[i, 1, 1] = (angle_z[i] * angle_y[i])/np.sqrt(angle_x[i] ** 2 + angle_y[i] ** 2) trans_matrix[i, 1, 2] = angle_y[i] trans_matrix[i, 2, 0] = 0 trans_matrix[i, 2, 1] = np.sqrt(angle_x[i] ** 2 + angle_y[i] ** 2) trans_matrix[i, 2, 2] = - angle_z[i] print(trans_matrix) # 各接触点的局部坐标计算 loc_positions_x = np.zeros((len(afilter), 40)) loc_positions_y = np.zeros((len(afilter), 40)) loc_positions_z = np.zeros((len(afilter), 40)) for i in range(len(afilter)): for j in range(40): loc_positions_x[i, j] = afilter[i, j] * np.cos(np.pi/20 * j) loc_positions_y[i, j] = afilter[i, j] * np.sin(np.pi/20 * j) # 组合为三维数组 sum_loc = np.stack((loc_positions_x, loc_positions_y, loc_positions_z), axis=0) print('111', sum_loc.shape) # 获取40臂各臂腿曲线采集点的实际坐标值 arms_positions = np.zeros((len(angle_x), 40, 3, 1)) for i in range(len(afilter)): for j in range(40): ddn = sum_loc[:, i , j].reshape(-1, 1) ddw = trans_matrix[i, :, :] ddm = arm_md0[i, :].reshape(-1, 1) arms_positions[i, j, :, :] = ddw @ ddn + ddm print('arms_positions', arms_positions) # 创建插值函数(根据垂深查询坐标) north_interp = PchipInterpolator(tvd_smooth, north_smooth) east_interp = PchipInterpolator(tvd_smooth, east_smooth) # 创建图形和3D坐标 fig = plt.figure(figsize=(16, 14)) # 使用GridSpec创建更灵活的布局 gs = GridSpec(4, 3, height_ratios=[1, 0.1, 0.05, 0.08], width_ratios=[0.7, 0.15, 0.15]) # 3D主视图 ax_main = fig.add_subplot(gs[0, 0], projection='3d') # 水平剖面图 ax_profile = fig.add_subplot(gs[0, 1:]) ax_profile.set_aspect('equal', adjustable='datalim') # 滑块区域 ax_slider = fig.add_subplot(gs[1, 0]) # 坐标比例控制区域 ax_scale = fig.add_subplot(gs[1, 1:]) ax_scale.axis('off') # 按钮区域 ax_buttons = fig.add_subplot(gs[2, 0]) ax_buttons.axis('off') # 文本信息区域 ax_text = fig.add_subplot(gs[2, 1:]) ax_text.axis('off') # 底部信息区域 ax_bottom = fig.add_subplot(gs[3, :]) ax_bottom.axis('off') # 调整布局 plt.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95, wspace=0.15, hspace=0.25) # 绘制多臂井径图 all_points, ax_main, n_depths = plot_40_arms_smooth(arms_positions, ax_main) # 绘制光滑轨迹 ax_main.plot(north_smooth, east_smooth, tvd_smooth, 'b-', linewidth=3, alpha=0.9, label='Smooth borehole trajectory') # 绘制原始数据点 ax_main.scatter(north, east, tvd, c='r', s=1, label='origin_point') # 收集所有点用于范围计算 all_points = np.vstack(all_points) if all_points else np.array([[0, 0, 0]]) all_north = np.concatenate([all_points[:, 0], north]) all_east = np.concatenate([all_points[:, 1], east]) all_tvd = np.concatenate([all_points[:, 2], tvd]) # 计算范围 max_range = np.array([ all_north.max() - all_north.min(), all_east.max() - all_east.min(), all_tvd.max() - all_tvd.min() ]).max() / 2.0 mid_x = (all_north.max() + all_north.min()) * 0.5 mid_y = (all_east.max() + all_east.min()) * 0.5 mid_z = (all_tvd.max() + all_tvd.min()) * 0.5 # 设置主视图范围 ax_main.set_xlim(mid_x - max_range, mid_x + max_range) ax_main.set_ylim(mid_y - max_range, mid_y + max_range) ax_main.set_zlim(mid_z - max_range, mid_z + max_range) # 保存全局范围用于重置 global_limits = { 'xlim': ax_main.get_xlim(), 'ylim': ax_main.get_ylim(), 'zlim': ax_main.get_zlim() } # 设置坐标标签 ax_main.set_xlabel('North (m)', fontsize=10) ax_main.set_ylabel('East (m)', fontsize=10) ax_main.set_zlabel('Depth (m)', fontsize=10) ax_main.set_title('Combined Caliper & Trajectory Visualization', fontsize=12) ax_main.legend(loc='upper right', fontsize=9) ax_main.grid(True, alpha=0.3) # 设置视角 ax_main.view_init(elev=25, azim=45) # 计算每个深度的椭圆参数 ellipse_params = [] # 获取深度级别 depth_levels = arms_positions[:, 0, 2, 0] # 假设所有臂在相同深度 for depth_idx in range(n_depths): points_at_depth = arms_positions[depth_idx, :, :2, 0] # (n_arms, 2) # 计算中心点 center = np.mean(points_at_depth, axis=0) # 计算点集协方差矩阵 cov_matrix = np.cov(points_at_depth.T) # 计算特征值和特征向量 eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # 计算椭圆参数 angle = np.degrees(np.arctan2(*eigenvectors[:, 0][::-1])) width = 2 * np.sqrt(eigenvalues[0]) height = 2 * np.sqrt(eigenvalues[1]) # 计算椭圆度 (长/短) ellipse_ratio = max(width, height) / min(width, height) if min(width, height) > 0 else 1.0 ellipse_params.append({ 'center': center, 'width': width, 'height': height, 'angle': angle, 'ratio': ellipse_ratio, 'depth': depth_levels[depth_idx], 'points': points_at_depth }) # 按深度排序椭圆参数 ellipse_params.sort(key=lambda x: x['depth']) # 初始垂深值(取中间点) init_depth = np.median(tvd_smooth) # 计算初始坐标 init_east = east_interp(init_depth) init_north = north_interp(init_depth) # 在主视图中绘制初始点 point = ax_main.scatter([init_north], [init_east], [init_depth], c='g', s=100, label='Current Depth') # 添加深度滑块 slider = Slider( ax=ax_slider, label='Depth (m)', valmin=tvd.min(), valmax=tvd.max(), valinit=init_depth, valstep=0.5, facecolor='lightblue' ) # 添加坐标比例输入框 scale_text_props = dict(fontsize=9, ha='right', va='center') input_props = dict(fontsize=9, bbox=dict(facecolor='white', alpha=0.7)) # X范围 ax_scale.text(0.05, 0.75, "X Range (min,max):", **scale_text_props) x_range_box = TextBox(fig.add_axes([0.25, 0.75, 0.2, 0.03]), "", initial=f"{mid_x - max_range:.2f}, {mid_x + max_range:.2f}") # Y范围 ax_scale.text(0.05, 0.5, "Y Range (min,max):", **scale_text_props) y_range_box = TextBox(fig.add_axes([0.25, 0.5, 0.2, 0.03]), "", initial=f"{mid_y - max_range:.2f}, {mid_y + max_range:.2f}") # Z范围 ax_scale.text(0.05, 0.25, "Z Range (min,max):", **scale_text_props) z_range_box = TextBox(fig.add_axes([0.25, 0.25, 0.2, 0.03]), "", initial=f"{mid_z - max_range:.2f}, {mid_z + max_range:.2f}") # 比例应用按钮 apply_ax = plt.axes([0.5, 0.25, 0.1, 0.03]) apply_button = Button(apply_ax, 'Apply Scale', color='lightgreen') apply_button.label.set_fontsize(9) # 比例重置按钮 reset_scale_ax = plt.axes([0.62, 0.25, 0.1, 0.03]) reset_scale_button = Button(reset_scale_ax, 'Reset Scale', color='lightcoral') reset_scale_button.label.set_fontsize(9) # 在按钮区域创建两个小按钮 reset_ax = plt.axes([0.15, 0.04, 0.15, 0.03]) # [左, 下, 宽, 高] rotate_ax = plt.axes([0.35, 0.04, 0.15, 0.03]) # 创建更小的按钮 reset_button = Button(reset_ax, 'Reset View', color='lightgoldenrodyellow') rotate_button = Button(rotate_ax, 'Rotate View', color='lightblue') # 设置按钮字体大小 for button in [reset_button, rotate_button]: button.label.set_fontsize(8) # 添加坐标显示文本 coord_text = ax_text.text( 0.5, 0.5, f'Depth: {init_depth:.2f}m | East: {init_east:.2f}m | North: {init_north:.2f}m', ha='center', va='center', fontsize=10 ) # 添加底部信息 ax_bottom.text(0.5, 0.8, "3D Borehole Visualization with Caliper Data", ha='center', va='center', fontsize=12, weight='bold') ax_bottom.text(0.5, 0.4, "Use sliders and buttons to explore the data | Adjust scales for detailed views", ha='center', va='center', fontsize=9, alpha=0.7) # 绘制初始水平剖面 def plot_depth_profile(depth): # 找到最接近的深度索引 closest_idx = np.argmin(np.abs(depth_levels - depth)) params = ellipse_params[closest_idx] # 清除之前的绘图 ax_profile.clear() # 设置标题和标签 ax_profile.set_title(f'Horizontal Profile at {params["depth"]:.1f}m Depth', fontsize=10) ax_profile.set_xlabel('North (m)', fontsize=9) ax_profile.set_ylabel('East (m)', fontsize=9) ax_profile.grid(True, alpha=0.3) # 绘制所有臂点 ax_profile.scatter(params['points'][:, 0], params['points'][:, 1], c='b', s=30, alpha=0.7, label='Caliper Points') # 绘制中心点 ax_profile.scatter(params['center'][0], params['center'][1], c='r', s=80, marker='x', label='Center') # 绘制拟合椭圆 ellipse = Ellipse( xy=params['center'], width=params['width'], height=params['height'], angle=params['angle'], edgecolor='g', facecolor='none', linewidth=2, alpha=0.8, label=f'Ellipticity: {params["ratio"]:.2f}' ) ax_profile.add_patch(ellipse) # 添加椭圆度信息 ax_profile.text(0.05, 0.95, f'Ellipticity: {params["ratio"]:.2f}\n' f'Major Axis: {max(params["width"], params["height"]):.2f}m\n' f'Minor Axis: {min(params["width"], params["height"]):.2f}m', transform=ax_profile.transAxes, fontsize=9, verticalalignment='top', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5)) # 添加图例 ax_profile.legend(loc='lower right', fontsize=8) # 设置相同的比例 ax_profile.set_aspect('equal', adjustable='datalim') # 设置坐标范围(包含所有点) margin = 0.1 # 10%的边距 x_min, x_max = np.min(params['points'][:, 0]), np.max(params['points'][:, 0]) y_min, y_max = np.min(params['points'][:, 1]), np.max(params['points'][:, 1]) x_range = x_max - x_min y_range = y_max - y_min max_range = max(x_range, y_range) * (1 + margin) / 2 mid_x = (x_min + x_max) / 2 mid_y = (y_min + y_max) / 2 ax_profile.set_xlim(mid_x - max_range, mid_x + max_range) ax_profile.set_ylim(mid_y - max_range, mid_y + max_range) # 初始绘制 plot_depth_profile(init_depth) # 更新函数 def update(val): depth = slider.val # 计算新坐标 new_east = east_interp(depth) new_north = north_interp(depth) # 更新主视图点位置 point._offsets3d = ([new_north], [new_east], [depth]) # 更新水平剖面图 plot_depth_profile(depth) # 更新文本 coord_text.set_text(f'Depth: {depth:.2f}m | East: {new_east:.2f}m | North: {new_north:.2f}m') # 重绘图形 fig.canvas.draw_idle() slider.on_changed(update) # 重置视图函数 def reset_view(event): ax_main.set_xlim(global_limits['xlim'][0], global_limits['xlim'][1]) ax_main.set_ylim(global_limits['ylim'][0], global_limits['ylim'][1]) ax_main.set_zlim(global_limits['zlim'][0], global_limits['zlim'][1]) ax_main.view_init(elev=25, azim=45) # 更新输入框值 x_range_box.set_val(f"{global_limits['xlim'][0]:.2f}, {global_limits['xlim'][1]:.2f}") y_range_box.set_val(f"{global_limits['ylim'][0]:.2f}, {global_limits['ylim'][1]:.2f}") z_range_box.set_val(f"{global_limits['zlim'][0]:.2f}, {global_limits['zlim'][1]:.2f}") fig.canvas.draw_idle() reset_button.on_clicked(reset_view) # 旋转视图函数 def rotate_view(event): current_azim = ax_main.azim ax_main.view_init(elev=5, azim=current_azim + 20) fig.canvas.draw_idle() rotate_button.on_clicked(rotate_view) # 应用比例函数 def apply_scale(event): try: # 解析X范围 x_min, x_max = map(float, x_range_box.text.split(',')) ax_main.set_xlim(x_min, x_max) # 解析Y范围 y_min, y_max = map(float, y_range_box.text.split(',')) ax_main.set_ylim(y_min, y_max) # 解析Z范围 z_min, z_max = map(float, z_range_box.text.split(',')) ax_main.set_zlim(z_min, z_max) fig.canvas.draw_idle() except Exception as e: print(f"Invalid scale input: {e}") apply_button.on_clicked(apply_scale) # 重置比例函数 def reset_scale(event): ax_main.set_xlim(global_limits['xlim'][0], global_limits['xlim'][1]) ax_main.set_ylim(global_limits['ylim'][0], global_limits['ylim'][1]) ax_main.set_zlim(global_limits['zlim'][0], global_limits['zlim'][1]) # 更新输入框值 x_range_box.set_val(f"{global_limits['xlim'][0]:.2f}, {global_limits['xlim'][1]:.2f}") y_range_box.set_val(f"{global_limits['ylim'][0]:.2f}, {global_limits['ylim'][1]:.2f}") z_range_box.set_val(f"{global_limits['zlim'][0]:.2f}, {global_limits['zlim'][1]:.2f}") fig.canvas.draw_idle() reset_scale_button.on_clicked(reset_scale) plt.show()】
06-14
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值