1

我知道 StackOverflow 中有很多类似的主题,但没有一个答案能解决我的具体问题。

首先,我正在尝试使用 scatter 命令将来自不同类的二维数据点绘制到图中。该程序使用 matplotlib 事件,如 button_press_event 和 motion_notify_event,我假设应该在事件命令 plt.show() 之后立即使用。主要问题是,一旦某些任务完成了事件(即标记),我想更新整个图,但 plt.show() 阻止了继续程序的选项。实际上 plt.show() 应该阻止程序,直到程序的用户决定继续。有没有办法控制这个阻塞属性?

我尝试过 plt.ion()、plt.ioff()、plt.show(block=False)、plt.draw()、plt.pause(0.001)、带有 while 循环的全局变量等,但没有成功。程序以某种方式正确工作的唯一方法是当满足所谓的前向条件时在 button_press_event 内关闭所有图形,但是如果每次更新数据点时都关闭所有图形,则不是非常用户友好的解决方案。

这是代码的一瞥:

def draw_original_figure(random_sample, random_sample_label, random_sample_image, X_train_chosen, y_train_chosen, images_train_chosen, classes, accuracy, embedding, model, h=0.05):
    global points1, im1, s_im1, xybox, x1, y1, fig1, classes1, points_to_plot, y_train_chosen1, accuracy1, random_sample1, embedding1, y_train_chosen1, h1, random_sample_label1, result1
    fig1 = plt.gcf()
        .
        .
        .
    original_figure_plot()
    fig1.canvas.mpl_connect('motion_notify_event', hover)
    fig1.canvas.mpl_connect('button_press_event', click)
    plt.show()

def hover(event):
    # if the mouse is over the scatter points
    if points1.contains(event)[0]:
        # find out the index within the array from the event
        inds = points1.contains(event)[1]["ind"]
        ind = inds[0]
        # get the figure size
        w,h = fig1.get_size_inches()*fig1.dpi
        ws = (event.x > w/2.)*-1 + (event.x <= w/2.) 
        hs = (event.y > h/2.)*-1 + (event.y <= h/2.)
        # if event occurs in the top or right quadrant of the figure,
        # change the annotation box position relative to mouse.
        ab1.xybox = (xybox[0]*ws, xybox[1]*hs)
        # make annotation box visible
        ab1.set_visible(True)
        # place it at the position of the hovered scatter point
        ab1.xy =(x1[ind], y1[ind])
        # set the image corresponding to that point
        im1.set_data(s_im1[ind,:,:])
    else:
        #if the mouse is not over a scatter point
        ab1.set_visible(False)
    fig1.canvas.draw_idle()

def click(event):
    # if the mouse is over the scatter points
    if points1.contains(event)[0]:
        # find out the index within the array from the event
        inds = points1.contains(event)[1]["ind"]
        ind = inds[0]
        # if one specific point is chosen
        if ind == len(x1)-1:
            plt.scatter(x1[ind], y1[ind], s=25, marker='x', c='#556B2F')
            q = question(True, ind)
            # do nothing
            if q == "":
                original_figure_plot()
            # quit the program
            elif q == "q":
                exit()
            # continue the program without updating labels
            elif q == "n":
                result1 = copy.deepcopy(y_train_chosen1)
                plt.close("all")
            # continue the program after labels are updated
            else:
                result1 = copy.deepcopy(y_train_chosen1)
                result1 = np.append(result1, [int(q)], axis=0)
                plt.close("all")

        else:
            # if anyone else point is chosen
            plt.scatter(x1[ind], y1[ind], s=8, c='k')
            q = question(False, ind)
            # do nothing
            if q == "":
                original_figure_plot()
            # quit the program
            elif q == "q":
                exit()
            # update labels
            else:
                y_train_chosen1[ind] = int(q)
                original_figure_plot()
    fig1.canvas.draw_idle()

可能最好使用其他库,例如 plotly 或 dash 但是如果您使用 matplotlib 事件,您真的不能在不关闭它的情况下更新图形吗?我可以提供所有项目文件,但我认为如果有解决方案,应该在这些函数内部完成。

4

1 回答 1

0

花了一整天的时间才找到答案,但它就在这里!

我现在在交互模式下使用 plt.show() 和命令 plt.ion() 并使用命令 fig.canvas.start_event_loop() 和 fig.canvas.stop_event_loop() 手动阻止。老实说,很难找到解决这个问题的方法,但我们吸取了教训。

在 tk 应用程序内触发关闭事件后,matplotlib 图不继续程序流程

于 2019-05-15T13:15:54.857 回答