A GTK3 Mandelbrot Set

The use of matplotlib for displaying the Mandelbrot Set has been very convenient. It automatically proves a readout of the cursor position, save functionality, and a simple interface for adding a rubberband selection. How painful would it be to replicate this using GTK3 directly?

Quite painful. The example mandel_gtk.py has grown to over 570 lines, and does not include all of the functionality of the matplotlib code. Being the first code of any length I have attempted to write using python and GTK3, it is probably full of errors too. There is more room for mistakes in 570 lines of code than in 120 lines...

It is also painful for MacOS (and presumably Windows) users. Whereas python distributions on Linux (and Raspbian) generally support GTK, those on MacOS and Windows do not. GTK would not be regarded as a native graphics toolkit on those systems. By using it, our program has lost portability.

But it is faster. The previous benchmark which took 5.6s in mandel_improved.py is now dispatched in about 0.65s in mandel_gtk.py (remembering to disregard the first time after launch due to numba's extra overhead the first time it is used on each function).

Increase the window size and resolution on the matplotlib example, and it is easy to get runtimes of around 30s, which is quite tedious. The new code can dispatch many of these examples over ten times faster. From the human point of view, boredom and frustration is less likely to arise with a sub five second animated update than with a thirty second update. Not only is the new code faster, arguably it is fast enough, in that there would be little benefit in making it yet faster. But do not let that statement stop you from trying to improve it!

Mandelbrot Set, detail

(Note that an attempt to enter a resolution of zero causes the resolution to be set to the current window size. Hence the odd value above.)

The code responsible for the user interface is now about ten times longer than that responsible for the calculation itself. A good user interface (and arguably this has yet to reach that category) often takes huge amounts of code. But it does impress Humans, and sells well. Some enjoy the challenges of writing user interfaces, others prefer to concentrate on the more computational aspects of coding.

How impressive is the speed of this example? One can guess the number of floating point operations performed. One iteration of the inner Mandelbrot loop contains a complex multiplication, a complex add, and a complex modulus: eleven real floating point operations (or is it nine?). In the above picture there are 804x804 pixels to calculate, and none took more than 384 iterations, so there were fewer than 2.73 billion floating point operations. It took two seconds, so it did not achieve more than 1.36 GFLOPS. One could try modifying the code to include a global counter which is updated by the number of iterations spent on each pixel, and one could then print a more accurate measure of the performance in GFLOPS at the end of each calculation.

(If there is the error

  TypeError: Couldn't find foreign struct converter for 'cairo.Context'

and nothing is drawn, this can be fixed with

  sudo apt get install python3-gi-cairo