使用mplcursors访问本地数据时的标注异常问题排查
问题原因
- 闭包延迟绑定导致变量引用错误:循环中定义的
on_add回调函数属于闭包,它不会在定义时立即捕获当前循环的local_data_df,而是在触发hover事件时才去查找该变量。当循环结束后,local_data_df最终指向最后一次循环的sith数据集,因此所有点的hover提示都会显示sith的信息,坐标也对应错误。 - 缺失numpy导入:代码中使用了
np.random.uniform()但未导入numpy库,会导致运行报错。
修正后的代码方案
import pandas as pd import matplotlib.pyplot as plt import mplcursors import numpy as np # 补上缺失的numpy导入 %matplotlib qt5 def random_data(rows_count): data = [] for i in range(rows_count): row = {} row["x"] = np.random.uniform() row["y"] = np.random.uniform() if i % 2 == 0: row["type"] = "sith" row["color"] = "red" else: row["type"] = "jedi" row["color"] = "blue" data.append(row) return pd.DataFrame(data) data_df = random_data(30) fig, ax = plt.subplots(figsize=(8,8)) types = ["jedi","sith"] for scat_type in types: local_data_df = data_df.loc[data_df["type"] == scat_type].reset_index(drop=True) # 重置索引避免原df索引混乱 scat = ax.scatter(local_data_df["x"], local_data_df["y"], c=local_data_df["color"], label=scat_type) cursor = mplcursors.cursor(scat, hover=mplcursors.HoverMode.Transient) # 使用默认参数捕获当前循环的local_data_df,避免闭包延迟绑定问题 @cursor.connect("add") def on_add(sel, df=local_data_df): row = df.iloc[sel.index] annotation = ( f"{row['type']}\n" f"x: {row['x']:.4f}\n" f"y: {row['y']:.4f}" ) sel.annotation.set(text=annotation) ax.legend() plt.title("a battle of Force users") plt.xlabel("x") plt.ylabel("y") plt.xlim(-1, 2) plt.ylim(-1, 2) ax.set_aspect('equal', adjustable='box') plt.show()
关键修正点
- 补上
import numpy as np,解决未定义np的报错。 - 对
local_data_df执行reset_index(drop=True),确保散点图内的索引与DataFrame的索引一一对应,避免因原DataFrame索引不连续导致的坐标错误。 - 在
on_add函数中添加默认参数df=local_data_df,利用Python默认参数在定义时求值的特性,将当前循环的数据集绑定到回调函数中,解决闭包延迟绑定的问题。 - 使用f-string格式化标注文本,让输出更整洁易读。
内容的提问来源于stack exchange,提问作者Plop
相关产品推荐
相关产品推荐

