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

能否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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:25:18