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

使用Matplotlib滑块时如何更新悬停标注?

解决Matplotlib滑块切换时悬停标签不更新的问题

问题分析

初始设置的悬停标签回调绑定了初始的标签列表,滑块切换后虽然更新了散点数据,但回调函数依然引用旧的标签,导致显示错误。直接在update里新建cursor会叠加多个悬停实例,出现重复标签。

解决思路

  • 保存初始创建的mplcursors.Cursor实例,避免重复创建
  • 使用可变对象存储当前标签(比如列表),让回调函数能动态获取最新标签;或者直接在回调中根据当前滑块值从DataFrame取对应标签

修改后的完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import mplcursors as mplc
%matplotlib widget

data = {'Name': ['A', 'B', 'C', 'D'], 
        'x': [1,3,3,2],
        'y': [4,7,5,1],
        'color': [1,2,3,2],
        'size' :[50,40,10,30],
        'slide': [1,1,2,2]}
df=pd.DataFrame.from_dict(data)
dff=df.loc[df['slide']==1]
z=list(set(df['slide'].to_list()))

# 用可变列表存储当前标签,让回调能动态获取最新值
current_labels = dff['Name'].to_list()

fig, ax = plt.subplots()
points = ax.scatter(dff['x'], dff['y'], s=100, alpha=0.5)

# 保存cursor实例,避免重复创建
cursor = mplc.cursor(ax, hover=True)
# 绑定回调,使用current_labels获取最新标签
@cursor.connect("add")
def on_add(sel):
    sel.annotation.set_text(current_labels[sel.index])

# 设置坐标轴范围
xmin, xmax = df['x'].min()-10, df['x'].max()+10
ymin, ymax = df['y'].min()-10, df['y'].max()+10
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)

# 创建滑块
axfreq = fig.add_axes([0.15, 0.1, 0.65, 0.03])
plot_slider = Slider(
    ax=axfreq,
    label='Slide',
    valmin=1,  # 匹配slide字段的实际取值,避免0值无数据
    valmax=max(z),
    valinit=1,
    valstep=1,)

def update(val):
    global current_labels
    dff=df.loc[df['slide']==val]
    x = dff['x'].to_list()
    y = dff['y'].to_list()
    # 更新可变列表的内容,而非重新赋值
    current_labels[:] = dff['Name'].to_list()
    # 更新散点位置
    points.set_offsets(np.c_[x,y])
    # 可选:同步更新点的大小和颜色
    points.set_sizes(dff['size'].to_list())
    points.set_array(dff['color'].to_list())

plot_slider.on_changed(update)
plt.show()

关键修改点

  1. 可变列表存储标签:current_labels是可变列表,在update中用current_labels[:] = ...更新内容,确保回调函数始终引用最新标签
  2. 单例cursor实例:只创建一次cursor,避免重复实例导致的多标签叠加问题
  3. 修正滑块范围:将valmin改为1,匹配slide字段的实际取值,避免0值无数据的情况
  4. 可选样式同步:添加set_sizes和set_array,同步更新点的大小与颜色

另一种无全局变量的思路

如果不想用全局变量,可在回调中直接根据当前滑块值查询DataFrame:

@cursor.connect("add")
def on_add(sel):
    current_slide_val = plot_slider.val
    dff_current = df.loc[df['slide'] == current_slide_val]
    sel.annotation.set_text(dff_current.iloc[sel.index]['Name'])

该方式无需维护current_labels,每次悬停时直接查询数据,性能差异可忽略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 07:33:22