Created
January 5, 2025 09:41
-
-
Save Nick3523/3dee47c35441b5372d6435b272400f95 to your computer and use it in GitHub Desktop.
Random simulation of fractales using pyfracgen
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
#!/usr/bin/env python | |
# coding: utf-8 | |
import pyfracgen as pf | |
import numpy as np | |
from matplotlib import pyplot as plt | |
import random | |
from pathlib import Path | |
import time | |
import itertools as itt | |
from matplotlib import cm | |
# Function to generate random bounds | |
def random_bounds(): | |
center_x = random.uniform(0.3602404434376143632361252444495 - 0.00000000000003, 0.3602404434376143632361252444495 + 0.00000000000025) | |
center_y = random.uniform(-0.6413130610648031748603750151793 - 0.00000000000006, -0.6413130610648031748603750151793 + 0.00000000000013) | |
zoom = random.uniform(0.005, 2) | |
width = random.uniform(0.5, 1.5) / zoom | |
height = random.uniform(0.5, 1.5) / zoom | |
return ( | |
(center_x - width/2, center_x + width/2), | |
(center_y - height/2, center_y + height/2) | |
) | |
# List of available colormaps | |
colormaps = [ | |
"viridis", "plasma", "inferno", "magma", "cividis", "Greys", "Purples", "Blues", | |
"Greens", "Oranges", "Reds", "YlOrBr", "YlOrRd", "OrRd", "PuRd", "RdPu", "BuPu", | |
"GnBu", "PuBu", "YlGnBu", "PuBuGn", "BuGn", "YlGn", "PiYG", "PRGn", "BrBG", | |
"PuOr", "RdGy", "RdBu", "RdYlBu", "RdYlGn", "Spectral", "coolwarm", "bwr", | |
"seismic", "Pastel1", "Pastel2", "Paired", "Accent", "Dark2", "Set1", "Set2", | |
"Set3", "tab10", "tab20", "tab20b", "tab20c", "flag", "prism", "ocean", | |
"gist_earth", "terrain", "gist_stern", "gnuplot", "gnuplot2", "CMRmap", | |
"cubehelix", "brg", "hsv", "gist_rainbow", "rainbow", "jet", "nipy_spectral", | |
"gist_ncar" | |
] | |
def get_colormap(): | |
return plt.get_cmap(random.choice(colormaps)) | |
# In the context of generating the Mandelbrot set, transforming each point refers to iteratively applying a mathematical function to each point in the complex plane to determine whether it belongs to the Mandelbrot set. Here's a step-by-step explanation of why and how this transformation is done: | |
# | |
# Step-by-Step Explanation | |
# Complex Plane Representation: | |
# | |
# The Mandelbrot set is defined in the complex plane, where each point represents a complex number ( c = x + yi ) (with ( x ) and ( y ) being real numbers and ( i ) being the imaginary unit). | |
# Initial Setup: | |
# | |
# For each point ( c ) in the complex plane, we start with an initial value ( z_0 = 0 ). | |
# Iterative Transformation: | |
# | |
# We iteratively apply the transformation function ( z_{n+1} = z_n^2 + c ) (or a more general form ( z_{n+1} = f(z_n, c) )) to each point. | |
# Here, ( z_n ) is the value of the complex number after ( n ) iterations. | |
# Escape Condition: | |
# | |
# After each iteration, we check the magnitude (absolute value) of ( z_n ). If ( |z_n| ) exceeds a certain threshold (commonly 2), the point ( c ) is considered to escape to infinity, and it is not part of the Mandelbrot set. | |
# If the point does not escape after a predefined number of iterations (e.g., 5000), it is considered to be part of the Mandelbrot set. | |
# Color Mapping: | |
# | |
# Points that escape are colored based on the number of iterations it took for them to escape. This creates the fractal's intricate and colorful boundary. | |
# Points that do not escape are typically colored black. | |
# Why Transform Each Point? | |
# Determine Membership: | |
# | |
# The iterative transformation helps determine whether each point ( c ) belongs to the Mandelbrot set or not. | |
# Fractal Boundary: | |
# | |
# The boundary of the Mandelbrot set is where the interesting fractal patterns emerge. The iterative process reveals these patterns by showing how quickly points escape to infinity. | |
def generate_and_save_images(n): | |
"""Generate `n` random Mandelbrot images.""" | |
current_time = time.strftime("%Y%m%d_%H%M%S") | |
for i in range(n): | |
xbound = ( | |
0.3602404434376143632361252444495 - 0.00000000000003, | |
0.3602404434376143632361252444495 + 0.00000000000025, | |
) | |
ybound = ( | |
-0.6413130610648031748603750151793 - 0.00000000000006, | |
-0.6413130610648031748603750151793 + 0.00000000000013, | |
) | |
xbound, ybound = random_bounds() | |
res = pf.mandelbrot( | |
xbound, ybound, pf.funcs.power, width=4, height=4, dpi=300, maxiter=5000 | |
) | |
filename = f"{current_time}_{i}.png" | |
stacked = pf.images.get_stacked_cmap(get_colormap(), 50) | |
pf.images.image(res, cmap=stacked, gamma=0.8) | |
plt.savefig("mandelbrot/"+filename) | |
plt.clf() # Clear the current figure to avoid overlapping images | |
def get_colormap_julia(): | |
"""Get a random colormap for the animation.""" | |
colormaps = [cm.viridis, cm.plasma, cm.inferno, cm.magma, cm.cividis] | |
return random.choice(colormaps) | |
def generate_random_julia_animation(n): | |
"""Generate `n` random Julia animations.""" | |
output_dir = Path("julia") | |
output_dir.mkdir(exist_ok=True) | |
for i in range(n): | |
# Generate random bounds and parameters | |
xbound = (-random.uniform(0.5, 2), random.uniform(0.5, 2)) | |
ybound = (-random.uniform(0.5, 2), random.uniform(0.5, 2)) | |
maxiter = random.randint(200, 400) | |
width = 5 | |
height = 4 | |
dpi = 200 # Reduced to avoid excessive memory usage | |
reals = itt.chain(np.linspace(-1, 2, 60)[0:-1], np.linspace(2, 3, 40)) | |
series = pf.julia( | |
(complex(real, random.uniform(0.5, 1.5)) for real in reals), | |
xbound=xbound, | |
ybound=ybound, | |
update_func=pf.funcs.magnetic_2, | |
maxiter=maxiter, | |
width=width, | |
height=height, | |
dpi=dpi, | |
) | |
output_file = output_dir / f"julia_animation4_{i + 1}.gif" | |
pf.images.save_animation( | |
list(series), | |
cmap=get_colormap(), | |
gamma=random.uniform(0.5, 1.0), | |
file=output_file, | |
) | |
print(f"Generated animation {i + 1} at {output_file}") | |
def get_colormap_lyapunov(): | |
"""Get a random colormap.""" | |
colormaps = [cm.viridis, cm.plasma, cm.inferno, cm.magma, cm.cividis] | |
return random.choice(colormaps) | |
def generate_random_lyapunov_images(n): | |
"""Generate `n` random Lyapunov fractal images.""" | |
output_dir = Path("lyapunov_images") | |
output_dir.mkdir(exist_ok=True) | |
for i in range(n): | |
# Generate random sequence string (A and B of random lengths) | |
string = "".join(random.choice("AB") for _ in range(random.randint(10, 20))) | |
# Generate random bounds | |
xbound = (random.uniform(2.5, 3.0), random.uniform(3.0, 3.5)) | |
ybound = (random.uniform(3.4, 3.6), random.uniform(3.6, 4.0)) | |
# Generate random image parameters | |
width = 4 | |
height = 5 | |
dpi = 300 # Reduced to avoid excessive memory usage | |
ninit = random.randint(1000, 2000) | |
niter = random.randint(1000, 2000) | |
# Generate the Lyapunov fractal | |
res = pf.lyapunov( | |
string, xbound, ybound, width=width, height=height, dpi=dpi, ninit=ninit, niter=niter | |
) | |
# Save the image | |
output_file = output_dir / f"lyapunov_image_{i + 1}.png" | |
pf.images.markus_lyapunov_image( | |
res, get_colormap(), get_colormap(), gammas=(random.uniform(5, 10), random.uniform(0.5, 2)) | |
) | |
plt.savefig(output_file, dpi=dpi) | |
plt.clf() # Clear the figure for the next image | |
print(f"Generated Lyapunov image {i + 1} at {output_file}") | |
def generate_random_buddhabrot_images(n): | |
"""Generate `n` random Buddhabrot images.""" | |
output_dir = Path("buddhabrot_images") | |
output_dir.mkdir(exist_ok=True) | |
for i in range(n): | |
# Generate random bounds and parameters | |
xbound = ( | |
-random.uniform(1.5, 2.0), | |
random.uniform(0.5, 1.0), | |
) | |
ybound = ( | |
-random.uniform(1.0, 1.5), | |
random.uniform(1.0, 1.5), | |
) | |
ncvals = random.randint(1_000_000, 10_000_000) # Number of c-values | |
maxiters = ( | |
random.randint(50, 200), | |
random.randint(200, 500), | |
random.randint(500, 1500), | |
) | |
width = 4 | |
height = 3 | |
dpi = 300 # Reduced to avoid excessive memory usage | |
horizon = random.uniform(1.0e5, 1.0e6) | |
# Generate the Buddhabrot | |
res = pf.buddhabrot( | |
xbound, | |
ybound, | |
ncvals=ncvals, | |
update_func=pf.funcs.power, | |
horizon=horizon, | |
maxiters=maxiters, | |
width=width, | |
height=height, | |
dpi=dpi, | |
) | |
# Save the image | |
output_file = output_dir / f"buddhabrot_image_{i + 1}.png" | |
pf.images.nebula_image(tuple(res), gamma=random.uniform(0.3, 0.6)) # Adjust gamma for variation | |
plt.savefig(output_file, dpi=dpi) | |
plt.clf() # Clear the figure for the next image | |
print(f"Generated Buddhabrot image {i + 1} at {output_file}") | |
#Run : | |
generate_and_save_images(100) | |
generate_random_lyapunov_images(100) | |
generate_random_buddhabrot_images(100) | |
generate_random_julia_animation(100) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment