February 20, 2025
(This article originally appeared on Medium.)
Exploring Julia Sets with Python
In the 1990s, I was a young Gen Xer, Nirvana smelled like teen spirit, OJ Simpson pervaded the news, Seinfeld was the hottest thing on TV, and fractals were everywhere in the popular imagination — on posters, on TV, in the mountains of the latest Star Trek movie, on aspiring programmers' computer screens.
They certainly look cool, but what are fractals? The short answer is that they are mathematical shapes that exhibit self-similarity at different scales, meaning their patterns repeat infinitely in smaller and smaller versions, often resulting in complex, intricate structures. A more comprehensive answer can be found readily on the from ChatGPT, in countless books, or from many sources on the internet, including my review of “Fractals: A Very Short Introduction.”
Julia Sets
Consider the function \(z \rightarrow z^2\). Let's take a complex point, say \(z = 1 + 2i\), and iterate it over this function. We get \(1 + 2i \rightarrow 3 + 4i \rightarrow -7 - 24i \rightarrow -527 + 336i\) and so forth. Each iteration gets larger and larger and will eventually diverge to infinity. Now, let's consider \(z = i\). Its iterates are \(i \rightarrow -1 \rightarrow 1 \rightarrow 1 \rightarrow \cdots\). So the iterates of \(z = i\) converge to 1.
A similar function is \(z \rightarrow z^2 + C\) for some fixed value of \(C\). We can play the same game and see which points diverge and which ones do not. This is the idea behind the Julia set. Fix a value of \(C\) and look at the points in the complex plane. Color each point according to how quickly it escapes (or doesn't) to infinity.
Python Code
It is not too difficult to write Python code for this process. Here's an example.
import numpy as np import matplotlib.pyplot as plt def create_julia_set(C, width=800, height=800, max_iterations=256): """ Function to define the Julia set for a given constant C. """ # Define the complex plane x_axis = np.linspace(-2, 2, width) y_axis = np.linspace(-2, 2, height) x, y = np.meshgrid(x_axis, y_axis) z = x + 1j * y # Initialize an array to store the iteration counts for the Julia set. julia_set = np.zeros(z.shape, dtype=int) # Determine the iteration count for points in the plane. for i in range(max_iterations): # Throw out points that have "diverged." mask = np.abs(z) < 2 # Apply the Julia set formula. z[mask] = z[mask] ** 2 + C # Increment the iteration count for points still in the set. julia_set[mask] += 1 return julia_set def plot_julia_set(julia_set, C, figsize=(5,5)): """ Function to plot the Julia set. """ plt.figure(figsize=figsize) plt.title(f'Julia Set for c = {C.real} + {C.imag}i') plt.imshow(julia_set, cmap='inferno') plt.show() if __name__ == "__main__": # Generate the Julia set. C = complex(-0.7, 0.27015) julia_set = create_julia_set(C) # Plot the Julia set. plot_julia_set(julia_set, C)
This code block has only two functions: create_julia_set(...)
and plot_julia_set(...)
. They are both straightforward.
The function create_julia_set(...)
first defines a complex plane with the x-axis (real axis) and complex axis (y-axis) both ranging from -2 to 2. An array is then initialized to store the iteration counts (i.e., how many times a function has been iterated and not flown off to infinity). At each iteration, we knock out points that are over some threshold (we've arbitrarily chosen 2). Then the formula is applied, and iteration counts iterated. The function plot_julia_set(...) contains simple matplotlib code to get the image onto the screen.
Try the code with \(C = -0.7 + 0.27015i\). The result should be the image at the top of the article.
Explorations
Let's try some examples and see what we get.
Let \(C = -0.6–0.3i\). The result is a Julia set with a single loop.
When \(C = -1\), we get a Julia Set with (infinitely) many loops.
As \(C\) becomes larger, the set breaks up into a totally disconnected “fractal dust.”
Conclusion
I hope this article has been a fun dive into the world of fractals. We defined what Julia sets are, wrote a simple program, and then played around with different values of \(C\) to see how they shape the fractal. It is fascinating how much variety and complexity can emerge from a simple iterative process.
So, what's next? Try experimenting with different values of \(C\) and see what results you get. It's a fascinating process. Once you start, you may never stop.