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

Matplotlib多曲线绘图如何实现鼠标悬停显示对应标注

Matplotlib多曲线悬停显示标注实现

核心逻辑是绘图时暂存所有曲线对象,绑定鼠标移动事件,仅当光标距离某条曲线足够近时才弹出对应标注,非悬停状态下所有标注隐藏,完全避免多标签堆叠杂乱的问题。


完整可运行代码

# Jupyter环境保留这行启用交互后端,本地脚本可注释
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np

# ---------------------- 原有数据替换区 ----------------------
# 替换为你自己的distance、force数据即可
# distance = x轴距离数据
# force = 二维列表,每个元素对应一条曲线的力值序列
# -------------------------------------------------------------

fig, ax = plt.subplots(figsize=(10,6))
# 提前配置每条曲线的标注文本,可替换为实际的曲线名/工况名/测试编号
curve_labels = [f"测试序列 {i+1}" for i in range(len(force))]
lines = []  # 存储所有曲线对象,用于后续悬停检测

# 循环绘图,xlabel/ylabel放在循环外避免重复执行
for i in range(len(force)):
    line, = ax.plot(distance, force[i], alpha=0.1, color='#1f77b4')
    lines.append(line)

ax.set_xlabel('Distance [mm]', fontsize=12)
ax.set_ylabel('Force [N]', fontsize=12)

# 初始化悬停标注,默认隐藏
annot = ax.annotate(
    "", 
    xy=(0,0), 
    xytext=(10,10),  # 标注相对光标位置的像素偏移
    textcoords="offset points",
    bbox=dict(boxstyle="round", fc="white", alpha=0.9),
    visible=False
)

# 悬停检测阈值,单位为像素,可按需调整
hover_threshold = 5

def on_mouse_move(event):
    # 鼠标不在坐标轴范围内时,隐藏标注、恢复所有曲线默认透明度
    if event.inaxes != ax:
        annot.set_visible(False)
        for line in lines:
            line.set_alpha(0.1)
        fig.canvas.draw_idle()
        return
    
    closest_line = None
    min_dist = hover_threshold
    closest_label = ""
    # 遍历所有曲线,找离光标最近的符合阈值要求的曲线
    for line, label in zip(lines, curve_labels):
        if not line.get_visible():
            continue
        # 将曲线数据坐标转为像素坐标,计算光标到曲线的最短距离
        xdata = line.get_xdata()
        ydata = line.get_ydata()
        disp_coords = line.get_transform().transform(np.column_stack((xdata, ydata)))
        dist = np.min(np.hypot(disp_coords[:,0] - event.x, disp_coords[:,1] - event.y))
        
        if dist < min_dist:
            min_dist = dist
            closest_line = line
            closest_label = label
    
    # 找到匹配的最近曲线时,显示标注+高亮当前曲线
    if closest_line:
        xdata = closest_line.get_xdata()
        ydata = closest_line.get_ydata()
        disp_coords = closest_line.get_transform().transform(np.column_stack((xdata, ydata)))
        closest_idx = np.argmin(np.hypot(disp_coords[:,0] - event.x, disp_coords[:,1] - event.y))
        annot.xy = (xdata[closest_idx], ydata[closest_idx])
        annot.set_text(closest_label)
        annot.set_visible(True)
        # 悬停曲线加深显示,其余保持低透明度
        for line in lines:
            line.set_alpha(0.8 if line is closest_line else 0.1)
    else:
        annot.set_visible(False)
        for line in lines:
            line.set_alpha(0.1)
    
    fig.canvas.draw_idle()

# 绑定鼠标移动事件
fig.canvas.mpl_connect('motion_notify_event', on_mouse_move)

plt.tight_layout()
plt.show()

可调参数说明

  • 悬停灵敏度:修改hover_threshold数值即可,数值越大越容易触发悬停,数值越小需要光标越贴近曲线才会弹出标注
  • 标注样式:修改ax.annotate的bbox参数可调整标注框的颜色、圆角、透明度,修改xytext可调整标注和光标的相对偏移
  • 高亮效果:如果不需要悬停时加深曲线透明度,删除代码中所有set_alpha相关行即可
  • 标注内容:将curve_labels列表内容替换为实际需要显示的曲线信息(比如材料参数、采集时间、测试组号等)即可

注意事项

  • Jupyter Notebook/Lab环境运行需要先安装ipympl包,再用%matplotlib widget启动交互后端,否则鼠标事件无法正常触发
  • 本地脚本运行可注释开头的%matplotlib widget行,Matplotlib会自动调用Qt/Tk等本地交互后端,不影响功能
  • 70条曲线的量级下该检测逻辑无卡顿问题,不需要额外做性能优化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:54:25