Created
December 25, 2024 08:35
-
-
Save zuriby/1fd156492f2b8b75597ad2f7e9502cf5 to your computer and use it in GitHub Desktop.
Mandelbrot Set Basic Viewer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# (c) copyright zuri bar yochay - [email protected] | |
import numpy as np | |
import matplotlib.pyplot as plt | |
from matplotlib.widgets import Button | |
class MandelbrotViewer: | |
def __init__(self): | |
self.max_iter = 100 | |
self.xmin, self.xmax = -2, 1 | |
self.ymin, self.ymax = -1.5, 1.5 | |
self.history = [] # Store zoom history | |
# Create the main figure and plot | |
self.fig, self.ax = plt.subplots(figsize=(10, 8)) | |
plt.subplots_adjust(bottom=0.2) # Make room for buttons | |
# Add zoom out button | |
self.bzoom_out_ax = plt.axes([0.7, 0.05, 0.1, 0.075]) | |
self.bzoom_out = Button(self.bzoom_out_ax, 'Zoom Out') | |
self.bzoom_out.on_clicked(self.zoom_out) | |
# Add reset button | |
self.breset_ax = plt.axes([0.81, 0.05, 0.1, 0.075]) | |
self.breset = Button(self.breset_ax, 'Reset') | |
self.breset.on_clicked(self.reset) | |
# Connect mouse events | |
self.fig.canvas.mpl_connect('button_press_event', self.on_click) | |
self.draw_mandelbrot() | |
def mandelbrot(self, h, w): | |
y, x = np.ogrid[self.ymin:self.ymax:h*1j, self.xmin:self.xmax:w*1j] | |
c = x + y*1j | |
z = c | |
divtime = self.max_iter + np.zeros(z.shape, dtype=int) | |
for i in range(self.max_iter): | |
z = z**2 + c | |
diverge = z*np.conj(z) > 2**2 | |
div_now = diverge & (divtime == self.max_iter) | |
divtime[div_now] = i | |
z[diverge] = 2 | |
return divtime | |
def draw_mandelbrot(self): | |
self.ax.clear() | |
h, w = 1000, 1000 | |
self.ax.imshow(self.mandelbrot(h, w), cmap='hot', extent=[self.xmin, self.xmax, self.ymin, self.ymax]) | |
self.ax.set_title(f'Mandelbrot Set (click to zoom)\nCurrent view: [{self.xmin:.3f}, {self.xmax:.3f}] x [{self.ymin:.3f}, {self.ymax:.3f}]') | |
plt.draw() | |
def on_click(self, event): | |
if event.inaxes != self.ax or event.button != 1: | |
return | |
# Store current view in history | |
self.history.append((self.xmin, self.xmax, self.ymin, self.ymax)) | |
# Calculate new boundaries (zoom by factor of 4) | |
zoom_factor = 4 | |
x, y = event.xdata, event.ydata | |
dx = (self.xmax - self.xmin) / zoom_factor | |
dy = (self.ymax - self.ymin) / zoom_factor | |
self.xmin = x - dx/2 | |
self.xmax = x + dx/2 | |
self.ymin = y - dy/2 | |
self.ymax = y + dy/2 | |
# Example: set max_iter proportional to 2000 times the zoom level | |
current_width = self.xmax - self.xmin | |
self.max_iter = int(100 / current_width) | |
self.max_iter = (self.max_iter <= 2000 and self.max_iter) or 2000 | |
print (f"current_width {current_width} max_iter {self.max_iter}") | |
self.draw_mandelbrot() | |
def zoom_out(self, event): | |
if self.history: | |
self.xmin, self.xmax, self.ymin, self.ymax = self.history.pop() | |
self.draw_mandelbrot() | |
def reset(self, event): | |
self.history = [] | |
self.xmin, self.xmax = -2, 1 | |
self.ymin, self.ymax = -1.5, 1.5 | |
self.draw_mandelbrot() | |
# Create and show the viewer | |
viewer = MandelbrotViewer() | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment