如何在Matplotlib极坐标图中实现文本沿曲线排列?
在Matplotlib极坐标图中实现文本沿曲线排列
我想要在Matplotlib的极坐标图里实现文本沿曲线排列,以下是我的基础实现代码:
import matplotlib.pyplot as plt import numpy as np text = ["Electoral Process", "Political Pluralism", "Rule of Law", "Freedom of expression", "Freedom of believe"] no_labels = len(text) angle_size = int(360 / no_labels) # 定义角度(度转弧度) theta = [i / 180 * np.pi for i in range(0, 360, angle_size)] # 文本所在的径向半径 radius = [1] * no_labels # 计算每个扇区的中点角度 mid_point = [i / 180 * np.pi for i in range(int(angle_size/2), 360, angle_size)] fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(10, 6), facecolor="white") ax.set_theta_zero_location('N') ax.set_theta_direction(-1) ax.set_xticklabels([]) # 移除默认x轴标签 ax.set_yticklabels([]) # 移除默认y轴标签 # 按标签数量划分网格线 lines = plt.thetagrids(range(0, 360, int(360/len(text)))) # 在每个扇区中点放置居中文本 for m, r, t in zip(mid_point, radius, text): ax.annotate(t, xy=[m, r], fontsize=12, ha="center", va="center")
这段代码生成的是普通居中文本的极坐标图。我尝试从零开始实现文本沿曲线排列,目前的进展如下:
import numpy as np import matplotlib.pyplot as plt text = ["Electoral Process", "Political Pluralism", "Rule of Law", "Freedom of expression", "Freedom of believe"] no_labels = len(text) angle_size = int(360 / no_labels) # 定义角度(度转弧度) theta = [i / 180 * np.pi for i in range(0, 360, angle_size)] # 文本所在的径向半径 radius = [1] * no_labels # 计算每个扇区的中点角度 mid_point = [i / 180 * np.pi for i in range(int(angle_size/2), 360, angle_size)] fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(10,6), dpi=100) # 按标签数量划分网格线 lines = plt.thetagrids(range(0, 360, int(360/len(text)))) ax.set_theta_zero_location('N') ax.set_theta_direction(-1) ax.set_xticklabels([]) # 移除默认x轴标签 ax.set_yticklabels([]) # 移除默认y轴标签 # 尝试单个标签拆分字母排列 start_text = theta[0] text2 = ["ELECTORAL PROCESS"] spacing = len(text[0]) + 4 end_text = theta[1] x = np.linspace(start_text, end_text, spacing) for txt in text2: for a, tx in zip(x, txt): ax.text(a, 1.05, tx, rotation=-28, fontsize=8, ha="center", va="center")
这段代码实现了单个标签拆分字母的初步效果,但我需要循环处理所有标签,动态调整每个字母的旋转角度以贴合曲线,还要根据位置调整文本方向(比如部分区域文本正向,部分区域反向),这让问题变得复杂。
简洁实现代码
以下是可以批量处理所有标签、自动调整旋转角度和方向的完整代码:
import matplotlib.pyplot as plt import numpy as np text = ["Electoral Process", "Political Pluralism", "Rule of Law", "Freedom of expression", "Freedom of believe"] no_labels = len(text) angle_size = 360 / no_labels radius = 1.05 # 文本所在的径向距离,稍大于网格半径更美观 fig, ax = plt.subplots(subplot_kw={'projection': 'polar'}, figsize=(10, 6), facecolor="white") ax.set_theta_zero_location('N') ax.set_theta_direction(-1) ax.set_xticklabels([]) ax.set_yticklabels([]) plt.thetagrids(range(0, 360, int(angle_size))) for idx, label in enumerate(text): # 计算当前标签所在扇区的起始和结束角度(弧度) start_angle = idx * angle_size * np.pi / 180 end_angle = (idx + 1) * angle_size * np.pi / 180 # 生成每个字符对应的角度,均匀分布在扇区内 char_angles = np.linspace(start_angle, end_angle, len(label)) for char, angle in zip(label, char_angles): # 将极坐标角度转换为文本旋转角度(贴合曲线切线) rotation = np.rad2deg(angle) # 右半区(角度在90-270度之间,对应弧度π/2到3π/2)文本反向,避免倒置 if np.pi/2 < angle < 3*np.pi/2: rotation += 180 ax.text(angle, radius, char, fontsize=10, ha='center', va='center', rotation=rotation, rotation_mode='anchor') # 基于锚点旋转,保证字符位置准确 plt.show()
参考代码原理解释
你提到的参考代码核心逻辑和上述实现一致,拆解来看:
- 文本拆分与角度分配:把每个标签拆分为单个字符,将当前扇区的角度范围均匀分配给每个字符,确保字符沿着扇区的弧线排列。
- 旋转角度计算:极坐标下的每个角度对应笛卡尔坐标系中的切线方向,文本的旋转角度需要和这个切线方向一致,才能贴合曲线。
- 方向调整:当文本位于极坐标的右半区(弧度π/2到3π/2)时,直接按切线方向旋转会导致文本倒置,因此需要额外增加180度旋转,让文本正向显示。
- 旋转模式设置:使用
rotation_mode='anchor'确保文本以锚点为中心旋转,避免字符位置偏移。
内容的提问来源于stack exchange,提问作者ruthpozuelo
相关产品推荐
相关产品推荐

