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

如何用adjust_text调整局部高低点标注:低点在下、高点在上?

解决方案

要强制局部最大值标注在曲线上方、最小值标注在曲线下方,核心是区分点的类型并调整标注的y坐标,再配合adjust_text的参数避免自动调整破坏位置。

步骤1:区分局部高点/低点

首先确保你能识别每个标注点是峰值(局部最大值)还是谷值(局部最小值)。如果graph_annotates没有现成的标识列,可以通过对比该点与前后数据的数值来判断:

# 为graph_annotates添加点类型标识
graph_annotates['point_type'] = 'peak'  # 默认设为峰值
y_col = 'mentee_per_mentor'
date_col = 'date'

for idx in graph_annotates.index:
    current_date = graph_annotates[date_col].iloc[idx]
    current_val = graph_annotates[y_col].iloc[idx]
    
    # 获取当前点的前一个值(最近的更早日期)
    prev_rows = df_for_pred[df_for_pred[date_col] < current_date]
    prev_val = prev_rows[y_col].iloc[-1] if not prev_rows.empty else current_val
    
    # 获取当前点的后一个值(最近的更晚日期)
    next_rows = df_for_pred[df_for_pred[date_col] > current_date]
    next_val = next_rows[y_col].iloc[0] if not next_rows.empty else current_val
    
    # 判断是否为谷值
    if current_val < prev_val and current_val < next_val:
        graph_annotates['point_type'].iloc[idx] = 'trough'

步骤2:调整标注位置并创建文本

基于点的类型,给标注添加相对数据范围的y轴偏移,同时设置垂直对齐方式让文本位置更合理:

# 计算相对偏移量(基于数据范围的5%,适配不同尺度)
y_min = df_for_pred[y_col].min()
y_max = df_for_pred[y_col].max()
y_offset = (y_max - y_min) * 0.05

labels = []
for idx in graph_annotates.index:
    x = graph_annotates[date_col].iloc[idx]
    base_y = graph_annotates[y_col].iloc[idx]
    val_text = f"{base_y:.2f}"
    point_type = graph_annotates['point_type'].iloc[idx]
    
    # 调整y坐标:峰值上移,谷值下移
    if point_type == 'peak':
        adjusted_y = base_y + y_offset
        vertical_align = 'bottom'  # 文本底部对齐点的上方
    else:
        adjusted_y = base_y - y_offset
        vertical_align = 'top'     # 文本顶部对齐点的下方
    
    # 创建标注文本
    label = plt.text(x, adjusted_y, val_text, verticalalignment=vertical_align)
    labels.append(label)

步骤3:限制adjust_text的调整方向

默认的adjust_text可能会把标注拉回错误位置,所以限制它只在y轴方向微调,避免破坏上下布局:

adjust_text(labels, only_move={'points': 'y', 'texts': 'y'}, force_text=0.5)

完整代码整合

# graph plot
plt.plot(
    df_for_pred['date'],
    df_for_pred['mentee_per_mentor'],
    color="r"
)
plt.title('Mentee per mentor dynamic')
plt.grid(False)

# --- 区分高点/低点 ---
graph_annotates['point_type'] = 'peak'
y_col = 'mentee_per_mentor'
date_col = 'date'

for idx in graph_annotates.index:
    current_date = graph_annotates[date_col].iloc[idx]
    current_val = graph_annotates[y_col].iloc[idx]
    
    prev_rows = df_for_pred[df_for_pred[date_col] < current_date]
    prev_val = prev_rows[y_col].iloc[-1] if not prev_rows.empty else current_val
    
    next_rows = df_for_pred[df_for_pred[date_col] > current_date]
    next_val = next_rows[y_col].iloc[0] if not next_rows.empty else current_val
    
    if current_val < prev_val and current_val < next_val:
        graph_annotates['point_type'].iloc[idx] = 'trough'

# --- 调整标注位置 ---
y_min = df_for_pred[y_col].min()
y_max = df_for_pred[y_col].max()
y_offset = (y_max - y_min) * 0.05

labels = []
for idx in graph_annotates.index:
    x = graph_annotates[date_col].iloc[idx]
    base_y = graph_annotates[y_col].iloc[idx]
    val_text = f"{base_y:.2f}"
    point_type = graph_annotates['point_type'].iloc[idx]
    
    if point_type == 'peak':
        adjusted_y = base_y + y_offset
        va = 'bottom'
    else:
        adjusted_y = base_y - y_offset
        va = 'top'
    
    label = plt.text(x, adjusted_y, val_text, verticalalignment=va)
    labels.append(label)

# --- 限制标注调整方向 ---
adjust_text(labels, only_move={'points': 'y', 'texts': 'y'}, force_text=0.5)

plt.show()

关键说明

  • 相对偏移量:避免因数据尺度不同导致偏移过大/过小
  • 垂直对齐参数:让文本与曲线的位置关系更自然,减少覆盖情况
  • only_move参数:防止adjust_text自动调整破坏标注的上下位置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:26:37