我在使用tkinter gui时遇到了一个相当普遍的问题。我将子窗口作为子类生成,而这些子窗口使用多进程包启动具有未知时间延迟的计算量大的进程。这个计算量大的进程偶尔会将结果推入队列,该队列由图形循环使用子窗口类主进程中的matplotlib进行监视。使用多种不同的方法,这在其他环境下也可以使用,但是我一直无法让这个图表在python3.11的安装中实时更新。
我确信我使用的软件包有很多基本的东西我不理解。我基本上是一个硬件爱好者,我用自己的方式实现自我自动化(或者自我复制)我非常努力地远离Matlab和Igor,这样我就可以免费编译东西,而不必永远花时间创建自己的类。这个疯子非常感谢广大社区能给他的任何帮助,因为他是从荒野中游荡过来的。我愿意接受广泛的答案。如果最正确的答案是“学习QT 5”,我会的。我走进了死胡同。
第一种方法使用以下解:Python realtime plotting
当我直接从console运行python时,这种方法在我的python安装中工作得很好。当在spyder中启动时,由于一些已知的问题,它不工作。当我直接从console在我的类中运行它时,它崩溃了:
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
Made by Matthew Earl Wallace the Reed
"""
#import os
import time
import numpy as np
#import cv2
#import scipy as sp
import matplotlib.pyplot as plt
#import matplotlib as mpl
try:
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
except ImportError:
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk as NavigationToolbar2TkAgg
#from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
#import scipy.ndimage as nd
#from scipy.optimize import curve_fit, differential_evolution, least_squares
#import warnings
import multiprocess
#from IPython import get_ipython
#get_ipython().run_line_magic('matplotlib','qt')
#from scipy.interpolate import interp1d
#import dill
import tkinter as tk
#from tkinter import filedialog
#import glob
#import os.path
#from scipy.stats import linregress
#from scipy.stats import norm as normdist
#from copy import deepcopy
#from scipy.signal import find_peaks, peak_widths
#import matplotlib.colors as colors
#from tkinter import messagebox
#from datetime import date
#import threading as td
#import pyautogui as pg
#import multiprocessing as mp
#import time as time
from functools import partial
class trueautoLOL(tk.Toplevel):
def __init__(self,parent):
super().__init__(parent)
lengthtarget=float(tk.simpledialog.askstring('length','feed me length'))
tolerance=float(tk.simpledialog.askstring('Tolerance','Mas o menos'))
uniformitytarget=float(tk.simpledialog.askstring('Uniformity','What\'s good brother?'))
self.geometry('300x200')
self.title('I\'m a horrible window love me anyway')
q=multiprocess.Queue()
def genplot(parent):
global line,ax,canvas, fig, x,y, li
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
# some X and Y data
x = [0]
y = [0]
li, = ax2.plot(x, y,'o')
# draw and show it
fig2.canvas.draw()
plt.show(block=False)
genplot(self)
def optloop(q):
print("Istarted")
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
error=200
counter=0
while uniformity>uniformitytarget or length>lengthtarget+tolerance or length<lengthtarget-tolerance:
time.sleep(1)
theset=np.random.rand(1)*20
print(theset)
q.put(theset)
error=np.random.rand(1)*100
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
counter=counter+1
print(q)
q.put('Q')
def updateplot(q):
try:
result=q.get(False)
print(result)
if result != 'Q':
print(result)
x=[0,1,2]
y=[0,result,2]
# set the new data
li.set_xdata(x)
li.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
plt.pause(1)
updateplot(q)
else:
print('done')
except:
print("empty")
self.after(500,updateplot,q)
theprocess=multiprocess.Process(target=optloop,args=[q])
theprocess.start()
print(theprocess.is_alive())
updateplot(q)
def autoLOL():
window=tk.Tk()
window.title("LOOOL")
window.geometry('900x250')
updateLOL=tk.Button(window, text="True AutoLOL", command=partial(trueautoLOL,window))
updateLOL.grid(column=3,row=3)
window.mainloop()
if __name__=='__main__':
autoLOL()
第二种方法试图直接使用tkinter画布(这是我按时间顺序排列的第一种方法,我对上面的方法进行了修改)。
值得注意的是,这种方法是有效的,但只有当从spyder内部启动时,在bog标准的anaconda 3.9安装上安装额外的软件包w/ pip,而当从spyder启动时,在python 3.11上手动安装就不行了。
我非常想引用整个架构的来源,但我很久以前就复制过了,现在找不到了......
# -*- coding: utf-8 -*-
"""
Spyder Editor
This is a temporary script file.
Made by Matthew Earl Wallace the Reed
"""
import os
import time
import numpy as np
import cv2
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib as mpl
try:
from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg
except ImportError:
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk as NavigationToolbar2TkAgg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import scipy.ndimage as nd
from scipy.optimize import curve_fit, differential_evolution, least_squares
import warnings
import multiprocess
from IPython import get_ipython
#get_ipython().run_line_magic('matplotlib','qt')
from scipy.interpolate import interp1d
import dill
import tkinter as tk
from tkinter import filedialog
import glob
import os.path
from scipy.stats import linregress
from scipy.stats import norm as normdist
from copy import deepcopy
from scipy.signal import find_peaks, peak_widths
import matplotlib.colors as colors
from tkinter import messagebox
from datetime import date
import threading as td
import pyautogui as pg
import multiprocessing as mp
import time as time
from functools import partial
class trueautoLOL(tk.Toplevel):
def __init__(self,parent):
super().__init__(parent)
lengthtarget=float(tk.simpledialog.askstring('length','feed me length'))
tolerance=float(tk.simpledialog.askstring('Tolerance','Mas o menos'))
uniformitytarget=float(tk.simpledialog.askstring('Uniformity','What\'s good brother?'))
self.geometry('300x200')
self.title('I\'m a horrible window love me anyway')
q=multiprocess.Queue()
def genplot(parent):
global line,ax,canvas, fig
fig=mpl.figure.Figure()
ax=fig.add_subplot(1,1,1)
canvas = FigureCanvasTkAgg(fig, master=parent)
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
plt.show(block=False)
line, = ax.plot([1,2,3], [1,2,10])
genplot(self)
def optloop(q):
print("Istarted")
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
error=200
counter=0
while uniformity>uniformitytarget or length>lengthtarget+tolerance or length<lengthtarget-tolerance:
time.sleep(1)
theset=np.random.rand(1)*20
print(theset)
q.put(theset)
error=np.random.rand(1)*100
uniformity=np.random.rand(1)*100
length=np.random.rand(1)*100
counter=counter+1
print(q)
q.put('Q')
def updateplot(q):
try:
result=q.get(False)
print(result)
if result != 'Q':
print(result)
line.set_ydata(1,result,10)
ax.draw_artist(line)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
canvas.draw()
plt.show(block=False)
self.after(500,updateplot,q)
else:
print('done')
except:
print("empty")
self.after(500,updateplot,q)
theprocess=multiprocess.Process(target=optloop,args=[q])
theprocess.start()
print(theprocess.is_alive())
updateplot(q)
def autoLOL():
window=tk.Tk()
window.title("LOOOL")
window.geometry('900x250')
updateLOL=tk.Button(window, text="True AutoLOL", command=partial(trueautoLOL,window))
updateLOL.grid(column=3,row=3)
window.mainloop()
if __name__=='__main__':
autoLOL()
我尝试了多种解决方案来使用tkinter图形用户界面实时更新matplotlib绘图,其中绘图需要在无限循环中定期更新,同时由另一个进程异步提供数据。但在我的基于类的多处理架构中失败了。我对任何在1.函数调用需要在类外部定义的函数上执行; 2.一些全局变量在类外部定义用于所述函数调用;以及3.绘图更新可以周期性地发生。
我已经断断续续地做了一个月了。我唯一的目的是监视和绘制周期性输出的数据。如果这可以通过文件I/O或其他方式完成,我会做任何事情,简单或迟钝。
1条答案
按热度按时间oknwwptz1#
这主要是多处理的问题&没有完全理解matplotlib后端。基于画布的多处理方法的源代码没有使用
当multiprocess.process在pickle(或者dill'ing,就像multiprocess模块那样)的时候,它试图重新运行初始化窗口的函数,重新开始绘图等等,这让matplotlib后端很沮丧。
我开始工作的代码的版本如下: