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

mplcursors结合Seaborn与多个Pandas DataFrame绘图时光标失效问题排查

解决Seaborn结合mplcursors多DataFrame散点图光标不显示的问题

嘿,我太懂你遇到的这个坑了!问题根源其实很直白:Seaborn的scatterplot()返回的是Axes对象,而不是像matplotlib原生scatter()那样返回散点图的实际绘图元素(PathCollection)。你之前把annotation_names绑定到Axes上,mplcursors根本找不到对应的关联数据,自然就没法正常显示光标啦。

修正后的可运行代码

直接看能解决问题的版本:

from matplotlib import pyplot as plt
import mplcursors
from pandas import DataFrame
import seaborn as sns
sns.set()

df = DataFrame([("Alice", 163, 54), ("Bob", 174, 67), ("Charlie", 177, 73), ("Diane", 168, 57)], 
               columns=["name", "height", "weight"])
df1 = DataFrame([("Alice1", 140, 50), ("Bob1", 179, 60), ("Charlie1", 120, 70), ("Diane1", 122, 60)], 
                columns=["name", "height", "weight"])

fig, ax = plt.subplots(1, 1)

# 用Seaborn绘图后,提取实际的散点绘图元素
sns.scatterplot(data=df, x="height", y="weight", ax=ax)
# Axes的collections列表存储了所有散点元素,取最后一个就是刚创建的那组
scat = ax.collections[-1]
scat.annotation_names = [f'{n}\nh: {h}' for n, h in zip(df["name"], df["height"])]

sns.scatterplot(data=df1, x="height", y="weight", ax=ax)
scat1 = ax.collections[-1]
scat1.annotation_names = [f'{n}\nw: {w}' for n, w in zip(df1["name"], df1["weight"])]

# 把实际的散点元素传给mplcursors,而不是Axes
cursor = mplcursors.cursor([scat, scat1], hover=True)
cursor.connect("add", lambda sel: sel.annotation.set_text(sel.artist.annotation_names[sel.target.index]))

plt.show()

关键改动说明

  • 拿到正确的绘图对象:每次用Seaborn在Axes上画完散点,ax.collections会新增一个PathCollection(就是你看到的那些散点圆点),用ax.collections[-1]就能精准拿到刚创建的那组散点。
  • 绑定属性到正确对象:把annotation_names绑定到散点元素(PathCollection)上,而不是Seaborn返回的Axes,这样mplcursors回调里的sel.artist才能找到对应的标注文本。
  • 让cursor监听正确元素:给mplcursors.cursor()传入散点元素列表,而不是Axes,这样光标才能和每个散点数据正确关联。

小提示

如果你的Jupyter Notebook用%matplotlib notebook后端偶尔还是出问题,可以试试切换成%matplotlib widget后端(需要提前安装ipympl库),交互式绘图的稳定性会更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 19:59:05