如何在非均匀刻度的极坐标图中垂直旋转所有刻度标签?
解决方案:动态调整旋转角度与锚点
直接围绕原点旋转会导致所有标签统一偏移,忽略了各自的刻度角度,这就是90度旋转后标签转出画布的原因。正确的做法是针对每个刻度的自身角度,单独调整旋转参数和文本锚点,让标签始终朝向外侧且垂直于径向。
核心修改代码
替换原函数中plt.xticks()及后续的循环部分为以下代码:
plt.xticks( np.concatenate(tuple(list(thetas.values()))), labels, transform_rotates_text=False # 关闭自动旋转,手动控制 ) # 获取所有刻度的极角(转换为角度) tick_thetas = np.concatenate(tuple(list(thetas.values()))) * 180 / np.pi for tick, theta_deg in zip(plt.xticks()[1], tick_thetas): # 计算旋转角度:让标签垂直于径向,朝向外侧 rotate_angle = theta_deg - 90 # 围绕刻度自身位置旋转,避免偏移 tick.set_transform( tick.get_transform() + mpl.transforms.Affine2D().rotate_deg_around( tick.get_position()[0], tick.get_position()[1], rotate_angle ) ) # 根据象限设置锚点,确保文本向外排列 if 0 <= theta_deg < 90: tick.set_ha('right') tick.set_va('bottom') elif 90 <= theta_deg < 180: tick.set_ha('right') tick.set_va('top') elif 180 <= theta_deg < 270: tick.set_ha('left') tick.set_va('top') else: # 270°-360° tick.set_ha('left') tick.set_va('bottom')
修改说明
- 关闭自动旋转:
transform_rotates_text=False避免Matplotlib默认的极坐标旋转干扰自定义设置。 - 基于刻度位置旋转:不再围绕原点旋转,而是以每个刻度的实际坐标点为旋转中心,确保标签不会偏离刻度线。
- 动态计算旋转角度:根据刻度的极角计算旋转值,保证文本方向与径向垂直。
- 象限锚点适配:根据刻度所在象限调整文本对齐方式,让标签始终向外,避免被画布截断。
修改后的完整draw_radar函数
def draw_radar(data, colour_letters, person_name=""): """Draw the graph. Based substantially on a SO thread """ # not really sure why -1, but if you don't you get an empty segment num_areas = len(data) - 1 running_total = 0 thetas = {} for key, value in data.items(): this_area_num_points = len(value) this_area_theta = ((2 * np.pi) / num_areas) / (this_area_num_points) thetas[key] = [] for i in range(len(value)): thetas[key].append((i * this_area_theta) + running_total) running_total += (2 * np.pi) / num_areas labels = [] for key, value in data.items(): for area, score in value.items(): labels.append(f"{score} {key}: {area}") for name, theta_list in thetas.items(): individual_scores = list(data[name].values()) colour = random.choice(colour_letters) if len(theta_list) > 1: plt.polar(theta_list, individual_scores, c=colour, label=name) elif len(theta_list) == 1: plt.scatter(theta_list, individual_scores, c=colour, label=name) plt.yticks(np.arange(-5, 5), [""] * 5 + list(range(5))) # 修改后的刻度设置部分 plt.xticks( np.concatenate(tuple(list(thetas.values()))), labels, transform_rotates_text=False ) tick_thetas = np.concatenate(tuple(list(thetas.values()))) * 180 / np.pi for tick, theta_deg in zip(plt.xticks()[1], tick_thetas): rotate_angle = theta_deg - 90 tick.set_transform( tick.get_transform() + mpl.transforms.Affine2D().rotate_deg_around( tick.get_position()[0], tick.get_position()[1], rotate_angle ) ) if 0 <= theta_deg < 90: tick.set_ha('right') tick.set_va('bottom') elif 90 <= theta_deg < 180: tick.set_ha('right') tick.set_va('top') elif 180 <= theta_deg < 270: tick.set_ha('left') tick.set_va('top') else: tick.set_ha('left') tick.set_va('bottom') if person_name: plt.title = f"Competency for {person_name}" plt.savefig("radar.png")
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

