python - 如何从 Tkinter 框架中正确删除图形
问题描述
我有几个要在按下按钮时显示的图表。为此,我将plt.Figure
andFigureCanvasTkAgg
变量设置为全局变量,并且每次按下按钮时只需擦除轴ax.clear()
。之后,我使用Figure.canvas.mpl_connect
: 添加了一个功能,当我按下图形区域时,第二个点以垂直线突出显示。当我打印一些简单的输出(在我的例子中,print('Vertical Line Constructed')
在select_trade_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_connect()
只需在开始时使用一次,而不是在清除图表时一次又一次地使用。
或者您必须保留click_id
全局变量并mpl_disconnect(click_id)
在之前使用click_id = mpl_connect()
我在开始时创建全局变量click_id = None
,稍后如果不是,construct_graph()
我将删除以前的变量。这种方式图只分配了一个功能click_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()
推荐阅读
- image-processing - 从 USB 摄像头读取嵌入式人脸检测数据
- java - 需要在children实体中定义command handler和EventSourcingHandler
- mysql - 如何在 mysql tableTHEN 限制中对所有列进行排序
- java - 当我使用 Epsilon GC 时,我无法使用 Flight Recorder
- javascript - 使用 require 在另一个文件中访问 Node.js 中立即调用的函数表达式变量
- python - 如何根据空值在python中删除行
- javascript - Collapsible 或 Accordion 哪个更适合隐藏答案?
- php - 数组到字符串的转换 SOAP
- android - 将在 Android 手机上“执行”短信的链接
- graphql - 在 GraphQL 中传递变量