Simple Julia and Mandelbrot Sets with Python

This article explains how to create some fractal plots with graphics.py, a popular graphics library for Python written by John Zelle. Graphics.py is a single file containing graphics functions such as Point, Line, Circle and Rectangle. Elsewhere on this blog, it’s been used to create sinusoidal patterns, including a Mexican hat/blancmange surface. This article focuses on the creation of fractal images.

Plot 1. A Julia set, c = -1+j0

Install Graphics.py

Install graphics.py as follows:

pip install graphics.py

Install Julia.py

julia.py is a small program for plotting Julia and Mandelbrot sets. It’s just a quick learning aid for gaining appreciation of these sets and the simple algorithms that produce them. Grab julia.py now, and set its permissions:

$ curl -O https://raw.githubusercontent.com/webtaster/Julia/master/julia.py
$ chmod 755 julia.py

…and the tkColors.py library, which needs to stay in your current working directory.

$ curl -O https://raw.githubusercontent.com/webtaster/Julia/master/tkColors.py

Plot a Julia Set

Run the program. A graphics window should appear, and a classic Julia set will be drawn, just like the one pictured above. Be patient. The plotting can take 30 seconds or more. That’s how long it took on my powerful but ageing laptop (containing a 4th generation Intel i7 CPU).

What you are looking at (hopefully) is a classic Julia set, similar to Plot 1 (above) and to this example at Michael Goodwin’s site. Meanwhile, some information appears in the shell:

$ ./julia.py
Type: Type: Julia, c = (-1+0j)
zoom factor 200
most iterations 40
Done

Click the mouse for information on a point, or ctrl-c to end


Press ctrl-c in the shell to exit the program.

Varying the Constant

A Julia set can be varied by changing the c constant. Do so now. Edit julia.py and change line 119 so that the new value of c becomes:

c = complex(-0.512511498387847167, 0.521295573094847167)

These c values are taken from the first example on the Wikipedia Julia Set page, and the image produced (below) closely resembles the Wikipedia rendering. But not before we make one more edit. Comment line 58 and uncomment line 63, changing the output from multi-colour to graduated monochrome:

  # Colourful, a bit random but clear
  #color = tkColors[(a+25) % 750]

  # Uncomment for a nice graded monochome rendering.  Increases plot time.
  color = color_rgb(a*4, a*4, a*4)

Now run it, and you should see:

Plot 2. Julia set, c = -0.512 + j 0.521 (approx)

Slightly changing the value of c has resulted in a big change in the output image. Switching from colour rendering to monochrome makes the details, and the resemblance to Wikipedia’s version, easier to see.

Undo your edits to julia.py before proceeding. Or just download it again:

curl -O https://raw.githubusercontent.com/webtaster/Julia/master/julia.py

Mandlebrot Sets

The Mandelbrot set is like the Julia set, except that the value of c isn’t constant. It varies with each point on the plane, taking the complex value of that point. Simple to program, because the Julia/Mandelbrot code needs differ by just a few characters, (viz. line 217: ‘c = z’).

Also, there is just 1 Mandelbrot set, whereas there are many Julia sets – we plotted 2 of them above. Anyway, draw the Mandelbrot set now. Edit julia.py. Change line 114 from

julia = True

to

julia = False

and run the program:

./julia.py

Up comes the familiar Mandelbrot shape, complete with garish colourisation:

Plot 3. The Mandelbrot set.

When the Mandelbrot set has finished drawing, click your mouse in the graphics window, just where you see the pointer/cursor in the above image. A set of coordinates will be printed to the terminal, something like:

x_offset = -0.15265265265265243
y_offset = 1.0287859824780976

These numbers will come in useful presently.

Mandelbrot Zoom In

Being a fractal, the Mandelbrot plot responds well to zooming in, the effect of which is to reveal ever more detail. Edit julia.py again, go to lines 103 to 104, and insert the x_offset and y_offset values, just as they are written above. Next, edit line 98 and change the value of the ‘zoom‘ variable to 5000. This will increase the existing zoom in by a factor of 25. Save julia.py.

Run the program:

$ ./julia.py
Plot 4. Mandelbrot set detail. Centred at about -0.153 + j 1.029. Zoom 5000. Showing a “mini Mandelbrot” near to the top of the set. (It is also visible without zoom, just, in Plot 3).

What has been revealed here is a common feature of the set, known for obvious reasons as a “mini Mandelbrot”. The area in the middle of this image has a shape similar to the overall set.

Mandelbrot Browsing with julia.py

If you like, it is possible to explore the Mandelbrot set by repeatedly applying this zoom and offset technique. Draw an image, click the mouse on an interesting looking place, put the printed coordinates back into julia.py, increase the zoom, and re-run. And repeat. Interesting features or especially decorative areas can be plotted. For example, there are many mini Mandelbrots, including some at levels of zoom much higher than that shown in Plot 4.

Professional Browsers

For serious exploration, there are also many excellent Mandelbrot browsers online. These are professional quality, with real time zoom and pan. For example, here’s how mandel.gart.nz interprets the same area from Plot 4:

Plot 5. The same mini Mandelbrot as Plot 4, drawn by the professional quality Mandelbrot browser at mandel.gart.nz. Not sure why, but their imaginary axis seems reversed, showing negative imaginary values above the horizontal axis and positive ones below it. The larger mini Mandelbrot here is centred at about -0.157 -1.033j (their coordinates) despite being in the upper quadrant.

Try the “I Feel Lucky” button over at bertbaron.github.io. Also easy on the eye, with a calm default colour scheme, is mandelbrot.site.

Well Known Features

An intriguing feature of mandel.gart.nz is the invitation to “Jump to” a list of well known Mandelbrot beauty spots, including “Seahorse Valley”, “Julia Island” and “Star Fish”. Some of these are at mind-blowing magnifications. For example, select Julia Island, and enjoy an animated journey down to zoom level 1,585,714,676, where this comely figure lives:

Plot 6. The very charming Julia Island, rendered by mandel.gart.nz. At this zoom level, the whole Mandelbrot set would be about 100,000 miles across. Or to put it another way, if you were looking at a picture of the whole set, like plot 3, and the picture was about 6 inches (15 cm) wide, then Julia Island, within that picture, would measure about 13.5 pico-metres shore to shore. Or about 13.5 billionths of a millimetre. Or 1 7000th the width of a human hair.

Julia Island

Here’s how the humble julia.py draws Julia Island. Edit the program as before, changing the offsets and zoom again, as follows, then run it.

zoom = 792857338
x_offset = -1.768778833
y_offset = -0.001738996
./julia.py
Plot 7. “Julia Island” of the Mandelbrot set, rendered by julia.py. The image seems to “lean” the other way, probably due to the inversion of mandel.gart.nz coordinates, as noted under Plot 5. We also seem to have an additional central hole. Time to fiddle with the settings…

There are some differences this image (Plot 7) and the one produced by mandel.gart.nz (plot 6). Apart from the colour scheme, our home-made plot has a central “hole”, a black disk, which does not appear in mandel or other online renderings. Plot 8 shows the effect of increasing maxitr, (line 149), one of the rarely adjusted settings, to 2000, and swapping to monochrome:

Plot 8. A more accurate rendering of Julia Island. Maximum iterations increased to 2000. Still that hole though…

Plot 8 is better, but we still have those holes. Decreasing the zero_threshold from 0.01 to 0.00001 (line 146) improves matters, as shown in plot 9:

Plot 9. Tighter settings give a yet more accurate Julia Island picture. A pretty thing, and it closely reflects the same feature drawn by the professional set browsers.

Shrinking the zero_threshold reduced the level at which the algorithm deems a complex value to have imploded to near zero. Areas that were previously black, like those unexpected black disks in Plot 7, must have had a value (an absolute size) between 0.01 and 0.00001. Now the algorithm considers them non-zero, instead of zero, and they are colourised accordingly.

Changing the Complex Function

It is possible to change the complex series itself, resulting in further fractal sets. For a quick example, “reset” julia.py by downloading it again.

curl -O https://raw.githubusercontent.com/webtaster/Julia/master/julia.py

Now we are back to plotting Julia sets. Running the program now would yield the same image as in Plot 1, above. Go to line 31. This is the main complex equation and the heart of the program. Change it from

z = z*z + c

to

z = z*z*z + c

or even

z = z*z*z*z*z + c

Run the program to display the higher order Julia set. These can also be zoomed-in on, of course, showing the effect of the polynomial. Z cubed functions tend to produce images with a 3 lobe motif. Z to the power of 5 five tends to make quintuple visual effects. The plot below is a julia set, with the function modified to z = z*z*z + c.

Plot 10. A Julia set, with a cubic function and c = -1 + 0j. Also the colours have been jazzed up somewhat.

Conclusion

This article could go on longer, citing more and more Fractal examples. With Mandelbrot and Julia sets being fractal, there is an infinite amount of detail to explore. I hope it has been an interesting read and not too waffly.

There are many online resources for visualising Julia and Mandelbrot sets. Apart from sites mentioned in the above section entitled “Professional Browsers” there excellent pages and especially YouTube videos explaining with detail and clarity the underlying mathematics.

For an everyday illustration, this effort on the Numberphile channel, “What’s so Special about the Mandelbrot Set?“, is hard to beat.

Another kind of satisfaction can be obtained by drawing these things in a do-it-yourself manner, with a simple program like julia.py, or similar, making alterations and seeing their affect on the output. The simplicity behind the Mandelbrot and Julia sets forms a large part of their fascination.

Appendix

Improvements to Julia.py

julia.py is just a quick program, designed to aid understanding the Mandelbrot algorithm. As such, it has been left plain and unoptimised. From a programming point of view, there is much scope for improvement. Eg. tidying the code into proper functions, making it more readable, adding command line arguments to replace tiresome editing, making it multi threaded, optimising the iteration loop, and so on.

Computing Notes

Even on a multi core machine, julia.py is quite slow, because it is single threaded. On my 8 core laptop, one core is busy, while the others are relatively idle.

Building the image also takes a surprising amount of memory. As the Julia set in Plot 1 is drawn, memory consumption increases steadily, eventually reaching 495 MB as the image completes. This can’t be explained simply by the image size, which by default is 1000*800 pixels, implying 648 bytes per pixel. Plainly, the structures in Graphics.py are sizeable.

A Note on Zoom Factors

For some reason, to produce an image of comparable size, the zoom factor within julia.py has to be about half that of the online fractal browsers. Not a big problem. It means julia.py’s images are about twice as big as those found online. Perhaps due to differences in screen size.

END.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.