能否Pickle mplcursors标注以保存复用?如何提取所有标注?
关于mplcursors标注的提取与Pickle序列化方案
一、提取mplcursors生成的持久化标注
mplcursors的持久化标注(即点击后保留的标注,对应multiple=True的cursor)并非直接存放在轴的get_children()中,而是保存在cursor实例的_persisted属性里——这个列表存储了所有Selection对象,每个对象包含对应的标注(annotation)和关联的数据点信息。
你代码中的cursor2采用HoverMode.Transient模式,它的标注是临时的,不会被持久化,因此无需提取。
提取标注关键信息的示例代码:
def get_persisted_annotations(cursor): """提取cursor中所有持久化标注的关键数据""" anno_info_list = [] for sel in cursor._persisted: anno_info = { "scatter_id": id(sel.artist), # 用唯一标识关联对应的散点图 "point_index": sel.target.index, "text": sel.annotation.get_text(), "position": sel.annotation.get_position(), "bg_color": sel.annotation.get_facecolor(), "draggable": sel.annotation.get_draggable() } anno_info_list.append(anno_info) return anno_info_list # 在你原代码的plt.show()之前调用(点击生成标注后,可通过交互暂停后执行) # anno_data = get_persisted_annotations(cursor1)
二、Pickle序列化与加载恢复
直接序列化Annotation对象不可行——matplotlib的艺术家对象与当前画布、轴实例强绑定,序列化后会丢失关联关系,无法正常恢复交互功能。正确的做法是序列化上述提取的关键数据,加载时重新构建标注并绑定交互。
1. 序列化保存标注数据
import pickle # 假设已提取anno_data with open("mpl_annotations.pkl", "wb") as f: pickle.dump(anno_data, f)
2. 加载并恢复标注与交互
重新创建绘图后,加载数据并恢复标注,同时保留原交互逻辑:
import matplotlib.pyplot as plt import mplcursors import pickle # 1. 重建原绘图结构 x1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] x2 = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] fig, ax = plt.subplots() ax.set_title("Loaded Annotations (Keep Interactions)") scatter1 = ax.scatter(x1, x1) scatter2 = ax.scatter(x2, x2) # 2. 创建与原配置一致的cursor,并绑定原交互逻辑 cursor1 = mplcursors.cursor(multiple=True) cursor1.connect("add", lambda sel: sel.annotation.draggable(True)) # 3. 加载标注数据 with open("mpl_annotations.pkl", "rb") as f: anno_data = pickle.load(f) # 4. 建立散点图标识到对象的映射 scatter_map = {id(scatter1): scatter1, id(scatter2): scatter2} # 5. 逐个恢复标注 for anno_info in anno_data: scatter = scatter_map[anno_info["scatter_id"]] point_idx = anno_info["point_index"] # 创建Selection对象,关联cursor与数据点 sel = mplcursors.Selection(cursor1, scatter, point_idx) # 恢复标注的文本、位置、样式 sel.annotation.set_text(anno_info["text"]) sel.annotation.set_position(anno_info["position"]) sel.annotation.set_facecolor(anno_info["bg_color"]) sel.annotation.draggable(anno_info["draggable"]) # 将标注加入cursor的持久化列表,保留右键删除、拖拽交互 cursor1._persisted.append(sel) sel.annotation.set_visible(True) plt.show()
三、关键说明
- 仅
multiple=True的cursor会生成持久化标注,临时hover标注无法被保存。 - 序列化时必须存储可重建标注的核心数据,而非直接序列化标注对象,否则会丢失交互与显示关联。
- 恢复时需确保重建的绘图结构(如散点图)与原绘图一致,否则无法正确关联数据点。
内容的提问来源于stack exchange,提问作者Hannibal
相关产品推荐
相关产品推荐

