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

如何用Matplotlib TextBox替代input实现图形化输入等待?

问题描述

需要在1D数据图中通过选择起止点提取线段,为每条选中的线段指定名称(用Matplotlib的TextBox替代终端input函数),但原代码无法复刻input的阻塞等待行为,导致程序会持续接收用户的点击操作,无法正常完成单条线段的命名流程。

解决方案

Matplotlib采用事件驱动的交互模式,无法直接实现类似input的阻塞逻辑,需要重构代码逻辑:将输入名称后的后续操作(存储线段信息、清理图形)放到TextBox的提交回调中,同时在等待输入时暂时禁用拾取事件,避免用户误操作。

修改后的完整代码
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.widgets import TextBox


def main():
    # 预设要提取的线段数量
    nSegment = 3
    # 记录已选择的点数
    nPointPressed = 0   
    # 存储当前线段的起始索引
    I0 = 0
    # 保存所有线段的信息:[名称, 起始索引, 结束索引]
    segment = []
    # 存储拾取事件的连接ID,用于断开/重新连接事件
    pick_cid = None  

    def onpick(event):
        nonlocal nPointPressed, I0, fig, ax, pick_cid
        
        # 获取选中点的索引
        ind = event.ind
        if len(ind) != 1:
            return
    
        # 绘制选中的点(红色空心圆)
        ax.plot(x[ind], y[ind], 'o', markerfacecolor='none', color='red', linewidth=2, markersize=5)
        plt.draw() 
        nPointPressed += 1
        
        # 偶数次点击为线段终点
        if nPointPressed % 2 == 0:
            # 生成当前线段的索引区间
            current_ij = np.linspace(I0, ind, dtype=int)
            # 绘制临时连线(绿色)
            ax.plot(x[current_ij], y[current_ij], color='green')
            plt.draw()
            
            # 断开拾取事件,防止用户在输入名称时继续点击
            fig.canvas.mpl_disconnect(pick_cid)
            
            # 定义名称提交后的处理逻辑
            def submit_name(name):
                nonlocal current_ij, pick_cid
                # 保存当前线段的信息
                segment.append([name, current_ij[0], current_ij[-1]])
                
                # 清理临时绘制的起点、终点和连线
                pts = ax.get_lines()
                pts[-3].remove()  # 删除起点标记
                pts[-2].remove()  # 删除终点标记
                pts[-1].set_color("darkgreen")  # 将临时连线改为深绿色,标记已确认
                
                # 移除TextBox组件
                text_box.remove()
                plt.draw()
                
                # 如果还未选够预设的线段数量,重新连接拾取事件
                if len(segment) < nSegment:
                    pick_cid = fig.canvas.mpl_connect("pick_event", onpick)
                else:
                    # 选够线段后关闭窗口
                    plt.close()
            
            # 在图底部添加TextBox输入框
            axbox = fig.add_axes([0.1, 0.05, 0.8, 0.075])
            text_box = TextBox(axbox, "Segment name: ", textalignment="center")
            text_box.on_submit(submit_name)
            text_box.set_val("Unknown")  # 设置默认名称
            
        else:
            # 奇数次点击为线段起点,保存索引
            I0 = ind

    # 生成示例数据
    x = np.linspace(0, 2*np.pi, 20, dtype=float)
    y = np.sin(x) 
   
    # 创建绘图窗口并连接拾取事件
    fig, ax = plt.subplots()
    ax.plot(x, y, '-^', picker=True)
    pick_cid = fig.canvas.mpl_connect("pick_event", onpick)
    plt.show()
 
    # 打印最终提取的线段信息
    for seg in segment:
        print(seg)


if __name__ == '__main__':
    main()
关键修改说明
  • 新增pick_cid变量管理拾取事件的连接状态,在等待名称输入时断开事件,避免用户误操作
  • 将线段的起止索引暂存到current_ij,在TextBox的提交回调中完成信息存储和图形清理
  • 提交名称后,根据是否已完成所有线段的提取,决定重新连接拾取事件或关闭窗口
  • 移除TextBox避免界面冗余,修改连线颜色区分已确认的线段

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:54:52