Tkinter和Pyplot内存不足 [英] Tkinter and pyplot running out of memory
问题描述
我正在运行一个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屋!