Mandelbrot set tutorial
A fractal image is an image in which a pattern is repeated when the image is magnified. In this article we’ll see how to draw a Mandelbrot set, one of the most well known fractals.
Definition
The Mandelbrot set is the set of all the complex numbers \(c\) for which the iteration
(1) \(z_{n+1}=z_n^2+c\)
starting with \(z_0=0\), never escapes to infinity, but stays bounded, no matter how many iterations we do. For example:
- If \(c=1+2i\) we have \(z_0=0\), \(z_1=1+2i\), \(z_2=-2+6i\), \(z_3=-31-22i\)… as we go on \(z_n\) grows without stopping, it escapes to infinity.
- If \(c=-1\) we have \(z_0=0\), \(z_1=-1\), \(z_2=0\), \(z_3=-1\)… in this case \(z_n\) is bounded, so \(c\) is in the Mandelbrot set.
Plotting
On a Cartesian plane the Mandelbrot set intersects with the \(x\) axis at \((-2.5, 1)\) and with the \(y\) axis at \((-1,1)\). To plot the set on a \(WxH\) surface we scale each \((x,y)\) point of the surface in the \((-2.5,1)\) range for \(x\) and \((-1,1)\) range for \(y\). The scaled \(x\) becomes the real part of \(c\) and the scaled \(y\) becomes the imaginary part. Once we have \(c\) how do we know if \(z_n\) is bounded or not? We can’t count to infinity so we introduce limits. One is the upper bound on the number of iterations (for example 50). The other is a bailout condition: if \(|z_n| > 2\) then \(z_n\) has grown too much and we know that it’ll grow indefinitely so \(c\) is not in the set, if at the end of the loop we have \(|z_n| < 2\) then \(c\) is in the set.
All black
black.go is a basic implementation. If a pixel is inside the set we draw it black, otherwise transparent. It uses the image Golang package.
To run do:
$ go run black.go > black.png
Escape time algorithm
The way the set is drawn is up to the programmer. One common technique (known as Escape time algorithm) is to use a different color based on how many iterations takes \(z_n\) to escape to infinity. escape.go shows an implementation. On http://colourlovers.com you may find some inspiration for your colors.
Smooth coloring
The problem with the above algorithm is that it creates bands of color. An improved algorithm is the “Normalized Iteration Count”. We use a fractional iteration count to better smooth the colors. The integral part is used to choose two colors, the fractional part is used to blend them togheter. To get this count do:
\(f = i - log_2(log_2(z_n))\)
where \(i\) is the number of iterations done. For the derivation of the formula see Renormalizing the Mandelbrot Escape.
This time we’ll use lucasb-eyer/go-colorful which provides some color manipulation functions. The implementation is in smooth.go.
Binary decomposition
We can draw the Mandelbrot set however we want. For example we can use one palette of colors if the imaginary part of \(z_n\) is \(<0\) and another if it’s \(>=0\). See decomposition.go.
Golang Weekly
Checkout Go Weekly for the latest articles, tutorials and projects about Go.