Tkinter and pyplot running out of memory
Question: 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.

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?

Thanks!

    
    
    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)
    


Answer: 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()
    

* * *

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](http://www.scipy.org/Cookbook/Matplotlib/Animations).

Technical note:

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) 
    

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

