Tkinter和pyplot耗尽内存

时间:2012-12-21 22:08:47

标签: python memory matplotlib tkinter

我正在运行一个Tkinter脚本,每5秒更新一次。它调用每5秒绘制一次的函数。在没有那么长的python开始使用大量内存之后,我检查了任务管理器。内存使用量持续增长非常快。它每24小时启动一个新文件,因此文件中的行数有限制。 该文件开始为空。

我尝试增加5s的时间跨度,但它做同样的事情。也许有点慢, 也尝试过每隔3行左右绘制一次,但同样的事情又发生了。

知道导致如此高内存使用率的原因以及如何修复?

谢谢!

data = np.genfromtxt(filename)

time_data = data[:,0]
room_temp_data_celsius = data[:,1]
rad_temp_data_celsius = data[:,2]
fan_state_data = data[:,3]
threshold_data = data[:,4]
hysteresis_data = data[:,5]

threshold_up = [] #empty array
threshold_down = []#empty array

for i in range(0,len(threshold_data)):
    threshold_up.append(threshold_data[i]+hysteresis_data[i])
    threshold_down.append(threshold_data[i]-hysteresis_data[i])

# Time formatting
dts = map(datetime.datetime.fromtimestamp, time_data)

fds = matplotlib.dates.date2num(dts)

hfmt = matplotlib.dates.DateFormatter('%H:%M')

# Temperature conversion
room_temp_data_fahrenheit = map(celsius_to_fahrenheit, room_temp_data_celsius)
rad_temp_data_fahrenheit = map(celsius_to_fahrenheit, rad_temp_data_celsius)
threshold_data_fahrenheit = map(celsius_to_fahrenheit, threshold_data)
threshold_up_fahrenheit = map(celsius_to_fahrenheit, threshold_up)
threshold_down_fahrenheit = map(celsius_to_fahrenheit, threshold_down)


f = plt.figure()
a = f.add_subplot(111)

a.plot(fds,room_temp_data_fahrenheit, fds, rad_temp_data_fahrenheit, 'r')
a.plot(fds,fan_state_data*(max(rad_temp_data_fahrenheit)+4),'g_')
a.plot(fds, threshold_up_fahrenheit, 'y--') 
a.plot(fds, threshold_down_fahrenheit, 'y--')

plt.xlabel('Time (min)')
plt.ylabel('Temperature '+unichr(176)+'F')
plt.legend(["Room Temperature","Radiator","Fan State","Threshold Region"], loc="upper center", ncol=2)
plt.ylim([min(room_temp_data_fahrenheit)-5, max(rad_temp_data_fahrenheit)+5])
plt.grid()


a.xaxis.set_major_formatter(hfmt)


data_graph = FigureCanvasTkAgg(f, master=root)
data_graph.show()
data_graph.get_tk_widget().grid(row=6,column=0, columnspan=3)    
root.after(WAIT_TIME, control)

1 个答案:

答案 0 :(得分:0)

我的代码并不清楚你的情节是如何随时间变化的。所以我对您现有的代码没有任何具体建议。但是,这是一个如何在Tkinter应用程序中嵌入动画matplotlib图形的基本示例。一旦你弄清楚它是如何工作的,你应该能够适应你的情况。

import matplotlib.pyplot as plt
import numpy as np
import Tkinter as tk
import matplotlib.figure as mplfig
import matplotlib.backends.backend_tkagg as tkagg
pi = np.pi
sin = np.sin

class App(object):
    def __init__(self, master):
        self.master = master
        self.fig = mplfig.Figure(figsize = (5, 4), dpi = 100)
        self.ax = self.fig.add_subplot(111)
        self.canvas = canvas = tkagg.FigureCanvasTkAgg(self.fig, master)
        canvas.get_tk_widget().pack(side = tk.TOP, fill = tk.BOTH, expand = 1)
        self.toolbar = toolbar = tkagg.NavigationToolbar2TkAgg(canvas, master)
        toolbar.update()
        self.update = self.animate().next
        master.after(10, self.update) 
        canvas.show()

    def animate(self):
        x = np.linspace(0, 6*pi, 100)
        y = sin(x)
        line1, = self.ax.plot(x, y, 'r-')
        phase = 0
        while True:
            phase += 0.1
            line1.set_ydata(sin(x + phase))
            newx = x+phase
            line1.set_xdata(newx)
            self.ax.set_xlim(newx.min(), newx.max())
            self.ax.relim()
            self.ax.autoscale_view(True, True, True) 
            self.fig.canvas.draw()
            self.master.after(10, self.update) 
            yield

def main():
    root = tk.Tk()
    app = App(root)
    tk.mainloop()

if __name__ == '__main__':
    main()

这里的主要想法是plt.plot只应该调用一次。它返回Line2D个对象line1。然后,您可以通过调用line1.set_xdata和/或line1.set_ydata来操纵图表。这种动画“技术”来自Matplotlib Cookbook

技术说明:

此处使用生成器函数animate来保存和更新绘图的状态,而无需在实例属性中保存状态信息。请注意,重复调用的是生成器函数的next方法(而不是生成器self.animate):

    self.update = self.animate().next
    master.after(10, self.update) 

因此,我们通过调用生成器self.animate()的下一个方法逐帧推进绘图。