While at work, I came across my colleague implementing a graphics library and drawing amazing patterns on his display. Now, creating shapes using graphics library is pretty mainstream, however, this seemed too convoluted for a shape to be readily included in a graphics library. Naturally, I was overcome by curiosity and asked him,
“What sorcery is this?”
just to get two words for an answer: Mandelbrot Set.
I was perplexed and performed a quick search on the topic. I was awestruck by the result. Here is a link to the same.
This seemed like a great opportunity to explore Mandelbrot sets using Python, making it my first blog article on Python, allowing me to hit two birds with a single stone.
The Mandelbrot set is a set of complex numbers for which the function, does not diverge when iterated from z = 0 to z = infinity.
where C is the complex number of our interest.
It is not possible to compute the equation up to infinity, thus, a definite value is used to limit the computation for analysis. This is directly linked to the plot as we will see later.
A complex number is a number which when multiplied by itself (or squared) results in -1.
This is weird and unrealistic, as we know that the square of any number is always positive. For example,
2 * 2 = 4
(-5 )* (-5) = 25
Then, what is
(number) * (number) = -1
This is unimaginable and hence the number is termed as imaginary or i
i * i = -1
i = √-1
So a number would be considered complex if it contains an imaginary part.
5 + i, 9 – 4i, 2i are all complex numbers.
So, by definition, if C = i then,
and so on.
Now the question arises, what is the value, for which the function must remain bounded i.e. does not diverge? This value is known as Hausdorff dimension.
Hausdorff dimension is an integer that relates to the dimension corresponding to its topology (shape). It is the measure of a local size in space which is defined by the distance between its points in space.
Thus, the Hausdorff dimension for:
a point is 0
a line is 1
a square is 2, and
a cube is 3
As humans, we are limited to three-dimensional (3D) space, making 3, the maximum value of Hausdorff dimension.
Thus, for our application to obtain a Mandelbrot set, the Hausdorff dimension i.e. the boundary value for the function is 2. The logic behind this is the set when plotted on the Cartesian plane, would be a two-dimensional (2D) surface, similar to a square.
The mathematics behind Mandelbrot set is quite interesting. However, understanding the same would require introducing a whole lot of other mathematical concepts, making the whole thing beyond the scope of this article. However, a good place to start would be from the article by Wolfram MathWorld.
In order to implement this project, Python 3.6.1 or greater is required. This project requires a lot of additional packages like SciPy and NumPy, other than those that come with the installer. I could just install these packages using pip utility, however, I already had Anaconda installed, making my life easier. I would recommend my viewer’s to do the same, but working with bare-bone python is cool as well.
Just issue following commands, in case you are missing the packages listed above.
pip install scipy
pip install numpy
- Download latest Anaconda distribution from their official site.
- Run installer.
- Follow installer instructions and install with recommended specifications.
- And, you are ready to go.
- Run Anaconda Prompt or search for the same and launch the application.
Note! It takes a while for the shell to boot and be ready for usage. This is because a lot of packages are loaded on start-up. Please wait patiently.
While understanding maths and equations are fun, visualizing theory is what I love. So, I experimented and wrote a python script to plot the infamous Mandelbrot set. The code is available and can be downloaded from my Github repository.
The code uses numpy and pylab to generate Mandelbrot set, store the values as arrays and plot them as coordinates. One might think, how to implement complex numbers in Python, but therein lies the beauty of using this language. By default, Python supports usage of complex numbers using the readily available cmath library.
The function implements the Mandelbrot equation to generate a set of complex numbers stored in a numpy array.
x_min – the lower limit of the real axis.
x_max – the upper limit of the real axis.
x_num – the number of samples to be plotted on the real axis.
y_min – the lower limit of the imaginary axis.
y_max – the upper limit of the imaginary axis.
y_num – the number of samples to be plotted on the imaginary axis.
max_iteration – maximum number of iterations i.e. a definite value to replace infinity.
The function returns the number of iterations as an array and the complex numbers that satisfy Manderbolt equation Z < 2 as an array.
X = np.linspace(x_min, x_max, x_num, dtype = np.float32)
Y = np.linspace(y_min, y_max, y_num, dtype = np.float32)
The above snippet uses linspace method defined in numpy. It returns evenly spaced numbers over the specified interval.
So, x_num of equally spaced values would be returned between x_min and x_max. The data type of these values would be 32-bit floating point number, defined by dtype argument.
The same applies to Y.
C = X + Y[:, None] * 1j
This is the cmath syntax to represent a complex number.
complex_number = Real_num + Imaginary_num * 1j
Note! i and j are the same and are used interchangeably to represent a complex number.
N = np.zeros(C.shape, dtype = int)
Z = np.zeros(C.shape, np.complex64)
zeros is a numpy method that returns a zero-array of given shape and type i.e data type.
C.shape is the shape of the array i.e. complex
N is an array filled with zeroes to hold the current iteration value.
Z is an array filled with zeroes to hold complex values that satisfy Mandelbrot equation.
I = np.less(abs(Z), 2)
less is a numpy method that takes in two arguments, checks if the first argument is greater or not and returns True or False based on the result.
Here, the absolute value of Z is compared with 2, to check if it is less than 2 or not.
Z[I] = Z[I] ** 2 + C[I]
This is the implementation of Mandelbrot equation.
The function initializes the values required to call mandelbrot_set() and passes them as arguments.
with np.errstate(invalid = ‘ignore’):
M = np.nan_to_num(N + 1 – np.log(np.log(abs(Z))) / np.log(2))
errstate is a numpy method that performs floating-point error handling. Based on the error generated, an error-handler is defined in the argument.
nan_to_num is a numpy method that replaces NaN (not-a-number) with 0, positive infinity with the largest possible positive number and negative infinity with the largest possible negative number (i.e smallest number).
imshow(M, cmap = plt.cm.prism, interpolation = ‘none’, extent = (x_min, x_max, y_min, y_max))
imshow is a pyplot method defined under matplotlib. It is a straightforward way to display images on the axes.
I generated plots with various patterns outlining the behavior of the sets with respect to the number of iterations used.
The Mandelbrot plot illustrates the region where the Mandelbrot equation is satisfied i.e. the square of the complex number is less than 2. The region where these complex numbers are concentrated is seen in solid black color, while the other regions illustrate the rate at which the values diverge from Hausdorff dimension.
The following set of images demonstrate how the complex numbers are clustered on the axes and the greater the number of iterations, more evenly the values are distributed when they diverge, this reduces color variation over the entire plot.
Following are some of the other color mappings I used to obtain beautiful plots.
For more color mappings, check out colormaps_reference.
Mandelbrot sets are just a small part of numerous such sets. Mandelbar sets and Julia sets are other such sets exploiting the properties of complex numbers. These sets along with many others are collective entities that belong to a major field of study called fractals. The best source to learn about fractals is from their official website. The real-world applications are many and the most prominent one being the gaming and graphics industry. Fractals play a major role here. These topics will be covered in another blog post.