I am writing a python tkinter-based GUI that should show Matplotlib-Plots in new Windows whenever I hit a button. Plots shall be non-exclusive, I want to be able to bring up as many Plots as I would like. (Original App has more than one button, I shortened it below)
The Problem is: When I click one of my buttons the plot appears correctly. When I close the plot again the behaviour of the used button becomes spooky:
- at MacOS it appears pushed on Mouse-over
- at Windows it stays pushed for the rest of runtime
On both OS'es it keeps working perfectly fine though. Only the graphics of the button are weird after first usage. I believe it has something to do with the running plt.show() blocking the GUI framework somehow, but I can not nail it down.
class Simulator:
def __init__(self) -> None:
self.startGUI()
def startGUI(self):
self.window = tk.Tk()
frmCol2 = tk.Frame(pady=10, padx=10)
self.btnDraw = tk.Button(master = frmCol2, text="Draw Something", width=20)
self.btnDraw.grid(row = 1, column = 1)
self.btnDraw.bind("<Button-1>", self.drawSth)
frmCol2.grid(row=1, column=2, sticky="N")
self.window.mainloop()
def drawSth(self, event):
if self.btnDraw["state"] != "disabled":
self.visualizer.plotSth(self.scenario)
Plotting itself is then done by the object visualizer of the following class:
class RadarVisualizer:
def plotClutterVelocities(self, scenario):
scArray = np.array(scenario)
plt.figure()
plt.plot(scArray[:,0], scArray[:,1])
plt.title("Some Title")
plt.grid()
plt.show()
I checked the MPL Backend: It is TkAGG. I furthermore tried to put the plotting in a different thread which makes python crying a lot. It seems to expect the plots to be started in the same Thread. Maybe because the backend I am using is also Tkinter based.
CodePudding user response:
An example with many windows without plt.show(). Sample taken from here.
import tkinter as tk
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
i = 0
new_windows = []
data1 = {'country': ['A', 'B', 'C', 'D', 'E'],
'gdp_per_capita': [45000, 42000, 52000, 49000, 47000]
}
df1 = pd.DataFrame(data1)
data2 = {'year': [1920, 1930, 1940, 1950, 1960, 1970, 1980, 1990, 2000, 2010],
'unemployment_rate': [9.8, 12, 8, 7.2, 6.9, 7, 6.5, 6.2, 5.5, 6.3]
}
df2 = pd.DataFrame(data2)
data3 = {'interest_rate': [5, 5.5, 6, 5.5, 5.25, 6.5, 7, 8, 7.5, 8.5],
'index_price': [1500, 1520, 1525, 1523, 1515, 1540, 1545, 1560, 1555, 1565]
}
df3 = pd.DataFrame(data3)
def f_1(win):
global df1
figure1 = plt.Figure(figsize=(6, 5), dpi=100)
ax1 = figure1.add_subplot(111)
bar1 = FigureCanvasTkAgg(figure1, win)
bar1.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
df = df1[['country', 'gdp_per_capita']].groupby('country').sum()
df.plot(kind='bar', legend=True, ax=ax1)
ax1.set_title('Country Vs. GDP Per Capita')
def f_2(win):
global df2
figure2 = plt.Figure(figsize=(5, 4), dpi=100)
ax2 = figure2.add_subplot(111)
line2 = FigureCanvasTkAgg(figure2, win)
line2.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
df = df2[['year', 'unemployment_rate']].groupby('year').sum()
df.plot(kind='line', legend=True, ax=ax2, color='r', marker='o', fontsize=10)
ax2.set_title('Year Vs. Unemployment Rate')
def f_3(win):
global df3
figure3 = plt.Figure(figsize=(5, 4), dpi=100)
ax3 = figure3.add_subplot(111)
ax3.scatter(df3['interest_rate'], df3['index_price'], color='g')
scatter3 = FigureCanvasTkAgg(figure3, win)
scatter3.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
ax3.legend(['index_price'])
ax3.set_xlabel('Interest Rate')
ax3.set_title('Interest Rate Vs. Index Price')
def new_window():
global i
new = tk.Toplevel(root)
if i == 0:
f_1(new)
if i == 1:
f_2(new)
if i == 2:
f_3(new)
new_windows.append(new)
i = 1
if i > 2:
i = 0
root = tk.Tk()
tk.Button(root, text='new_window', command=new_window).pack()
root.mainloop()