My code generates an image as a numpy array, and then displays it in a canvas object. I use matplotlib for debugging and when when display the matplotlib window, it seems to work correctly.
However, when I close the matplotlib window, the image object is cleared and becomes fully white.
You can see with both windows open the canvas is correctly displayed. However when closing the matplotlib window, it becomes fully white.
Note: I've tried completely removing the matplotlib calls, and now the image is always white and never displays anything.
from skimage.draw import polygon
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
import tkinter as tk
import numpy as np
def generate():
# clear canvas
canvas.delete("all")
# make clean array
img = np.ones((width, height, 3), dtype=np.float32) * 0.75
# randomly generate positions
x_generated = np.random.uniform(0, width, 5)
y_generated = np.random.uniform(0, height, 5)
for x, y in zip(x_generated, y_generated):
base_height = 70
base_width = 70
# generate the corners
x0 = x - base_width/2
x1 = x + base_width/2
y0 = y - base_height/2
y1 = y + base_height/2
# create rectangle
poly = np.array((
(x0, y0),
(x1, y0),
(x1, y1),
(x0, y1),
))
rr, cc = polygon(poly[:, 0], poly[:, 1], img.shape)
img[rr, cc, :] = 0.5
# # canvas method. I don't want to use this!
# canvas.create_rectangle(x0, y0, x1, y1, fill="red", outline="")
# display generated image in tkinter canvas
scaled_to_8bit = img * 255
newarr = scaled_to_8bit.astype(np.uint8)
imgarray = ImageTk.PhotoImage(image=Image.fromarray(newarr, 'RGB'))
# create the canvas image object from the numpy array
canvas.create_image(20, 20, anchor="nw", image=imgarray)
# display pixel data for debugging
plt.imshow(img)
plt.show()
if __name__ == "__main__":
width = 1000
height = 1000
# Create a root window
root = tk.Tk()
root.configure(background="green")
# Create a canvas widget
canvas = tk.Canvas(root, width=width, height=height)
canvas.pack()
# Create a button widget
button = tk.Button(root, text="Generate", command=generate)
button.pack()
# start main tk loop
root.mainloop()
The issue was that when the matplotlib window is closed, the canvas loses the reference to the image, and so the canvas is updated and its blank.
I used a class to organise the code and allow for the reference to the image to be stored nicely
from skimage.draw import polygon
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
import tkinter as tk
import numpy as np
class Application:
def __init__(self):
print("init")
self.width = 1000
self.height = 1000
# Create a root window
root = tk.Tk()
root.configure(background="green")
# Create a canvas widget
self.canvas = tk.Canvas(root, width=self.width, height=self.height)
self.canvas.pack()
# Create a button widget
button = tk.Button(root, text="Generate", command=self.generate)
button.pack()
# start main tk loop
root.mainloop()
def generate(self):
# clear canvas
self.canvas.delete("all")
# make clean array
self.img = np.ones((self.width, self.height, 3), dtype=np.float32) * 0.75
# randomly generate positions
x_generated = np.random.uniform(0, self.width, 5)
y_generated = np.random.uniform(0, self.height, 5)
for x, y in zip(x_generated, y_generated):
base_height = 70
base_width = 70
# generate the corners
x0 = x - base_width/2
x1 = x + base_width/2
y0 = y - base_height/2
y1 = y + base_height/2
# create rectangle
poly = np.array((
(x0, y0),
(x1, y0),
(x1, y1),
(x0, y1),
))
rr, cc = polygon(poly[:, 0], poly[:, 1], self.img.shape)
self.img[rr, cc, :] = 0.5
# # canvas method. I don't want to use this!
# canvas.create_rectangle(x0, y0, x1, y1, fill="red", outline="")
# display generated image in tkinter canvas
scaled_to_8bit = self.img * 255
self.img_8bit = scaled_to_8bit.astype(np.uint8)
self.photoimage = ImageTk.PhotoImage(image=Image.fromarray(self.img_8bit, 'RGB'))
# create the canvas image object from the numpy array
self.canvas.create_image(0, 0, anchor="nw", image=self.photoimage)
# display pixel data for debugging
plt.imshow(self.img_8bit)
plt.show()
if __name__ == "__main__":
print("start")
app = Application()