Tkinter canvas updating speed reduces during the course of a program
Question: The following python program creates a Tkinter `Canvas` object and draws
random matrix on it. It also measures the time it takes to make 10 subsequent
updates. As you may see from the output below, this time grows continiously
and substantially during the course of the program. What is the reason for
this behavior and how can I fix it?

    
    
    from Tkinter import Tk, Canvas
    import time
    import numpy as np
    
    window = Tk()
    nRows = 30
    nCols = 30
    CELL_SIZE = 10
    canvas = Canvas(window, width=CELL_SIZE*nRows,
                    height=CELL_SIZE*nCols)
    canvas.pack()
    def drawbox(m):
        for y in range(nRows):
            for x in range(nCols):
                if m[y][x]:
                    color = '#00FF00'
                else:
                    color = '#000000'
                canvas.create_rectangle(CELL_SIZE*x,
                                        CELL_SIZE*y,
                                        CELL_SIZE*x+CELL_SIZE,
                                        CELL_SIZE*y+CELL_SIZE,
                                        fill=color,
                                        outline="#000000", width=1)
    count = 0
    timeStart = time.time()
    while(True):
        board = np.random.rand(nRows, nCols) > 0.5
        if count % 10 == 0:
            print '%.1f seconds'%(time.time() - timeStart)
            timeStart = time.time()
            count = 0
        count += 1
        drawbox(board)
        canvas.after(5)
        canvas.update()
    

Here is the output

    
    
    0.0 seconds
    1.7 seconds
    4.1 seconds
    6.3 seconds
    8.7 seconds
    


Answer: Every time `drawbox` is called in your program, you're creating a new set of
rectangles and then drawing them on top of the old rectangles. As time goes
on, you're drawing more and more rectangles (even though it doesn't look like
it since the new rectangles are being drawn above the old ones). Also note
that with the way your program is written, you're bleeding memory.

The way to fix this is to create the rectangles on the first go-around and
then update them on the subsequent passes using
`canvas.itemconfig(rectangle_id,fill=color)`. I've posted an (ugly)
modification to your `drawbox` below which accomplishes this.

    
    
    def drawbox(m,_rectangles={}):
        if(_rectangles):
            myrectangles=_rectangles
        else:
            myrectangles={}
    
        for y in range(nRows):
            for x in range(nCols):
                if m[y][x]:
                    color = '#00FF00'
                else:
                    color = '#000000'
                if(not _rectangles):
                    cid=canvas.create_rectangle(CELL_SIZE*x,
                                                CELL_SIZE*y,
                                                CELL_SIZE*x+CELL_SIZE,
                                                CELL_SIZE*y+CELL_SIZE,
                                                fill=color,
                                                outline="#000000", width=1)
                    myrectangles[(y,x)]=cid
                else:
                    canvas.itemconfig(_rectangles[(y,x)],fill=color)
    
        if(not _rectangles):
          _rectangles.update(myrectangles)
    

