import tkinter as tk from tkinter import ttk from PIL import Image, ImageTk import threading import numpy as np import generate # your mandelbrot_numba / generate_mandelbrot module class MandelbrotApp: def __init__(self, root): self.root = root self.root.title("Mandelbrot Viewer") self.frame = ttk.Frame(root) self.frame.pack(fill=tk.BOTH, expand=True) self.canvas = tk.Canvas(self.frame, bg="black", scrollregion=(0, 0, 2000, 2000)) self.hbar = ttk.Scrollbar(self.frame, orient=tk.HORIZONTAL, command=self.canvas.xview) self.vbar = ttk.Scrollbar(self.frame, orient=tk.VERTICAL, command=self.canvas.yview) self.canvas.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set) self.hbar.pack(side=tk.BOTTOM, fill=tk.X) self.vbar.pack(side=tk.RIGHT, fill=tk.Y) self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # Mandelbrot view window self.xmin, self.xmax = -2.0, 1.0 self.ymin, self.ymax = -1.5, 1.5 self.zoom_factor = 1.0 self.image_on_canvas = None self.render_image() # Mouse bindings self.canvas.bind("", self.zoom) self.canvas.bind("", self.drag_start) self.canvas.bind("", self.drag_motion) def render_image(self): width, height = 800, 600 max_iter = 200 def render_task(): # Generate the Mandelbrot array img_array = generate.generate_mandelbrot( self.xmin, self.xmax, self.ymin, self.ymax, width, height, max_iter ) # Convert NumPy array to RGB image img_rgb = np.zeros((height, width, 3), dtype=np.uint8) img_rgb[:, :, 0] = img_array % 256 img_rgb[:, :, 1] = (img_array * 2) % 256 img_rgb[:, :, 2] = (img_array * 3) % 256 # Convert NumPy array → PIL Image → ImageTk.PhotoImage img = Image.fromarray(img_rgb) self.tk_img = ImageTk.PhotoImage(img) # Update canvas self.canvas.delete("all") self.image_on_canvas = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_img) self.canvas.config(scrollregion=(0, 0, width, height)) threading.Thread(target=render_task, daemon=True).start() def zoom(self, event): zoom_amount = 0.9 if event.delta > 0 else 1.1 self.zoom_factor *= zoom_amount center_x = (self.xmin + self.xmax) / 2 center_y = (self.ymin + self.ymax) / 2 width = (self.xmax - self.xmin) * zoom_amount height = (self.ymax - self.ymin) * zoom_amount self.xmin, self.xmax = center_x - width / 2, center_x + width / 2 self.ymin, self.ymax = center_y - height / 2, center_y + height / 2 self.render_image() def drag_start(self, event): self.last_x, self.last_y = event.x, event.y def drag_motion(self, event): dx = event.x - self.last_x dy = event.y - self.last_y x_shift = (self.xmax - self.xmin) * dx / 800 y_shift = (self.ymax - self.ymin) * dy / 600 self.xmin -= x_shift self.xmax -= x_shift self.ymin += y_shift self.ymax += y_shift self.last_x, self.last_y = event.x, event.y self.render_image() if __name__ == "__main__": root = tk.Tk() app = MandelbrotApp(root) root.mainloop()