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
相关产品推荐
相关产品推荐

