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

