You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用textalloc实现无重叠折线标注并自动选择标注位置?

解决多折线图标注自动定位与重叠避让问题

一、自动确定标注点位置

不用手动指定x坐标,可通过以下方式自动获取合适的标注锚点:

  • 取折线终点:直接用每条折线的最后一组(x,y)坐标作为锚点,适合趋势展示类图表
    for line in ax.lines:
        x_data = line.get_xdata()
        y_data = line.get_ydata()
        # 取最后一个点作为标注锚点
        annot_x = x_data[-1]
        annot_y = y_data[-1]
    
  • 取折线极值点:找到每条折线的最高点或最低点,适合突出关键数据的场景
    for line in ax.lines:
        y_data = line.get_ydata()
        # 找最高点索引
        peak_idx = y_data.argmax()
        annot_x = line.get_xdata()[peak_idx]
        annot_y = y_data[peak_idx]
    
  • x轴末端偏移:如果折线终点过于拥挤,可在x轴最大刻度外偏移一定距离作为标注位置
    x_max = ax.get_xlim()[1]
    x_offset = (x_max - ax.get_xlim()[0]) * 0.02  # 偏移x轴范围的2%
    for line in ax.lines:
        y_data = line.get_ydata()
        annot_x = x_max + x_offset
        annot_y = y_data[-1]
    

二、解决标注重叠问题

1. 正确使用adjustText模块

之前使用adjustText未成功大概率是参数配置不到位,试试以下包含折线避让的配置:

import matplotlib.pyplot as plt
from adjustText import adjust_text

# 绘制所有折线
fig, ax = plt.subplots()
labels = ["折线A", "折线B", "折线C"]
x = range(10)
y_list = [[i+1 for i in x], [i*1.5 for i in x], [i*0.8 for i in x]]
lines = []
for y, label in zip(y_list, labels):
    line, = ax.plot(x, y, label=label)
    lines.append(line)

# 收集所有标注对象
texts = []
for line, label in zip(lines, labels):
    x_data = line.get_xdata()
    y_data = line.get_ydata()
    # 以折线终点为锚点创建标注
    txt = ax.text(x_data[-1], y_data[-1], label)
    texts.append(txt)

# 关键配置:让标注避开折线,调整扩展距离与迭代次数
adjust_text(texts, 
            add_objects=lines,  # 将折线加入避让对象
            expand_points=(1.2, 1.2),  # 标注间的扩展间距
            expand_text=(1.5, 1.5),
            arrowprops=dict(arrowstyle="-", color='gray', lw=0.5),  # 用箭头连接锚点与标注
            force_text=0.8,
            force_objects=0.8,
            iterations=50)  # 增加迭代次数提升避让效果
plt.show()

2. 优化textalloc的避让逻辑

使用textalloc时,需将折线的所有坐标点加入避让障碍物列表,而非仅避让其他标注:

import matplotlib.pyplot as plt
from textalloc import allocate_text

fig, ax = plt.subplots()
x = range(10)
y_list = [[i+1 for i in x], [i*1.5 for i in x], [i*0.8 for i in x]]
labels = ["折线A", "折线B", "折线C"]
lines = []
for y, label in zip(y_list, labels):
    line, = ax.plot(x, y, label=label)
    lines.append(line)

# 收集所有折线的坐标点作为避让障碍物
obstacles = []
for line in lines:
    x_coords = line.get_xdata()
    y_coords = line.get_ydata()
    obstacles.extend(list(zip(x_coords, y_coords)))

# 自动获取标注锚点(此处用折线终点)
annot_points = [(line.get_xdata()[-1], line.get_ydata()[-1]) for line in lines]

# 调用textalloc并传入障碍物列表
allocate_text(
    ax,
    annot_points,
    labels,
    obstacles=obstacles,
    text_size=10,
    min_distance=15,  # 标注与障碍物、其他标注的最小像素距离
)
plt.show()

3. 辅助优化技巧

  • 给标注添加半透明背景,轻微重叠时也能保证可读性:
    txt = ax.text(x, y, label, bbox=dict(facecolor='white', alpha=0.7, edgecolor='none', pad=1))
    
  • 对密集区域的标注设置旋转角度,减少横向空间占用:
    txt = ax.text(x, y, label, rotation=45, ha='right')
    

内容的提问来源于stack exchange,提问作者user28754841

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:28:26