I have a problem with working of lattice gas automata application. Well, I can't refresh the image with after() function. App's starting and nothing more happens. I've tried many combinations of using this method or any other method for repeating the automata every some time but without success. Could you help me with solving this problem?
First file:
from PIL import Image, ImageTk
import tkinter as tk
import numpy as np
import methods
class Window:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master, background="white")
self.img_matrix = np.zeros([600, 600, 3], dtype=np.uint8)
self.state_matrix = np.zeros([600, 600, 5], dtype=np.uint8)
self.img_matrix, self.state_matrix = methods.fill_matrix(self.img_matrix, self.state_matrix)
self.img = ImageTk.PhotoImage(image=Image.fromarray(self.img_matrix))
self.canvas = tk.Canvas(self.frame, width=600, height=600)
self.canvas.pack(side="left", fill="y")
self.canvas.create_image(0, 0, anchor="nw", image=self.img)
self.frame.pack()
self.master.after(1000, methods.simulate(self.canvas, self.img_matrix, self.state_matrix))
def main():
root = tk.Tk()
root.withdraw()
top = tk.Toplevel(root)
top.protocol("WM_DELETE_WINDOW", root.destroy)
app = Window(top)
top.title("LGA")
top.mainloop()
if __name__ == '__main__':
main()
and the second:
import numba
from numba import jit, njit
from PIL import Image, ImageTk
import numpy as np
import random
@jit(nopython=True, parallel=True)
def fill_matrix(img_matrix, state_matrix):
for x in numba.prange(0, state_matrix.shape[0]-1):
for y in numba.prange(0, state_matrix.shape[1]-1):
state = state_matrix[x, y]
if y == 0 or x == 0 or y == state_matrix.shape[1]-1 or x == state_matrix.shape[0]-1:
state[0] = 1
state_matrix[x, y] = state
img_matrix[x, y] = [255, 255, 255]
if y == 150 and (0 < x < (((state_matrix.shape[0]-1)/2)-25) or \
(((state_matrix.shape[0]-1)/2)+25 < x < state_matrix.shape[0]-1)):
state[0] = 1
state_matrix[x, y] = state[0]
img_matrix[x, y] = [255, 255, 255]
random_gen_1 = random.randint(0, 100)
treshold = 92
if 0 < y < 150 and 0 < x < (state_matrix.shape[0]-1) and random_gen_1 > treshold:
random_gen_2 = random.randint(1, 4)
if random_gen_2 == 1:
state[1] = 1
elif random_gen_2 == 2:
state[2] = 1
elif random_gen_2 == 3:
state[3] = 1
elif random_gen_2 == 4:
state[4] = 1
state_matrix[x, y] = state
img_matrix[x, y] = [255, 0, 0]
return img_matrix, state_matrix
def simulate(canvas, img_matrix, state_matrix):
new_state_matrix = np.zeros([state_matrix.shape[0], state_matrix.shape[1], 5], dtype=np.uint8)
new_img_matrix = np.zeros([state_matrix.shape[0], state_matrix.shape[1], 3], dtype=np.uint8)
new_state_matrix, new_img_matrix = state_sim(state_matrix, new_state_matrix, img_matrix, new_img_matrix)
img = ImageTk.PhotoImage(image=Image.fromarray(new_img_matrix))
canvas.create_image(0, 0, anchor="nw", image=img)
#return img, new_img_matrix, new_state_matrix
@jit(nopython=True, parallel=True)
def state_sim(state_matrix, new_state_matrix, img_matrix, new_img_matrix):
for x in numba.prange(0, state_matrix.shape[0]-1):
for y in numba.prange(0, state_matrix.shape[1]-1):
state = state_matrix[x, y]
if state[0] == 1:
new_state_matrix[x, y] = state_matrix[x, y] #[1, 0, 0, 0, 0]
new_img_matrix[x, y] = img_matrix[x, y] #[255, 255, 255]
else:
new_state = state
state_up = state_matrix[x - 1, y]
state_right = state_matrix[x, y + 1]
state_down = state_matrix[x + 1, y]
state_left = state_matrix[x, y - 1]
new_state_up = state_matrix[x - 1, y]
new_state_right = state_matrix[x, y + 1]
new_state_down = state_matrix[x + 1, y]
new_state_left = state_matrix[x, y - 1]
#state
if state_up[3] == 1:
new_state[1] = 1
new_state_up[3] = 0
if state_right[4] == 1:
new_state[2] = 1
new_state_right[4] = 0
if state_down[1] == 1:
new_state[3] = 1
new_state_down[1] = 0
if state_left[2] == 1:
new_state[4] = 1
new_state_left[2] = 0
if new_state[1] == 1 and new_state[3] == 1:
new_state[1] = 0
new_state[2] = 1
new_state[3] = 0
new_state[4] = 1
elif new_state[2] == 1 and new_state[4] == 1:
new_state[1] = 1
new_state[2] = 0
new_state[3] = 1
new_state[4] = 0
new_state_matrix[x, y] = new_state
if new_state[1] == 1 or new_state[2] == 1 or new_state[3] == 1 or new_state[4] == 1:
new_img_matrix[x, y] = [255, 0, 0]
return new_state_matrix, new_img_matrix
Why simulate() function doesn't repeat every some time? Thanks for the answers!
To use after, you have to pass the function reference. Let's say I have a function hi()
that just prints "hi" to the screen. If I call hi when giving arguments to after()
, then I would pass the return value of hi()
as a parameter: .after(200, hi()) # hi() is equal to None
. Instead, I should pass the reference as so: .after(200, hi)
.
However, you can't do this because you need to pass arguments to the function. To do this, you can use lambda
to create an anonimous function that calls yours with its parameters: .after(200, lambda: methods.simulate(self.canvas, self.img_matrix, self.state_matrix))
.