Python 如何从Tkinter框架中正确删除图形

Python 如何从Tkinter框架中正确删除图形,python,matplotlib,tkinter,Python,Matplotlib,Tkinter,我有几个图形,我想显示在一个按钮按下。为此,我将plt.Figure和FigureCanvasTkAgg变量设置为全局变量,每次按下按钮时用ax.clear()清除轴。之后,我使用Figure.canvas.mpl_connect添加了一个特性:当我按下图形区域时,第二个点用垂直线高亮显示。当我打印一些简单的输出时(在我的例子中,print('Vertical Line Constructed')在select\u trade\u with_mouse函数中),结果是为构建和擦除的每个图形创建了

我有几个图形,我想显示在一个按钮按下。为此,我将
plt.Figure
FigureCanvasTkAgg
变量设置为全局变量,每次按下按钮时用
ax.clear()
清除轴。之后,我使用
Figure.canvas.mpl_connect
添加了一个特性:当我按下图形区域时,第二个点用垂直线高亮显示。当我打印一些简单的输出时(在我的例子中,
print('Vertical Line Constructed')
select\u trade\u with_mouse
函数中),结果是为构建和擦除的每个图形创建了事件:当我生成一个图形并按下图形(生成事件)时,然后
print('Vertical Line Constructed')
只执行一次。如果生成第二个图形并单击图形,则执行两次
print('Vertical Line Constructed')
。看起来旧图形没有被销毁,单击图形为内存中的每个图形生成一个事件,即使它没有显示。我尝试了
plt.cla()
plt.clf()
plt.close()
,但它们都不能完全删除图形

我的问题是,我如何才能正确地删除旧的图形?这样单击图形将只生成一个事件

我的代码:

import pandas as pd
import tkinter as tk
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


def select_trade_with_mouse(event, ax, graph, data):
    global vertical_line_trading
    print('Vertical Line Constructed')
    if vertical_line_trading:
        vertical_line_trading.remove()
        del vertical_line_trading
    vertical_line_trading = ax.axvline(data, color='b')
    graph.draw()

def construct_graph(change_by = 0):  
    global data
    global graph_index
    print('Graph Constructed')
    graph_index = graph_index + change_by
    ax.clear()
    #plt.close('all')
    line = data[graph_index].plot(x='x', y='y', linestyle='-', ax=ax, linewidth=1, color='y')
    click_id = figure.canvas.mpl_connect('button_press_event', lambda event: select_trade_with_mouse(event, ax, graph, data[graph_index].loc[1, 'x']))    
    graph.draw()


if __name__ == '__main__':

    vertical_line_trading = None
    graph_index = 0

    ## Some random data
    data = []
    for i in range(10):
        data.append(pd.DataFrame({'x': [1+i, 2+i, 3+2*i], 'y': [1+2*i, 2+i, 3+i]}))

    root = tk.Tk()
    main_frame = tk.Frame(root, height=600, width=1200)
    graph_frame = tk.Frame(main_frame, height=500, width=1200)

    ## Graph
    figure = plt.Figure(figsize=(10,10), dpi=100)
    ax = figure.add_subplot(111)
    graph = FigureCanvasTkAgg(figure, graph_frame)
    graph.get_tk_widget().pack(side=tk.LEFT)

    ## Buttons to switch between graphs
    prev_graph_button = tk.Button(graph_frame, command = lambda: construct_graph(-1), height=10, width=10, text='Prev\nGraph')
    next_graph_button = tk.Button(graph_frame, command = lambda: construct_graph(1), height=10, width=10, text='Next\nGraph')
    prev_graph_button.pack(side=tk.LEFT)
    next_graph_button.pack(side=tk.LEFT)

    for frame in [main_frame, graph_frame]:
        frame.pack(side=tk.BOTTOM, fill='both')
        frame.pack_propagate(0)

    root.mainloop()

您不必删除图形。您只需在开始时使用
mpl\u connect()
一次,而不必在清除图形时反复使用

或者您必须在全局变量中保留
单击\u id
,并在
单击\u id=mpl\u connect()之前使用
mpl\u disconnect(单击\u id)

我创建全局变量
在开始时单击\u id=None
,然后在
construct\u graph()
中删除以前的
单击\u id
,如果它不是
None
。这样,图形只分配了一个函数

import pandas as pd
import tkinter as tk
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


def select_trade_with_mouse(event, ax, graph, data):
    global vertical_line_trading
    print('Vertical Line Constructed')
    if vertical_line_trading:
        vertical_line_trading.remove()
        del vertical_line_trading
    vertical_line_trading = ax.axvline(data, color='b')
    graph.draw()

def construct_graph(change_by = 0):  
    global data
    global graph_index
    global click_id 

    print('Graph Constructed')
    graph_index = graph_index + change_by
    ax.clear()
    #plt.close('all')
    line = data[graph_index].plot(x='x', y='y', linestyle='-', ax=ax, linewidth=1, color='y')

    # if function exist then remove it
    if click_id: # if click_id is not None:
        figure.canvas.mpl_disconnect(click_id)

    click_id = figure.canvas.mpl_connect('button_press_event', lambda event: select_trade_with_mouse(event, ax, graph, data[graph_index].loc[1, 'x']))   

    graph.draw()


if __name__ == '__main__':

    click_id = None # create global varaible with default value at start

    vertical_line_trading = None
    graph_index = 0

    ## Some random data
    data = []
    for i in range(10):
        data.append(pd.DataFrame({'x': [1+i, 2+i, 3+2*i], 'y': [1+2*i, 2+i, 3+i]}))

    root = tk.Tk()
    main_frame = tk.Frame(root, height=600, width=1200)
    graph_frame = tk.Frame(main_frame, height=500, width=1200)

    ## Graph
    figure = plt.Figure(figsize=(10,10), dpi=100)
    ax = figure.add_subplot(111)
    graph = FigureCanvasTkAgg(figure, graph_frame)
    graph.get_tk_widget().pack(side=tk.LEFT)

    ## Buttons to switch between graphs
    prev_graph_button = tk.Button(graph_frame, command = lambda: construct_graph(-1), height=10, width=10, text='Prev\nGraph')
    next_graph_button = tk.Button(graph_frame, command = lambda: construct_graph(1), height=10, width=10, text='Next\nGraph')
    prev_graph_button.pack(side=tk.LEFT)
    next_graph_button.pack(side=tk.LEFT)

    for frame in [main_frame, graph_frame]:
        frame.pack(side=tk.BOTTOM, fill='both')
        frame.pack_propagate(0)

    root.mainloop()