Animation with 5x5 map of cubes I am trying to learn how to animate with tkinter. The code below is an example I was able to build. It creates a small 5x5 map of cubes, then one of them randomly moves around the screen (preferably on the map, but it can wander off).

Is this a good way to do it?  Is there a more pythonic, or more efficient way of doing it?

from tkinter import *
from time import sleep
from random import randrange

class alien(object):
    def __init__(self):
        self.root = Tk()
        self.canvas = Canvas(self.root, width=400, height=400)
        self.canvas.pack()
        self.map = [[1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [1, 0, 0, 1, 0]]
        self.x = 0
        self.y = 0
        for row in range(len(self.map)):
            for column in range(len(self.map[row])):
                color = "green"
                if self.map[row][column] == 1:
                    color = "black"                
                #print(50 * row + 50, 50 * column + 50)
                self.canvas.create_rectangle(50 * row , 50 * column , 50 * row + 50, 50 * column + 50,
                    outline=color, fill=color) 
        self.creature = self.canvas.create_rectangle(50 * self.x, 50 * self.y, 50 * self.x + 50, 50 * self.y + 50,
            outline="red", fill="red")     
        self.canvas.pack(fill=BOTH, expand=1)   
        self.root.after(0, self.animation)
        self.root.mainloop()

    def animation(self):
        while True:
            i = randrange(1, 5)
            print(i)
            if i == 1:
                y = -1
            elif i == 2:
                y = 1
            elif i == 3:
                x = -1
            elif i == 4:
                x = 1
            sleep(0.025)
            print(self.x, self.y)
            self.canvas.move(self.creature, self.x, self.y)
            self.canvas.update()
alien()
Here is anoted version of your code

from tkinter import *
from time import sleep
from random import randrange

# lowercase tkinter suggest you are using python3, in this case
# inheriting (object) is not needed anymore to create newstyle
# class
class alien(object):
    def __init__(self):
        self.root = Tk()
        self.canvas = Canvas(self.root, width=400, height=400)
        self.canvas.pack()
        self.map = [[1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [1, 0, 0, 1, 0]]
        self.x = 0
        self.y = 0
        for row in range(len(self.map)):
            for column in range(len(self.map[row])):
                color = "green"
                #since 0 evaluate to False, you can drop '== 1'
                if self.map[row][column] == 1:
                    color = "black"                
                self.canvas.create_rectangle(50 * row , 50 * column , 50 * row + 50, 50 * column + 50,
                    outline=color, fill=color) 
        self.creature = self.canvas.create_rectangle(50 * self.x, 50 * self.y, 50 * self.x + 50, 50 * self.y + 50,
            outline="red", fill="red")
        #this call overrides the previous 'canvas.pack'. Remove first.
        self.canvas.pack(fill=BOTH, expand=1)   
        self.root.after(0, self.animation)
        self.root.mainloop()

    def animation(self):
        #see below for further explanations on animations.
        while True:
            i = randrange(1, 5)
            print(i)
            #note: randrange ouput from 1 to 5 (included)
            #thus i = 5 is not handled in your switch (might be on purpose)
            if i == 1:
                y = -1
            elif i == 2:
                y = 1
            elif i == 3:
                x = -1
            elif i == 4:
                x = 1
            # after you switch, either x or y (or both) are not
            # initialized
            sleep(0.025)
            # self.x and self.y are never updated
            print(self.x, self.y)
            # move is a relative command (expect delta x,delta y)
            # if self.x,self.y is your creature absolute position,
            # you might want to use 'coords' on (self.x, self.y) 
            # or 'move' on (x,y)
            # in addition, your "*50" factor has disapeared.
            self.canvas.move(self.creature, self.x, self.y)
            # it is good practice to use 'update_idletasks' instead
            # of 'update' to avoid race conditions. By the way
            # the use of one of them is seldom required (see below)
            self.canvas.update()
alien()


Regarding how you handle the animation, it could be profitable to run your simulation in the python mainloop. What you does now is to provide your own mainloop (while True: [...] sleep(0.025) [...] canvas.update()). This can work, but will fail as soon as you will want to add interactivity to your application (other widgets, or react to events on canvas). This will not work because the execution path is stuck in alien.animation. The solution there would be to rely on tkinter mainloop and to beg for alien.animation to be repeatedly called.

def animation(self):
    #while True:  no longer needed
        i = randrange(1, 5)
        #[...]
        elif i == 4:
            x = 1
        #sleep(0.025) becomes
        self.root.after(25, animation)
        print(self.x, self.y)
        self.canvas.move(self.creature, x*50, y*50)
        #self.canvas.update() no longer needed