gpt4 book ai didi

python - Tkinter plt.figure() 不绘制,但 Figure() 绘制

转载 作者:太空宇宙 更新时间:2023-11-04 02:01:47 27 4
gpt4 key购买 nike

我开始构建 Tkinter 应用程序,最初使用的是 matplotlib 的 Figurefigure.add_subplot。有了它,一切都完美无缺。对于更多自定义,我现在想移动到 pyplotsubplot2grid,但在这样做时,我的所有 tkinter 变量突然停止工作。

在我的 MWE 中,变量 gArrChoice 跟踪哪个单选按钮被选中并且应该默认为第一个选项。基于此选项,图形应绘制一条悬停在 0.1 附近的线。如果选择了第二个选项,图表应该会变为在 5 左右徘徊。图表每 2.5 秒自动更新一次。如果您注释掉“Working”下方的 3 行并改为使用 3 行“Not Working”,则变量的默认设置将停止工作并且在单选按钮之间切换将不再起作用。在 animate 函数内部声明 a 不会改变问题。

如何将 plt 与 Tkinter 一起使用而不破坏我的变量?

MWE:

import tkinter as tk
import matplotlib
matplotlib.use("TkAgg") #make sure you use the tkinter backend
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.animation as animation
import numpy as np

gArrChoice = 0

#Working - using Figure and add_subplot
from matplotlib.figure import Figure
f = Figure()
a = f.add_subplot(121)

#Not Working - using plt and subplot2grid
# from matplotlib import pyplot as plt
# f = plt.figure()
# a = plt.subplot2grid((10, 7), (0, 0), rowspan=10, colspan=5)


class BatSimGUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
self.frames = {}
frame = StartPage(container,self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame.tkraise()

class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)

#Set defaults for global variable
global gArrChoice
gArrChoice = tk.IntVar()
gArrChoice.set(1)

radioArr1 = tk.Radiobutton(self, variable=gArrChoice, text="Exponential", value=1, command= lambda: print(gArrChoice.get()))
radioArr1.grid(row=2, column=0)
radioArr2 = tk.Radiobutton(self, variable=gArrChoice, text="Normal", value=2, command= lambda: print(gArrChoice.get()))
radioArr2.grid(row=3, column=0)

#Add Canvas
canvas = FigureCanvasTkAgg(f, self)
canvas.draw()
canvas.get_tk_widget().grid(row=1, column=1, columnspan=7, rowspan = 10)

def animate(i):
global gArrChoice
if gArrChoice.get() == 1:
lam = np.random.exponential(scale=.1, size = 100).reshape(-1,1)
else:
lam = np.random.normal(loc=5, scale=1, size = 100).reshape(-1,1)

a.clear()
a.step(list(range(100)), list(lam))

#Actually run the interface
app = BatSimGUI()
app.geometry("800x600")
ani = animation.FuncAnimation(f, animate, interval = 2500)
app.mainloop()

最佳答案

我认为 OO 方法会更好。

见下文,我使用线程和队列来管理绘图动画,您甚至可以设置时间间隔并动态更改图形类型

干得不错,很有趣

#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox

import threading
import queue
import time

from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

try:
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk as nav_tool
except:
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg as nav_tool

import numpy as np


class MyThread(threading.Thread):

def __init__(self, queue, which, ops, interval):
threading.Thread.__init__(self)

self.queue = queue
self.check = True
self.which = which
self.ops = ops
self.interval = interval

def stop(self):
self.check = False

def run(self):

while self.check:

if self.which.get() ==0:
lam = np.random.exponential(scale=.1, size = 100).reshape(-1,1)
else:
lam = np.random.normal(loc=5, scale=1, size = 100).reshape(-1,1)

time.sleep(self.interval.get())
args = (lam, self.ops[self.which.get()])
self.queue.put(args)
else:
args = (None, "I'm stopped")
self.queue.put(args)

class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()

self.parent = parent

self.which = tk.IntVar()
self.interval = tk.DoubleVar()
self.queue = queue.Queue()
self.my_thread = None

self.init_ui()

def init_ui(self):

f = ttk.Frame()
#create graph!
self.fig = Figure()
self.fig.suptitle("Hello Matplotlib", fontsize=16)
self.a = self.fig.add_subplot(111)
self.canvas = FigureCanvasTkAgg(self.fig, f)
toolbar = nav_tool(self.canvas, f)
toolbar.update()
self.canvas._tkcanvas.pack(fill=tk.BOTH, expand=1)

w = ttk.Frame()

ttk.Button(w, text="Animate", command=self.launch_thread).pack()
ttk.Button(w, text="Stop", command=self.stop_thread).pack()
ttk.Button(w, text="Close", command=self.on_close).pack()

self.ops = ('Exponential','Normal',)

self.get_radio_buttons(w,'Choice', self.ops, self.which,self.on_choice_plot).pack(side=tk.TOP, fill=tk.Y, expand=0)

ttk.Label(w, text = "Interval").pack()

tk.Spinbox(w,
bg='white',
from_=1.0, to=5.0,increment=0.5,
justify=tk.CENTER,
width=8,
wrap=False,
insertwidth=1,
textvariable=self.interval).pack(anchor=tk.CENTER)

w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
f.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

def launch_thread(self):

self.on_choice_plot()

def stop_thread(self):

if self.my_thread is not None:
if(threading.active_count()!=0):
self.my_thread.stop()

def on_choice_plot(self, evt=None):

if self.my_thread is not None:

if (threading.active_count()!=0):

self.my_thread.stop()

self.my_thread = MyThread(self.queue,self.which, self.ops, self.interval)
self.my_thread.start()
self.periodiccall()

def periodiccall(self):

self.checkqueue()
if self.my_thread.is_alive():
self.after(1, self.periodiccall)
else:
pass

def checkqueue(self):
while self.queue.qsize():
try:

args = self.queue.get()
self.a.clear()
self.a.grid(True)

if args[0] is not None:
self.a.step(list(range(100)), list(args[0]))
self.a.set_title(args[1], weight='bold',loc='left')
else:
self.a.set_title(args[1], weight='bold',loc='left')

self.canvas.draw()

except queue.Empty:
pass


def get_radio_buttons(self, container, text, ops, v, callback=None):

w = ttk.LabelFrame(container, text=text,)

for index, text in enumerate(ops):
ttk.Radiobutton(w,
text=text,
variable=v,
command=callback,
value=index,).pack(anchor=tk.W)
return w


def on_close(self):

if self.my_thread is not None:

if(threading.active_count()!=0):
self.my_thread.stop()

self.parent.on_exit()

class App(tk.Tk):
"""Start here"""

def __init__(self):
super().__init__()

self.protocol("WM_DELETE_WINDOW", self.on_exit)

self.set_title()
self.set_style()

Main(self)

def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("clam")

def set_title(self):
s = "{0}".format('Simple App')
self.title(s)

def on_exit(self):
"""Close all"""
if messagebox.askokcancel("Simple App", "Do you want to quit?", parent=self):
self.destroy()

if __name__ == '__main__':
app = App()
app.mainloop()

enter image description here

关于python - Tkinter plt.figure() 不绘制,但 Figure() 绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55542813/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com