I wrote this simple particle flow animation with Tkinter. I wanted to ask if there is some major improvements you can think of regarding the animation motor or the documentation of my code? I noticed that sometimes the "Stop animation" functionality takes some time to run but I don't know how to improve it.
This is an uni course project and later we will add some user inputs (radius and length of the pipe, pressure difference and flow liquid) and implement calculations for the speeds of the rows. Possibly changing the colour of the particles also depending on the flow liquid. This is why I'm deleting the particles and drawing them again when "Stop animation" is pressed.
Below you can see the code of my animation.
from tkinter import * size = 15 gap = 5 columns = 25 rows = 7 downspace = 40 # space for the buttons below the animation screenwidth = columns*size + (columns-2)*gap screenheight = rows*size + rows*gap + downspace color = "sky blue" xspeed = [2, 3, 4, 5, 4, 3, 2] # list for the speeds of the particle rows class Animation: """Class for the animation and buttons""" def __init__(self): """ Creates the canvas, lines, buttons and runs the mainloop of the tkinter window self.particlelist is a list for the rows of particles """ self.root = Tk() self.canvas = Canvas(self.root, width=screenwidth, height=screenheight) self.canvas.pack() self.root.title("Laminar flow in a pipe") self.canvas.create_line(0, gap, screenwidth, gap, width=2) self.canvas.create_line(0, rows*size + (rows+2)*gap, screenwidth, rows*size + (rows+2)*gap, width=2) self.particlelist =  self.stop_animation = False self.start = Button(self.root, text="Start animation", command=self.start_anim) self.start.pack() self.stop = Button(self.root, text="Stop animation", command=self.stop_anim) self.stop.pack() self.init() self.root.mainloop() def start_anim(self): """Starts the animation""" self.stop_animation = False self.start.configure(state=DISABLED) self.stop.configure(state=NORMAL) self.update() def stop_anim(self): """ Stops the animation and deletes the particles Runs the function init to draw new particles to the beginning positions """ self.stop_animation = True self.start.configure(state=NORMAL) self.stop.configure(state=DISABLED) self.update() for i in range(len(self.particlelist)): xlist = self.particlelist[i] for particle in xlist: particle.delete() self.particlelist[i] =  self.init() def init(self): """ Creates lists of particle rows and appends them to self.particlelist * ypos: vertical postition of the particle * xpos: horizontal position of the particle """ ypos = 10 for i in range(rows): xpos = 0 xlist =  for t in range(columns): xlist.append(Particle(self.canvas, xpos, ypos, color, xspeed[i])) xpos += size + gap self.particlelist.append(xlist) ypos += size + gap def update(self): """ Updates the screen * t: update interval in milliseconds """ t = 20 if self.stop_animation == False: for i in range(len(self.particlelist)): xlist = self.particlelist[i] for particle in xlist: particle.move() self.canvas.after(t, self.update) class Particle(): """ Class for particles Parameters: * canvas: canvas from the class "Animation" * xpos: x coordinate for creation of the shape * ypos: y coordinate for creation of the shape * color: fill color of the shape * xspeed: speed of the shape to the horizontal direction """ def __init__(self, canvas, xpos, ypos, color, xspeed): self.canvas = canvas self.shape = self.canvas.create_oval(xpos, ypos, xpos+size, ypos+size, fill=color) self.xspeed = xspeed def move(self): """ Function for moving the shape. * "pos" gives a vector of position [x0, y0, x1, y1] where 0 is the left upper corner and 1 is the right down corner of the shape """ self.canvas.move(self.shape, self.xspeed, 0) pos = self.canvas.coords(self.shape) if pos >= screenwidth: # returning the shape to the left side of the screen overlap = (pos - screenwidth) self.canvas.coords(self.shape, gap-size+overlap, pos, gap+overlap, pos) def delete(self): """Function for deleting the shape""" self.canvas.delete(self.shape) Animation()
Any comments are appreciated!