慢速动画脚本

时间:2018-07-02 13:29:08

标签: python python-3.x animation matplotlib

我在具有高于平均水平的硬件的Windows 10 PC上使用带蜘蛛解释器的python 3.6(最新版本)并编写了脚本,使我能够在安捷伦频率计数器上连续测量和绘制两个通道的频率并将数据保存到txt文件中。我还必须将脚本转换为.exe文件(使用pyinstaller),以便将其分发到多台测量PC。

即使在.exe文件中,一切都可以正常工作,直到测量时间达到大约2000秒为止。然后该软件开始变得非常缓慢,直到它甚至显示出Windows在绘制时所做的"window not answering"事情。

我试图激活FuncAnimate的消隐功能,但是当我这样做时,它仅显示一个白色窗口。

因此,我现在正在寻找提高软件速度的选项,尤其是在高数据量的情况下,而又不减少大量数据(它们需要从t=0到{{1 }}。

为什么t=whatever会杀死我的动画?还是有更好的方法来快速重复绘制这些数据量?

我的代码:

blit=True

好的,根据要求,显示我问题的更简单的脚本:

#Importing all required additional Python packages and sub-packages/functions
import visa, time, tkinter,sys
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg as FigureCanvas
from tkinter import messagebox, filedialog
from matplotlib.figure import Figure
import matplotlib.animation as animation

#Initialize the tkinter main window (graphical user interface window)
root=tkinter.Tk()
root.geometry('1200x900')

#Initialize the VISA resource manager and define a list object
rm=visa.ResourceManager('C:\\Windows\\System32\\visa32.dll')
liste=[]

#lists all available VISA resources and adds them to the list object
#one entry per VISA instrument
string=str(rm.list_resources())[1:-1]
liste.append(string.split('\'')[1:-1])

#opens a message box for each object in the list (each instrument)
#if user chosses "yes" for a VISA resource, the software tries to access the device
#if the device is present, the for-loop is left, otherwise the whole software quits
for i in liste[0]:
    box=messagebox.askyesno('VISA Resources','Is this the correct VISA-Resource?'+'\n'+str(i))
    if box==True:
       try: inst=rm.open_resource(i)
       except:
           messagebox.showerror('Wrong Resource','The VISA resource was wrong!')
           root.destroy()
           sys.exit()
       break
    elif box==False: continue

#checks if the VISA resource is actually existent and present
try: inst
except:
    messagebox.showerror('No Resource found','No VISA Resource was chosen.')
    root.destroy()
    sys.exit()

#opens a file dialog window and safes the chosen location as "filename"
#furthermore checks if the user specified a valid path or quited by using "cancel"
#if the user clicked "cancel", the software quits
filename=filedialog.asksaveasfilename()
if len(filename)==0:
    messagebox.showerror('No File','No file location was specified.')
    root.destroy()
    sys.exit()

#definition of variables as well as the update function
x_data,y_data1, y_data2, y_data3=[],[],[],[]
def update(frame):
    #create X-data, seconds since .clock was first called                                    
    x_data.append(time.clock())                       
    #read out current freq on channel1 and float it (originaly returned as string)
    value1=float(inst.query('MEAS:FREQ? 10 MHz, 0.1 Hz, (@1)')) 
    #add data to list        
    y_data1.append(value1)     
    #define and automatically adjust subplot limits                         
    subplot1.set_ylim(min(y_data1)-1,max(y_data1)+1)         
    subplot1.set_xlim(min(x_data)-1,max(x_data)+1)
    #define subplot title and labels
    subplot1.set_title('Channel 1')
    subplot1.set_xlabel('Time')
    subplot1.set_ylabel('Frequency')
    #same as above for second channel
    value2=float(inst.query('MEAS:FREQ? 10 MHz, 0.1 Hz, (@2)'))        
    y_data2.append(value2)
    subplot2.set_ylim(min(y_data2)-1,max(y_data2)+1)
    subplot2.set_xlim(min(x_data)-1,max(x_data)+1)
    subplot2.set_title('Channel 2')
    subplot2.set_xlabel('Time')
    subplot2.set_ylabel('Frequency')
    #calculates and plots the difference of the upper two channels
    y_data3.append(value1-value2)                    
    subplot3.set_ylim(min(y_data3)-1,max(y_data3)+1)
    subplot3.set_xlim(min(x_data)-1,max(x_data)+1)
    subplot3.set_title('Difference')
    subplot3.set_xlabel('Time')
    subplot3.set_ylabel('Frequency')
    #plots the subplots in the main plot frame
    subplot1.plot(x_data,y_data1,'b')
    subplot2.plot(x_data, y_data2,'r')
    subplot3.plot(x_data, y_data3,'g')
    #writes all data do a new file defined before
    newfile.write(str(time.clock())+', '+str(value1)+', ' +str(value2)+'\n')
    #enables the code to make use of the defined variables/data
    return x_data, y_data1, y_data2, y_data3

#create a global boolean variable and set it to "True"
global boolean
boolean=True
#define a Pause function using the global boolean variable
def Pause():
    global boolean
    #if the boolean is True, the animation stops and the variable is set to False
    if boolean==True:
        anim.event_source.stop()
        boolean=False
    #if the boolean is False, the animation continues and the variable is set to True
    elif boolean==False:
        anim.event_source.start()
        boolean=True

#define a Quit function that quits the application and closes the created file
def Quit():
    newfile.close()
    root.destroy()

#define a function that applies the user input data aquisition time to the animation
def SpeedApply():
    anim.event_source.interval=int(float(Interv.get())*1000)

#create and place different buttons that call the defined functions upon buttonclick
QuitBut=tkinter.Button(text='Quit', command=Quit)
QuitBut.place(x=15,y=15)
StartBut=tkinter.Button(text='Pause/Resume',command=Pause)
StartBut.place(x=55, y=15)
Interv=tkinter.Spinbox(root,values=(0.1,0.2,0.5,1,1.5,2), width=8)
Interv.place(x=160, y=17)
Interv.delete(0,'end')
Interv.insert(0,1)
Speedbut=tkinter.Button(text='Apply Speed', command=SpeedApply)
Speedbut.place(x=250, y=15)

#create the figure needed to plot the animated data
figure=Figure(figsize=(8,8), dpi=100)
subplot1=figure.add_subplot(311)
subplot2=figure.add_subplot(312)
subplot3=figure.add_subplot(313)
figure.subplots_adjust(hspace=0.6)

#create a tkinter canvas, needed to embedd the figure into a tkinter root window
canvas=FigureCanvas(figure,root)
canvas.draw()
#canvas.start_event_loop(0.001)
canvas.get_tk_widget().place(x=25,y=50, height=850, width=1150)

#create the newfile where the data will be stored lateron
newfile=open(filename+time.strftime('%d')+time.strftime('%m')+time.strftime('%y')+'.txt','w')
newfile.write('Time, Channel 1, Channel 2\n')
#animation calling the update function upon the figure in the canvas with an interval of 1 second
anim=animation.FuncAnimation(figure,update, blit=False, interval=1000)
#tkinter mainloop, needed to react to user input in tkinter GUI
root.mainloop()

我在代码中留下了标题之类的“美丽作品”。 要真正看到我遇到的问题,您将不得不至少运行该脚本600秒钟,在2000秒钟后问题变得“更严重”。

1 个答案:

答案 0 :(得分:1)

看来,您的问题很大一部分是每次都必须重新计算整个列表的最小值和最大值,

例如您的子图x和y的最小值/最大值,而不是处理整个附加列表,您应该使用一个变量来保存最小值和最大值,到目前为止将当前输入数据与其进行比较,如果满足条件,则对其进行更新,

   subplot1.set_ylim(min(y_data1)-1,max(y_data1)+1)         
   subplot1.set_xlim(min(x_data)-1,max(x_data)+1)

您还似乎在每次更新时都要重新设置子图标签,现在我对TKinter中的GUI不太熟悉,但是我觉得可以在初始化定义中对此进行覆盖,

   subplot1.set_title('Channel 1')
   subplot1.set_xlabel('Time')
   subplot1.set_ylabel('Frequency')

第一个建议应该使您的程序在更一致的时间内运行,而不是逐渐降低运行速度,另一个建议应能够减少每次更新的工作量。