Tkinter和Pyplot内存不足 [英] Tkinter and pyplot running out of memory

查看:126
本文介绍了Tkinter和Pyplot内存不足的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运行一个Tkinter脚本,该脚本每5秒更新一次绘图.它调用每5秒绘制一次的函数.不久之后,python开始使用大量内存,然后我在任务管理器中签入.内存使用量保持着非常快速的增长.它每24小时启动一个新文件,因此文件中的行数受到限制. 该文件开始为空.

I'm running a Tkinter script that updates a plot every 5 seconds. It calls the function that plots it every 5 seconds. After not that long python starts using a lot of memory, I checked in task manager. The memory usage keeps increasing really fast. It starts a new file every 24 hours so there is a limit to the number of lines in the file. The file starts empty.

我尝试增加5s的时间跨度,但它做的是相同的事情.也许慢一点 还尝试每三行绘制一次,但同样的事情再次发生.

I tried increasing the 5s time span but it does the same thing. Maybe a little slower, also tried tried plotting every 3 rows or so but the same thing happened again.

有什么想法导致如此高的内存使用以及如何解决?

Any idea what is causing such high memory usage and how to fix?

谢谢!

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)

推荐答案

从我的代码中还不清楚我的情节是如何随着时间变化的.因此,对于您现有的代码,我没有任何具体建议.但是,这是一个如何在Tkinter应用程序中嵌入动画matplotlib图形的基本示例.一旦掌握了它的工作原理,就应该能够使其适应您的情况.

It's not clear to me from your code how your plots are changing with time. So I don't have any specific suggestion for your existing code. However, here is a basic example of how to embed an animated matplotlib figure in a Tkinter app. Once you grok how it works, you should be able to adapt it to your situation.

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食谱.


The main idea here is that plt.plot should only be called once. It returns a Line2D object, line1. You can then manipulate the plot by calling line1.set_xdata and/or line1.set_ydata. This "technique" for animation comes from the Matplotlib Cookbook.

技术说明:

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

The generator function, animate was used here to allow the state of the plot to be saved and updated without having to save state information in instance attributes. Note that it is the generator function's next method (not the generator self.animate) which is being called repeatedly:

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

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

So we are advancing the plot frame-by-frame by calling the generator, self.animate()'s, next method.

这篇关于Tkinter和Pyplot内存不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆