如何从 Tkinter 中的 matplotlib remove/clear 子图和 canvas(白色 window- FigureCanvasTkAgg)?
How to remove/clear the subplot and canvas (white window- FigureCanvasTkAgg) from matplotlib in Tkinter?
我正在尝试 运行 一个提供两个按钮的图形用户界面。第一个是打印文件内容 'names.txt',第二个是绘制数据。但是,如果我先绘制数据然后打印内容,则子图将保持原样,我无法清除它。这是我的输出:[![wrong_output][1]]1
我读了 post : 并尝试了同样的方法,但是我没有得到正确的输出
次要情节并没有破坏。
我什至尝试使用 self.scatter1.get_tk_widget().destroy()
destroy
小部件,但这也不起作用
有人可以告诉我如何进行吗?
我的代码是:
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
x_loc=[5, 6, 34, 54, 23]
y_loc=[3, 4.34, 2, 44, 65]
avgLst=[24, 35.65, 54.6, 53, 2]
root= tk.Tk()
class graph_plot():
global graph_past
global graph_Avg
def __init__(self):
self.figure1 = plt.Figure()
self.scatter1 = FigureCanvasTkAgg(self.figure1, root)
self.scatter1.get_tk_widget().place(relx= 0.5, rely=0.1)
self.subplot1 = self.figure1.add_subplot(111)
self.subplot1.set_xlabel('x location')
self.subplot1.set_ylabel('y location')
def display_graph(self):
data1 = {'x-locations' : x_loc , 'y_locations' : y_loc}
df3 = DataFrame(data1,columns=['x-locations','y_locations'])
global graph_past
label2.config(text='')
print('graph in= ' , graph_past)
im0= self.subplot1.scatter(df3['x-locations'],df3['y_locations'], c=avgLst, cmap='rainbow', vmin=min(avgLst), vmax=max(avgLst))
self.figure1.colorbar(im0)
self.subplot1.set_title('Avg')
graph_past= True
def clear_graph(self):
print('Destroyed!')
self.subplot1.clear
## ??? which command
def do_graph():
obj1 = graph_plot()
obj1.display_graph()
def on_key(event):
if myLine and event.keysym != 'Return':
update_print()
def do_printing():
global myLine
global graph_past
#print('graph_past= ' , graph_past)
if graph_past:
obj2 = graph_plot()
obj2.clear_graph()
graph_past = False
input_File = open('names.txt','r')
myLine = input_File.readlines()
update_print()
def update_print():
label2.config(text=random.choice(myLine))
def flag_print():
global graph_Avg
graph_Avg=False
do_printing()
def flag_Avg():
global graph_Avg
graph_Avg=True
do_graph()
root.bind('<Key>', on_key)
myCanvas = tk.Canvas(root, width = 800, height = 500)
myCanvas.grid(row=2, column= 4)
label1 = tk.Label(root, text='MENU')
label1.config(font=('Arial', 20))
myCanvas.create_window(200, 20, window=label1)
myLine= None
graph_Avg=False
graph_past=False
label2 = tk.Label(root, font=('Courier', 15))
label2.place(relx= 0.3, rely=0.1)
B1 = tk.Button(root, text ="Option 1", font=('Courier', 12), command = flag_print)
myCanvas.create_window(200, 100, window=B1)
B2 = tk.Button(root, text ="Option 2", font=('Courier', 12), command = flag_Avg)
myCanvas.create_window(200, 140, window=B2)
root.mainloop()```
[1]: https://i.stack.imgur.com/RgL7S.png
问题
问题是由于在 graph_plot
class 的 __init__()
方法中创建了多个 FigureCanvasTkAgg
对象。此构造函数在 do_graph()
和 do_printing()
方法中调用,这意味着许多相同的 canvas 是在彼此之上创建的。这意味着当您 .destroy()
小部件时,它将破坏一个新的小部件并留下下面的小部件。
解决方案
如果您要继续使用 classes,解决方案是将更多变量提升到全局变量中,这样可以确保您处理的是相同的对象,而不是单独的对象.不过,最好重新考虑使用 classes 来解决这个问题。
代码
我重组了您的一些代码以避开 classes 并获得预期的结果:
import tkinter as tk
import matplotlib.pyplot as plt
from pandas import DataFrame
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
x_loc=[5, 6, 34, 54, 23]
y_loc=[3, 4.34, 2, 44, 65]
avgLst=[24, 35.65, 54.6, 53, 2]
GRAPH_AVG=False
GRAPH_PAST=False
MY_LINE = None
ROOT = tk.Tk()
ROOT.geometry("900x600")
FIGURE = plt.Figure()
SCATTER = FigureCanvasTkAgg(FIGURE, ROOT)
TK_WIDGET = SCATTER.get_tk_widget()
SUBPLOT = FIGURE.add_subplot(111)
SUBPLOT.set_xlabel('x location')
SUBPLOT.set_ylabel('y location')
NAME_LABEL = tk.Label(ROOT, font=('Courier', 15))
NAME_LABEL.place(relx=0.3, rely=0.1)
def display_graph():
global GRAPH_PAST, FIGURE, SUBPLOT
data1 = {'x-locations' : x_loc , 'y_locations' : y_loc}
df3 = DataFrame(data1, columns=['x-locations','y_locations'])
NAME_LABEL.config(text='')
print('graph past= ' , GRAPH_PAST)
im0= SUBPLOT.scatter(df3['x-locations'],df3['y_locations'], c=avgLst, cmap='rainbow', vmin=min(avgLst), vmax=max(avgLst))
FIGURE.colorbar(im0)
SUBPLOT.set_title('Avg')
TK_WIDGET.place(relx=0.3, rely=0.1)
GRAPH_PAST= True
def clear_graph():
global SUBPLOT, TK_WIDGET
print('Destroyed!')
SUBPLOT.clear()
TK_WIDGET.place_forget()
def on_key(event):
global MY_LINE
if MY_LINE and event.keysym != 'Return':
update_print()
def do_printing():
global MY_LINE, GRAPH_AVG, GRAPH_PAST
if GRAPH_PAST:
clear_graph()
GRAPH_PAST = False
MY_LINE = ["john kenny", "maria rose", "sheena"]
update_print()
def update_print():
NAME_LABEL.config(text=random.choice(MY_LINE))
def flag_print():
global GRAPH_AVG
GRAPH_AVG=False
do_printing()
def flag_Avg():
global GRAPH_AVG
GRAPH_AVG=True
display_graph()
ROOT.bind('<Key>', on_key)
B1 = tk.Button(ROOT, text ="Print", font=('Courier', 12), command=flag_print)
B1.place(relx=0.1, rely=0.1)
B2 = tk.Button(ROOT, text ="Graph", font=('Courier', 12), command=flag_Avg)
B2.place(relx=0.1, rely=0.2)
ROOT.mainloop()
尝试用 self.subplot1.clear()
代替 self.subplot1.destroy()
我正在尝试 运行 一个提供两个按钮的图形用户界面。第一个是打印文件内容 'names.txt',第二个是绘制数据。但是,如果我先绘制数据然后打印内容,则子图将保持原样,我无法清除它。这是我的输出:[![wrong_output][1]]1
我读了 post : self.scatter1.get_tk_widget().destroy()
destroy
小部件,但这也不起作用
有人可以告诉我如何进行吗?
我的代码是:
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
x_loc=[5, 6, 34, 54, 23]
y_loc=[3, 4.34, 2, 44, 65]
avgLst=[24, 35.65, 54.6, 53, 2]
root= tk.Tk()
class graph_plot():
global graph_past
global graph_Avg
def __init__(self):
self.figure1 = plt.Figure()
self.scatter1 = FigureCanvasTkAgg(self.figure1, root)
self.scatter1.get_tk_widget().place(relx= 0.5, rely=0.1)
self.subplot1 = self.figure1.add_subplot(111)
self.subplot1.set_xlabel('x location')
self.subplot1.set_ylabel('y location')
def display_graph(self):
data1 = {'x-locations' : x_loc , 'y_locations' : y_loc}
df3 = DataFrame(data1,columns=['x-locations','y_locations'])
global graph_past
label2.config(text='')
print('graph in= ' , graph_past)
im0= self.subplot1.scatter(df3['x-locations'],df3['y_locations'], c=avgLst, cmap='rainbow', vmin=min(avgLst), vmax=max(avgLst))
self.figure1.colorbar(im0)
self.subplot1.set_title('Avg')
graph_past= True
def clear_graph(self):
print('Destroyed!')
self.subplot1.clear
## ??? which command
def do_graph():
obj1 = graph_plot()
obj1.display_graph()
def on_key(event):
if myLine and event.keysym != 'Return':
update_print()
def do_printing():
global myLine
global graph_past
#print('graph_past= ' , graph_past)
if graph_past:
obj2 = graph_plot()
obj2.clear_graph()
graph_past = False
input_File = open('names.txt','r')
myLine = input_File.readlines()
update_print()
def update_print():
label2.config(text=random.choice(myLine))
def flag_print():
global graph_Avg
graph_Avg=False
do_printing()
def flag_Avg():
global graph_Avg
graph_Avg=True
do_graph()
root.bind('<Key>', on_key)
myCanvas = tk.Canvas(root, width = 800, height = 500)
myCanvas.grid(row=2, column= 4)
label1 = tk.Label(root, text='MENU')
label1.config(font=('Arial', 20))
myCanvas.create_window(200, 20, window=label1)
myLine= None
graph_Avg=False
graph_past=False
label2 = tk.Label(root, font=('Courier', 15))
label2.place(relx= 0.3, rely=0.1)
B1 = tk.Button(root, text ="Option 1", font=('Courier', 12), command = flag_print)
myCanvas.create_window(200, 100, window=B1)
B2 = tk.Button(root, text ="Option 2", font=('Courier', 12), command = flag_Avg)
myCanvas.create_window(200, 140, window=B2)
root.mainloop()```
[1]: https://i.stack.imgur.com/RgL7S.png
问题
问题是由于在 graph_plot
class 的 __init__()
方法中创建了多个 FigureCanvasTkAgg
对象。此构造函数在 do_graph()
和 do_printing()
方法中调用,这意味着许多相同的 canvas 是在彼此之上创建的。这意味着当您 .destroy()
小部件时,它将破坏一个新的小部件并留下下面的小部件。
解决方案
如果您要继续使用 classes,解决方案是将更多变量提升到全局变量中,这样可以确保您处理的是相同的对象,而不是单独的对象.不过,最好重新考虑使用 classes 来解决这个问题。
代码 我重组了您的一些代码以避开 classes 并获得预期的结果:
import tkinter as tk
import matplotlib.pyplot as plt
from pandas import DataFrame
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
x_loc=[5, 6, 34, 54, 23]
y_loc=[3, 4.34, 2, 44, 65]
avgLst=[24, 35.65, 54.6, 53, 2]
GRAPH_AVG=False
GRAPH_PAST=False
MY_LINE = None
ROOT = tk.Tk()
ROOT.geometry("900x600")
FIGURE = plt.Figure()
SCATTER = FigureCanvasTkAgg(FIGURE, ROOT)
TK_WIDGET = SCATTER.get_tk_widget()
SUBPLOT = FIGURE.add_subplot(111)
SUBPLOT.set_xlabel('x location')
SUBPLOT.set_ylabel('y location')
NAME_LABEL = tk.Label(ROOT, font=('Courier', 15))
NAME_LABEL.place(relx=0.3, rely=0.1)
def display_graph():
global GRAPH_PAST, FIGURE, SUBPLOT
data1 = {'x-locations' : x_loc , 'y_locations' : y_loc}
df3 = DataFrame(data1, columns=['x-locations','y_locations'])
NAME_LABEL.config(text='')
print('graph past= ' , GRAPH_PAST)
im0= SUBPLOT.scatter(df3['x-locations'],df3['y_locations'], c=avgLst, cmap='rainbow', vmin=min(avgLst), vmax=max(avgLst))
FIGURE.colorbar(im0)
SUBPLOT.set_title('Avg')
TK_WIDGET.place(relx=0.3, rely=0.1)
GRAPH_PAST= True
def clear_graph():
global SUBPLOT, TK_WIDGET
print('Destroyed!')
SUBPLOT.clear()
TK_WIDGET.place_forget()
def on_key(event):
global MY_LINE
if MY_LINE and event.keysym != 'Return':
update_print()
def do_printing():
global MY_LINE, GRAPH_AVG, GRAPH_PAST
if GRAPH_PAST:
clear_graph()
GRAPH_PAST = False
MY_LINE = ["john kenny", "maria rose", "sheena"]
update_print()
def update_print():
NAME_LABEL.config(text=random.choice(MY_LINE))
def flag_print():
global GRAPH_AVG
GRAPH_AVG=False
do_printing()
def flag_Avg():
global GRAPH_AVG
GRAPH_AVG=True
display_graph()
ROOT.bind('<Key>', on_key)
B1 = tk.Button(ROOT, text ="Print", font=('Courier', 12), command=flag_print)
B1.place(relx=0.1, rely=0.1)
B2 = tk.Button(ROOT, text ="Graph", font=('Courier', 12), command=flag_Avg)
B2.place(relx=0.1, rely=0.2)
ROOT.mainloop()
尝试用 self.subplot1.clear()
代替 self.subplot1.destroy()