An in-depth look at the fascinating features of the Mandelbrot set, the most famous fractal in mathematics.
Author
Shourya Eaga
Published
November 22, 2025
1 Introduction to the Mandelbrot Set
Before thinking about what different parts of the Mandelbrot set may mean, what exactly is the Mandelbrot set? The most concise definition is that which Wikipedia gives:
“The Mandelbrot set is a two-dimensional set that is defined in the complex plane as the complex numbers \(c\) for which the function \(f_c(z) = z^2+ c\) does not diverge to infinity when iterated starting at \(z=0\)” (Wikipedia contributors, n.d.)
But what does this exactly mean?
This means that if you take a complex number \(c\) of the form \(a+bi\) and let \(z_0=0\), and define \(z_{n+1}=z_{n}^2+c\) and repeatedly iterate through this iterative formula, you have two possible options - it “blows up” to infinity, or it remains stable. Here is an example (where \(c\) is a real number) when \(c=-1\)
Looking at the magnitudes1 of the complex numbers, we see that they diverge to infinity again, concluding that \(c=1+i\)is again outside the Mandelbrot set.
For what this would look like on the complex plane, where points in the Mandelbrot set are in black, and points outside the Mandelbrot set are in white, see Figure 1
Code
import numpy as npimport matplotlib.pyplot as pltdef complex_matrix(xmin, xmax, ymin, ymax, pixel_per_unit_width, pixels_per_unit_height): re = np.linspace(xmin, xmax, int((xmax-xmin)*pixel_per_unit_width)) im = np.linspace(ymin, ymax, int((ymax-ymin)*pixels_per_unit_height))return re[np.newaxis, :] +1j* im[:, np.newaxis]def mandelbrot(C, max_iter): Z = np.zeros(C.shape, dtype=complex) mask = np.ones(C.shape, dtype=bool)for i inrange(max_iter): Z = Z*Z + C mask &= np.abs(Z) <=2return maskC = complex_matrix(-2, 1, -1.5, 1.5, 300, 300)mandelbrot_set = mandelbrot(C, 50)plt.xlabel('Real')plt.ylabel('Imaginary')plt.imshow(mandelbrot_set, extent=[-2,1,-1.5,1.5], cmap='binary')
Figure 1: Mandelbrot set on the complex plane
Here we see the most famous fractal in mathematics - the Mandelbrot set, which we found by a simple mathematical rule. The axes on Figure 1 denote the real and imaginary parts of the complex number \(c=a+bi\) where \(a\) is the real value on the x axis and \(b\) is the imaginary value on the y axis .
2 The Bulbs
2.1 The Bifurcation of the Quadratic Map
The Bifurcation diagram of the Quadratic Map and the Mandelbrot set are linked and correspond to each other and the Quadratic Map is defined as: \[x_{n+1}=x_n^2+c\]
But what is a bifurcation diagram of the Quadratic Map?
It shows how the long term behaviour of a system changes as a parameter is adjusted in the quadratic map.
Let’s take a value for \(c\) like \(c=0.2\) and look at its long term behaviour.
Here, we see the values converging to a single point at approximately 0.2764 which is called a fixed point. Taking a different value for \(c\) like \(c=0.5\) we see a different behaviour: \[
\begin{aligned}
x_0&=0 \\
x_1&=0^2+0.5 &&=0.5 \\
x_2&=0.5^2+0.5 &&=0.75 \\
x_3&=0.75^2+0.5 &&=1.0625 \\
x_4&=1.0625^2+0.5 &&=1.6289 \\
x_5&=1.6289^2+0.5 &&=3.1555 \\
\end{aligned}
\]
Here, we see the values diverging to infinity, indicating that for \(c=0.5\), the system does not settle into a fixed point.
We can also do this for negative numbers like \(c=-1\): \[
\begin{aligned}
x_0&=0 \\
x_1&=0^2-1 &&=-1 \\
x_2&=-1^2-1 &&=0 \\
x_3&=0^2-1 &&=-1 \\
\end{aligned}
\]
We can clearly see that the values cycle between -1 and 0, showcasing the behaviour of a period-2 cycle.
2.2 Bifurcation Diagram
The values of \(c\) that do not escape to infinity are exactly between -2 and 0.25. Plotting the long term behaviour of the quadratic map gives us the bifurcation diagram, which is shown in Figure 2.
Code
P = np.linspace(-2, 1, 600)X = []Y = []for u in P: point =0+ ufor i inrange(600): point = point**2+ uifabs(point) >2:breakelse: points = []for i inrange(100): point = point**2+ u new_point =round(point, 3)if new_point notin points: points.append(new_point) X.append([u] *len(points)) Y.append(points)X= [item for sublist in X for item in sublist]Y= [item for sublist in Y for item in sublist]plt.scatter(X, Y, s=0.1, color='red')plt.show()
Figure 2: Bifurcation diagram of the quadratic map
The y values represent the long term values of \(x_n\) for each corresponding \(c\) value on the x axis. For example, at \(c=-1\), we see two points at y=-1 and y=0, representing the period-2 cycle we observed earlier. Similarly, at \(c=0.2\), we see a single point around y=0.2764, representing the fixed point we calculated.
2.3 Comparison with the Mandelbrot set
Now, if we overlay the bifurcation diagram on top of the Mandelbrot set as shown in Figure 3, we can see that the bulbs of the Mandelbrot set correspond to the stable regions in the bifurcation diagram.
Code
plt.imshow(mandelbrot_set, extent=[-2,1,-1.5,1.5], cmap='binary')plt.scatter(X, Y, s=0.01, alpha=0.5, color='red')plt.show()
Figure 3: Mandelbrot set with bifurcation diagram overlay
2.4 How do they correspond?
The individual bulbs in the mandelbrot set correspond to regions of stability. They also correspond to parameters of \(c\) where a specific period cycle is attracting. For example, the largest bulb at the centre of the set corresponds to fixed points, and the smaller bulbs to the left correspond to period-2, period-4 cycles, and so on. Also, you can see the Feigenbaum point at \(c \approx -1.401155\) where the period-doubling bifurcations accumulate, and chaos begins. This is where the orbit becomes chaotic, and there are no stable cycles, except for some periodic windows like around \(c \approx -1.75\), where you can see a period-3 cycle emerging. These period windows reveal some smaller minibrots in the Mandelbrot set, and you can see that there are a lot of them as you zoom in closer to the boundary of the Mandelbrot set.
2.5 Visualisation of the period cycles
Code
mutable x_centre =-0.5;mutable y_centre =0.0;mutable centre_x_pixel =0;mutable centre_y_pixel =0;viewof mandelbrotPlot = {const xmin =-2, xmax =1;const ymin =-1.5, ymax =1.5;const pixelPerUnitWidth =250;const pixelPerUnitHeight =250;const maxIter =50;const width =Math.floor((xmax - xmin) * pixelPerUnitWidth);const height =Math.floor((ymax - ymin) * pixelPerUnitHeight);const canvas = DOM.canvas(width, height);const ctx = canvas.getContext("2d");const image = ctx.createImageData(width, height); canvas.addEventListener("click", (event) => {const rect = canvas.getBoundingClientRect();const x =event.clientX- rect.left;const y =event.clientY- rect.top;const cr = xmin + (x / width) * (xmax - xmin);const ci =-ymin - (y / height) * (ymax - ymin); mutable x_centre = cr; mutable y_centre = ci; mutable centre_x_pixel = x; mutable centre_y_pixel = y; });// compute mandelbrotfor (let y =0; y < height; y++) {const ci = ymin + (y / height) * (ymax - ymin);for (let x =0; x < width; x++) {const cr = xmin + (x / width) * (xmax - xmin);let zr =0, zi =0;let iter =0;while (zr*zr + zi*zi <=4&& iter < maxIter) {const zrNew = zr*zr - zi*zi + cr; zi =2* zr * zi + ci; zr = zrNew; iter++; }const idx = (y * width + x) *4;const v = iter === maxIter ?0:255; image.data[idx] = v; image.data[idx +1] = v; image.data[idx +2] = v; image.data[idx +3] =255; } }// convert complex number from x_centre, and y_centre to x and y coordinatesconst centre_pixel_y = height -Math.floor(((y_centre - ymin) / (ymax - ymin)) * height);const centre_pixel_x =Math.floor(((x_centre - xmin) / (xmax - xmin)) * width);for (let y =0; y < height; y++) {for (let x =0; x < width; x++) {const dx = x - centre_pixel_x;const dy = y - centre_pixel_y;if (Math.sqrt(dx*dx + dy*dy) <5) {const idx = (y * width + x) *4; image.data[idx] =255;// Red image.data[idx +1] =0;// Green image.data[idx +2] =0;// Blue image.data[idx +3] =255;// Alpha } } } ctx.putImageData(image,0,0);return canvas;}// Calculate period at the center pointfunctioniterate(z, c) {return {re: z.re*z.re- z.im*z.im+ c.re,im:2*z.re*z.im+ c.im };}// magnitude squaredfunctionmag2(z) {return z.re*z.re+ z.im*z.im;}// round to 2dpfunctionround2(z) {return {re:Math.round(z.re*100) /100,im:Math.round(z.im*100) /100 };}// function to determine the orbit behaviourfunctionorbitPeriod(c, warmup =500, sampleCount =150, escapeRadius =4) {let z = { re:0,im:0 };// --- Warm-up phase ---for (let i =0; i < warmup; i++) { z =iterate(z, c);if (mag2(z) > escapeRadius) {return { status:"escapes",message:"Not in Mandelbrot set" }; } }// --- Sampling phase (bounded orbit) ---const values = [];for (let i =0; i < sampleCount; i++) { z =iterate(z, c);if (mag2(z) > escapeRadius) {return { status:"escapes",message:"Not in Mandelbrot set" }; }const r =round2(z); values.push(`${r.re},${r.im}`);// store as string so Set works nicely }// remove duplicatesconst unique = [...newSet(values)];// --- Determine behaviour ---const period = unique.length;if (period ===1) {return { status:"periodic",period:1,message:"Fixed point (period 1)" }; }if (period ===2) {return { status:"periodic",period:2,message:"Period-2 cycle" }; }if (period <32) {return { status:"periodic", period,message:`Period-${period} cycle` }; }// Many unique values → chaotic / non-repeatingreturn { status:"chaos",message:"Chaotic orbit" };}period =orbitPeriod({ re: x_centre,im: y_centre });period.status+" - "+ period.message+` (Period: ${period.period||'N/A'})`;
Code
"Position: "+ x_centre +" + "+ y_centre +"i";
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
(i)
(j)
(k)
(l)
Figure 4: Explore the Mandelbrot set by clicking on the plot to see the orbit behaviour at that point.
Figure 4 is a visualisation of the orbits of the points in the Mandelbrot set, clicking on different points in the set updates the label underneath to tell you the period of that point, as well as the position of the point in the complex plane. It can also tell you if the point is in chaos, and does not settle into a periodic cycle or a fixed point. You might notice something about the components of the main bulb, and that they all correspond to points that settle into a periodic cycle.
Figure 5: An image showcasing the periodicities of the mandelbrot set2
See Figure 5 for a coloured visualisation of the different periodicities in the Mandelbrot set.
3 The fibonnaci sequence and the Mandelbrot set
It may not seem likely, but the fibonacci sequence actually has a deep connection to the Mandelbrot set. The Fibonacci sequence is defined as follows: \[
\begin{aligned}
F(0) = 0 \\
F(1) = 1 \\
F(n) = F(n-1) + F(n-2) \text{ for } n \geq 2
\end{aligned}
\]
Code
viewof zoomed = {const xmin =-0.75, xmax =0.1;const ymin =-1, ymax =0;const pixelPerUnitWidth =600;const pixelPerUnitHeight =600;const maxIter =50;const width =Math.floor((xmax - xmin) * pixelPerUnitWidth);const height =Math.floor((ymax - ymin) * pixelPerUnitHeight);const canvas = DOM.canvas(width, height);const ctx = canvas.getContext("2d");const image = ctx.createImageData(width, height); canvas.addEventListener("click", (event) => {const rect = canvas.getBoundingClientRect();const x =event.clientX- rect.left;const y =event.clientY- rect.top;const cr = xmin + (x / width) * (xmax - xmin);const ci =-ymin - (y / height) * (ymax - ymin); mutable x_centre = cr; mutable y_centre = ci; mutable centre_x_pixel = x; mutable centre_y_pixel = y; });// compute mandelbrotfor (let y =0; y < height; y++) {const ci = ymin + (y / height) * (ymax - ymin);for (let x =0; x < width; x++) {const cr = xmin + (x / width) * (xmax - xmin);let zr =0, zi =0;let iter =0;while (zr*zr + zi*zi <=4&& iter < maxIter) {const zrNew = zr*zr - zi*zi + cr; zi =2* zr * zi + ci; zr = zrNew; iter++; }const idx = (y * width + x) *4;const v = iter === maxIter ?0:255; image.data[idx] = v; image.data[idx +1] = v; image.data[idx +2] = v; image.data[idx +3] =255; } }for (let y =0; y < height; y++) {for (let x =0; x < width; x++) {const dx = x - centre_x_pixel;const dy = y - centre_y_pixel;if (Math.sqrt(dx*dx + dy*dy) <5) {const idx = (y * width + x) *4; image.data[idx] =255;// Red image.data[idx +1] =0;// Green image.data[idx +2] =0;// Blue image.data[idx +3] =255;// Alpha } } } ctx.putImageData(image,0,0);return canvas;}period.status+" - "+ period.message+` (Period: ${period.period||'N/A'})`;
(a)
(b)
Figure 6: Mandelbrot set zoomed in on the components related to the fibonnaci sequence.
Magnitude of a complex number \(z=a+bi\) is defined as \(\sqrt{a^2+b^2}\)↩︎
Image By No machine-readable author provided. Hoehue~commonswiki assumed (based on copyright claims). - No machine-readable source provided. Own work assumed (based on copyright claims)., CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=396285↩︎