0% found this document useful (0 votes)
322 views134 pages

Make Your OWN Mandelbrot: Tariq Rashid

This document provides an introduction to making your own Mandelbrot set using Python. It will explore the key mathematical concepts behind fractals like the Mandelbrot set. These concepts include functions, iteration, convergence and divergence. It will also introduce complex numbers and how they allow visualizing the Mandelbrot set. The document is aimed at all readers and assumes only basic mathematics. It will guide the reader through understanding the concepts, writing Python code to generate the Mandelbrot set, and exploring related topics like Julia sets and 3D fractals.

Uploaded by

Ricardo_Semog
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
322 views134 pages

Make Your OWN Mandelbrot: Tariq Rashid

This document provides an introduction to making your own Mandelbrot set using Python. It will explore the key mathematical concepts behind fractals like the Mandelbrot set. These concepts include functions, iteration, convergence and divergence. It will also introduce complex numbers and how they allow visualizing the Mandelbrot set. The document is aimed at all readers and assumes only basic mathematics. It will guide the reader through understanding the concepts, writing Python code to generate the Mandelbrot set, and exploring related topics like Julia sets and 3D fractals.

Uploaded by

Ricardo_Semog
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 134

MAKE YOUR

OWN
MANDELBROT

A gentle journey through the mathematics of the


Mandelbrot and Julia fractcals, and making your own
using the Python computer language.

TARIQ RASHID
www.allitebooks.com
Contents 
 
Prologue 
The Mandelbrot Set 
Introduction 
Who is this book for? 
What will we do? 
How will we do it? 
Author’s Note 
The Journey 
Part 1: Concepts 
Fractals 
Some Mathematics 
Functions 
Iteration 
Divergence, Convergence 
Periodic Cycles ‘Flip Flopping’ 
Chaos 
Milestone Check 
Complex Numbers 
Visualising Complex Numbers 
Complex Functions 
The c=(0.33 + 0.577i) Neighbourhood 
Divergence Atlas 
We’re ready! 
Now We Can Make Our Own Mandelbrot 
Completing the Atlas 
The Recipe 
Part 2: DIY 
Working with Python 
Python 
Interactive Python, IPython 
A Very Gentle Start with Python 
Mandelbrot Set in Python 
Exploring the Mandelbrot Set 
Part 3: Even More Fun 
Julia Sets 
Mandelbrot and Julia Mountains 
Surface Plot 
Mandelbrot Mountains 
Julia Mountains 
Gentler Landscapes 
Epilogue 
Resources 

www.allitebooks.com
Prologue 
 

The Mandelbrot Set 
The organically intricate and beautiful object you see before you is the Mandelbrot set. Despite 
its complexity, and even haunting beauty, it is in fact the result of extremely simple mathematics. 
 

 
 
The following images show close­ups, as if we had a microscope, of various parts of this 
Mandelbrot set. You can see both the diversity of detail and also a constant theme with 
recurring elements. They are so detailed and diverse that you might not believe that they are, in 
fact, parts of the Mandelbrot set in the first image above. 
 

www.allitebooks.com
 
 

 
 

www.allitebooks.com
 
 

 
 

www.allitebooks.com
 
 

 
 

www.allitebooks.com
 
 

 
 

www.allitebooks.com
 
 
The Mandelbrot set is, in fact, infinitely detailed. You could keep on zooming in and exploring it 
forever without running out of detail or the patterns starting to repeat themselves exactly. All this 
from a very simple and easy to understand mathematical recipe. That’s what this book is about. 
 

 
   

www.allitebooks.com
Introduction 
 

Who is this book for? 
This book is for anyone who wants to understand what a Mandelbrot set is, how to make your 
own, and the few easy but exciting mathematical concepts that go into making it.  
 
This guide is not aimed at experts in mathematics. You won’t need any special knowledge or 
mathematical ability beyond school maths. If you can add, multiply, subtract and divide then you 
can make your own Mandelbrot set. 
 
Interested readers or students may wish to use this guide to go on an exciting and beautiful 
mathematical excursion. Yes, mathematics can indeed be exciting and beautiful, something 
that's not so easy to see when you're focused on the school curriculum, solving quadratic 
equations and churning through trigonometry puzzles. 
 
Teachers can use this guide to demonstrate the genuine excitement and beauty of mathematics 
­ often difficult to show through standard curriculum topics ­ at a level appropriate for secondary 
school students. 
 
I wish a guide like this had existed when I was a teenager struggling to work out what this 
beautiful intricate Mandelbrot set actually was and how to make my own. I'd seen it in books, on 
posters and even in music videos. At that time I could only find difficult academic texts aimed at 
those already experts in mathematics and its jargon. All I wanted was for someone to explain it 
to me in a way that a moderately curious school student could understand. 
 

What will we do? 
In this book we’ll learn about the few mathematical concepts that are needed to understand 
what  a Mandelbrot set is. These will be explained in a really easy, clear way, and will assume 
absolutely no previous knowledge or expertise beyond very simple school mathematics. The 
concepts we’ll walk through are functions, iteration, convergence and divergence, chaos and 
complex numbers. These sound scary but they’re not ­ they’re really simple and actually exciting 
because they’ll surprise us with their strange behaviour! 
 
We want to understand these concepts before we actually provide a recipe for constructing a 
Mandelbrot set because it's much more satisfying seeing the ideas come to life. It's like baking 
your own cake from scratch. If you’re really not interested in the underlying concepts feel free to 
jump straight to the recipe. 
 

www.allitebooks.com
Once we’ve made our first Mandelbrot set, we’ll take idea and run with it in different directions. 
We’ll try different colouring schemes, we’ll explore the related Julia sets, and even try to extend 
the flat world of Mandelbrot sets into 3 dimensions. 
 
Ultimately, I want to show how really simple mathematics can surprise us by behaving in ways 
that are not boringly linear and predictable but actually unsettlingly chaotic. Even more than this, 
I want to show that this really simple mathematics can be intricately and organically beautiful 
when it treads a delicate path between boringly predictable and apparently random messy 
disorder. This is the same beauty we see everywhere in nature, from snowflakes to clouds, from 
the structure of lungs to the patterns of a cauliflower. 
 

How will we do it? 
The aim of this guide is to open up the concepts behind a Mandelbrot set to as many people as 
possible. This means we’ll always start an idea somewhere really comfortable and familiar. We’ll 
then take small easy steps, building up from that safe place to get to where we have just 
enough understanding to appreciate something really cool or beautiful about the Mandelbrot set.  
 
To keep things as accessible as possible we’ll resist the temptation to discuss anything that is 
more than strictly required to make your own Mandelbrot set. There will be interesting context 
and tangents that some readers will appreciate, and if this is you, you’re encouraged to 
research them more widely. 
 
This guide is deliberately split into three distinct parts. The first part will take us on the journey of 
understanding and exploring the mathematical concepts behind the Mandelbrot set.  We will 
avoid talking about how we might practically get a computer to draw our own Mandelbrot set 
because the details of getting a software environment up and running, and then learning to use 
a computer programming language to calculate and plot the set can distract us from 
understanding and exploring the key mathematical concepts.  
 
The second part will take us on the practical journey to calculating and plotting our own 
Mandelbrot set using computers. We’ll start by gently introducing a mathematical computing 
environment, before gradually building up the computer instructions, or program code, to make 
a Mandelbrot set. We’ll do this piece by piece so that everyone can understand the code, no 
matter how new to computer programming they might be. 
 
The final part will extend the core ideas into new directions. We’ll explore Julia sets, which are 
intimately related to Mandelbrot sets, and are in my view even more beautiful. We’ll also create 
and visualise three dimensional versions of these fractals.  
 
And don’t worry, all the tools we’ll use will be free and open source so you won’t have to pay to 
use them. 

www.allitebooks.com
 

Author’s Note 
I will have failed if I haven’t given you a sense of the true excitement and surprises in 
mathematics. I will have failed if I haven’t shown you how mathematics can be beautiful, and in 
a way that is organic, intricate and detailed much like nature around us. I will have failed if 
anyone with school level mathematics stumbles and doesn’t complete the journey of discovery 
and understanding of the mathematical concepts. 
 
I welcome feedback to improve this guide. Please get in touch at makeyourownmandelbrot at 
gmail dot com.  
 
You will also find discussions about the topics covered here and others sparked by ideas 
presented here at ​ http://makeyourownmandelbrot.blogspot.co.uk​ . You will also find an errata 
there too. 

   
The Journey 
Here’s a map of the journey we’ll take. Feel free to speed through the bits you already 
understand. 
 

 
   
Part 1: Concepts 
 
In this section will gently introduce just enough ideas and mathematical concepts to appreciate 
the exciting dynamics underlying the Mandelbrot Set. 
 
We’ll introduce fractals, functions, iteration, the sometimes surprising behaviour of functions, 
and complex numbers, before we make our own Mandelbrot set. 
 
We’ll stick to ideas in this part, and intentionally leave the distractions of computer programming 
for Part 2. 
   
Fractals 
 
Fractals are really interesting objects. They’re interesting because they bust the myth that 
mathematics and its objects are always boring, predictable, and are cannot be as beautiful or 
intricate as objects we see in nature; clouds, mountains, flowers, water streams, snowflakes. 
 
Let’s look some of these so­called boring, predictable, flat objects. A square, a circle, and even 
a 3­dimensional cube or cylinder.  
 

 
 
These objects are certainly simple compared to those we see in nature. Actually some people 
do find these objects really fascinating, but I suspect most people wouldn’t want to stare at 
these objects for a long time, exploring their nooks and crannies. This last bit is important ­ 
these objects don’t have nooks and crannies, they don’t reveal new details for us to explore the 
longer we look at them. If we looked at them with a magnifying glass we wouldn’t find anything 
new or surprising. In that sense, we can call them boring. 
 
Now lets look at something totally unordered, noisy, following no rule or regulation, other than 
being totally random.  
 

 
 
The picture is of the familiar white noise we used to see on old television sets when they weren’t 
properly tuned to a broadcasting channel. It’s not that interesting either. Actually we humans 
have a tendency to try to project recognisable things onto noise, which is why we love finding 
faces and dragons in the clouds! If we set that human tendency aside, we’d find purely random 
objects boring.  
 
Now look at the following objects; some clouds, tree branches, a romanesco cauliflower and 
some leaves.  
 

   

   
 
There is something about these objects that leads us to explore them a little longer. It’s not just 
that they are very detailed, but that there is some semi­regularity about them. There appears to 
be a theme that pervades them, a repeated pattern, but repeated not in that boring and easily 
predictable way, but in a way that is somewhere between the two extremes of boring regularity 
and totally messy randomness. This is an important idea. The idea that objects that appeal to 
our human senses and minds are somewhere between boring trivial regularity and utter 
randomness.  
 
We’ll be coming back to this idea later, carefully treading a path between regularity and 
randomness where mathematics produces some really intricate beautiful objects. 
 
If we zoomed into the above images with a microscope or a telescope it would be difficult to 
guess at what scale we were looking at the object. Each little floret of the cauliflower looks like a 
collection of smaller ones, and you can’t guess whether the bit you’re looking at is 5 centimetres 
wide or 5 millimetres. Each bit of cloud fluff looks like a collection of smaller cloud fluffs ­ is it a 
metre wide or a kilometre? This is called ​ self­similarity​
 at different scales. 
 
The following objects are less organic and natural than clouds and plants, but they do have that 
self­similarity we talked about above. Their construction is much more regular. We include them 
here because when people talk about fractals they often think of these objects too. Personally I 
think they’re interesting to look at but the interest wears off quickly because they’re closer to the 
‘regular’ world than the more organic and less predictable natural objects.  
 
The first one is a Koch snowflake. The second is a Sierpinski gasket. You can easily find out 
how to make them, but the basic idea is to take a simple regular shape, such as a hexagon or 
triangle, and repeatedly add smaller versions of this shape at ever greater levels of detail.  
 

   
 
The following summarises this spectrum of objects, from totally random to totally ordered, with 
the interesting objects between the two. It’s as if the tension, the constant battle between total 
order and total randomness, produces the most natural, organic, intricate, beautiful objects. 
 
 
 

 
   
Some Mathematics 
 
In this section we’ll introduce some mathematical concepts that are needed to make the 
Mandelbrot set. For each concept we’ll start at an elementary place which should be familiar to 
everyone, needing nothing more than basic school mathematics. We’ll then take easy steps on 
a gentle journey of understanding to reach a place where we’ve understood just enough make a 
Mandelbrot set, and have seen enough to appreciate some of the surprising behaviour of really 
simple mathematics that leads to unexpectedly intricate and beautiful forms. 
 
For the most part you’ll only need to be able to add and multiply. This will will take us quite far. 
There will be a section where it will be helpful, though not essential, to be able to expand 
brackets of simple expressions like (x+a)(y+b) and collect terms. Most 11­14 year olds can do 
this with ease. You won’t need any mathematical capability beyond this at all. 
 
You can skip this section if you really aren’t interested and want to jump straight to the recipe for 
making a Mandelbrot set, but you’ll be missing out on some interesting insights and unexpected 
but pleasant surprises. 
 

Functions 
Functions are an easy idea that we’ll build a lot on, so it’s worth making sure we’re familiar with 
it. Let’s start, not with a definition, but some familiar examples.  
 
The following picture shows a machine which we’ve labelled “+1”. It’s a machine that does work. 
Its job is to take numbers in one end, and spit out a new number out the other end. This 
machine adds one to whatever number is pushed into it. It can be used on any number we 
throw at it, it’ll simply add one and throw out the new number. We call these reusable machines 
that work on numbers, ​ functions​ .  
 

 
 
Let’s see what this function does to other numbers. 
 
 
 
It shouldn’t surprise anyone that this ‘add one’ machine, or function, simply increments the 
number that is thrown onto it, so 1 is turned into 2, and 99 is turned into 100.  
 
That was a really easy example but it was ideal to introduce the idea of a reusable function. 
Some more jargon while we’ve got it easy: the number thrown into this function is called the 
input​, and the number that pops out is called the ​output​. Here’s a summary of these mildly 
technical words: 
 

 
 
Because the idea of a function is an important building block, we’ll make sure we’re really 
comfortable by looking at some more examples. 
 
 
 
 
We can see functions for ‘add 3’ and ‘subtract 7’, ‘multiply by ­1’, ‘square’ and ‘divide by 3’ all of 
which perform as expected. These functions are doing nothing more complicated than the 
arithmetic children learn at school. 
 

Iteration 
Now think about what happens when we feed the output of one of these functions back into it 
again as the input. This is not such a crazy idea. Many things in nature evolve according to 
external forces and their current state.  
 
If you were asked to predict the rabbit population for next season, you’d need to know about 
factors like weather and food availability. You’d also need to know the current population, 
because the next population very much depends on the current population. This is why 
scientists find modelling using iteration useful for modelling natural phenomenon which evolve 

www.allitebooks.com
over time.  
 
The following diagram shows the idea of iterating a function. The input and output are the same 
as before but this time we take the output and put it back into the function as input for the next 
iteration.  
 

 
 
Let’s try it with a starting number of zero, and the function “+ 1”. The first time we apply this 
function we get 0 turned into 1, just as we saw before. Now we take this output 1 and pop it 
back into the function as input and we get 2 popping out. Again, and we get 3. Then 4, 5, 6, 7, 
… you get the idea. The numbers keep getting bigger in steps of 1.  
 

 
 
Now let’s try it will a different number and a different function. Let’s start with “9” and apply the 
function “divide by 3”. We get the sequence 9, 3, 1, ⅓, … You can see the numbers getting ever 
smaller. We could go on for longer and the numbers would get miniscule. In fact, they’d never 
get to zero, they’d just keep getting smaller by a factor of 3. No matter how small a number is, 
dividing it by 3 never gives zero, just a smaller number. 
 

 
 
Now lets try the function “multiply by ­1”. If we start with 4, we get the sequence 4, ­4, 4, ­4, … 
and so on forever. The values simply flip and flop between positive 4 and negative 4, and they 
don’t get any bigger or smaller.  
 
 

Iteration ​simply means doing the same thing again and again to produce a series of outputs, 
just as we did above. 
 
Let’s now find a more concise way of presenting how an initial value evolves as a function is 
repeatedly applied. A table showing the initial value, and the subsequent values at each step, or 
iteration, is a good start.  
 
The following table shows how the initial value 2 evolves as the function “multiply by 2” is 
applied 10 times. Some people call the ​initial value​, the ​
seed value​

 
Function “multiply by 2”, initial value 2   

Iteration  Value 

0  2 (initial value) 

1  4 

2  8 

3  16 

4  32 

5  64 

6  128 

7  256 

8  512 

9  1024 

10  2048 

 
 
This is a more compact view than the function diagrams we’ve used before. You can quickly see 
the value grows bigger, and does so in a rather accelerated way. Let’s plot the information in 
this table as a graph to visualise the growth. 
 
 
 
Plotting graphs like this is a really good way of quickly portraying the broad nature of how a 
function evolves an initial value. If we only had tables of numbers to look at it wouldn’t be easy 
to appreciate this broad nature. We can see that starting with a value of 2 and repeatedly 
applying the function “multiply by 2” results in values which grow not steadily but at an 
accelerated rate, growing ever faster. 
 
Now let’s visualise similar graphs for other functions to get a feel for the broad nature of the 
evolution they create. This one is for the function “divide by 3” starting with a seed value of 10, 
applied 10 times. You can see that the values get smaller but this time changes between 
successive values are smaller too. That is, the speed at which the initial value of 10 get 
progressively smaller actually slows down. This is in contrast to the previous “multiply by 2” 
function which showed accelerated growth. 
 

 
 
 
We considered before how the function “multiply by ­1” simply flipped the value from positive to 
negative. Let’s be adventurous and visualise that function, but tweaked a little to apply a 
shrinking factor at each step, a bit like the “divide by 3” function but weaker. The following plot 
shows the evolution of values for the function “multiply by ­0.8” with a starting value of 2. 
 

 
 
Now this is a more interesting plot. The values evolve and do flip between positive and negative 
values, as you’d expect if you repeated multiplied by a negative number. The values also seem 
to get smaller too, and this is the effect of multiplying by a fraction of 1.  
 
We’ve reached a milestone here. We’ve found a really simply function “multiply by ­0.8” which to 
most people looks really boring, but which produces some quite dynamic behaviour. Behaviour 
which reflects some of the more interesting things we might see in nature, such as the decay of 
a pendulum swing or the vibrations of a plucked guitar string fading away.  
 
It is worth restating the importance of this again. We’ve connected very simple mathematical 
functions to behaviour which is unexpectedly more dynamic and complex. Unexpected because 
for many of us who laboured away with functions and mathematical expressions at school found 
they behaved in a really boring way. The functions we worked with, particularly because of the 
way we applied them, behaved quite linearly and predictably. And if they weren’t linear they 
were fairly boring curves. Remember endlessly plotting quadratic functions? 
 

Divergence, Convergence 
Looking back at the graphs we’ve already plotted we notice that the values which result from 
repeated applying a function keep growing forever, or they get smaller and smaller. 
 
If the values keep growing forever we say the values ​ diverge​. They sort of get out of hand. We 
saw the graph for the function “multiply by 2” with starting value 2, show the successive values 
getting bigger and bigger. There is no upper limit to how big those values could get. If you think 
of a huge number, that value will eventually get bigger than your huge number given enough 
applications of “multiply by 2”. Even if had another go at coming up with an even bigger number, 
this function will eventually produce values bigger than your humongous number. We say this 
function is ​ divergent​.  
 
Now look at graph for the function “divide by 3” with starting value 10. We saw the successive 
values get smaller and smaller. This function will produce values smaller than any small number 
you can think of, given enough iterations.  We can see the values got closer and closer to zero, 
but never reach it. We say this function ​ converges ​ towards zero. The function “divide by 3” is 
convergent​ .  
 
Do all functions either diverge to ever bigger numbers or converge to ever small numbers 
approaching zero? Are these two the only two possibilities? This is a good question to ask. It’s 
the kind of thinking that mathematicians like to do. They like to explore some specific examples, 
just like we have above, and then try to generalise and see if the ideas apply everywhere. 
Sometimes they do, which is great for mathematicians, but sometimes they don’t and need 
more exploring and refinement. Sometimes the ideas never go anywhere, but hey, that’s life! 
 
Let’s consider another function “add 0.8 * (5 ­ input value)“ with start value 1. Let’s be clear what 
this function means. It means take the input value, and take it from 5, then multiply the result by 
0.8, and add this resultant value to the input value. You can see we’re using the previous input 
value twice when we apply the function. This is okay, it doesn’t break any rules.  
 
Just to be sure, let’s try it once. We have a starting value of 1, so (5­1) is 4. Then we’re making 
it a little smaller by multiplying it by 0.8. So 0.8*4 is 3.2. Finally we’re adding this to the input 
value which was 1, to get 1+3.2 = 4.2. It’s a little more involved but still only uses the very basic 
adding and multiplying we’re all familiar with.  
 
The following table shows the values worked out as this function is repeatedly applied 10 times. 
 
Function “add 0.8 * 5 ­ input value)”, initial value 1   

Iteration  Value 

0  1 (initial value) 


4.2 

4.84 

4.968 

4.9936 

4.99872 

4.999744 

4.9999488 

4.99998976 

4.999997952 
10 
4.9999995904 
 
We can see that the successive output values get closer and closer to 5. If we carried on 
working out many more iterations, the values would even closer to 5. In fact you could think of 
any number that is really really close to 5, this function would eventually produce values that 
were even closer than the number you thought of. 
 
This is an important find, because we have a function that converges to a value that isn’t zero, 
in this case it converges to 5. The graph of successive values makes this visually clear. 
 

 
 
Out of interest, does this function still converge towards 5 if we started with a different seed 
value? Let’s try it again starting not with a value of 1, but with 9, a value deliberately chosen to 
be on the other side of 5. The following plot shows this function’s outputs do indeed converge 
towards 5 from 1.  
 
 
 
We explored different starting values because we wanted to show that some functions will 
converge to their target no matter what the starting values are. You can try other starting values 
for any of the functions we’ve looked at above, and you’ll see this is true. Mathematicians would 
say these functions are not sensitive to their starting values. 
 
In contrast, the simple iterated function “square the input” is sensitive to its starting value. The 
following graph shows three sequences from this function, with starting values 0.9, 1.0, and 1.1. 
These seed values are chosen deliberately to be close to 1.0. 
 

 
 
We can see that even though the seed values are very close to each other, the resultant 
sequence of values from iterating the function gives starkly different results. Unsurprisingly, a 
seed of x=1.0 results in subsequent values of 1 forever. However, a seed of c=0.9 results in a 
sequence which converges towards zero. A seed value of x=1.1 very rapidly diverges to ever 
larger values ­ it explodes!.  
 
We can start to think about ​ regions ​
of the input space and categorising them according to how 
they impact the evolution of values from an iterating function. So for this “square the input” 
function, we have 3 regions; convergence to zero where the seed x is less than 1, convergence 
to a finite value when the seed x is exactly 1, and divergence when x is more than 1. The 
following shows these three regions for the “square the input” function.  
 

 
 
This idea of marking regions according to the kind of function behavior that results from them is 
a core idea in making our own Mandelbrot set. This is because the Mandelbrot set is just that, a 
kind of atlas marking out the regions according to their behaviour when a function is applied 
iteratively.  
 
All of this helps us answer the question we asked ourselves above; do all functions diverge to 
ever bigger numbers or converge towards zero, and nothing else? We’ve done some really 
good mathematical research and shown that there is another case, which is functions 
converging to non­zero values.  
 
Let’s summarise what we’ve found so far: functions which diverge, and functions which 
converge towards zero, and some which converge towards non­zero values. 
 
 
 

Periodic Cycles ‘Flip Flopping’ 
Are there really no other kinds of function behaviour beyond diverging or converging towards 
zero or a non­zero value?  
 
We already know the answer to this question because we saw the flip flopping function “multiply 
by ­1, with starting value 4” which resulted in values +4, ­4, +4, ­4, … and these don’t grow ever 
larger, nor do they get ever small towards zero. Let’s plot it, so we can visualise it. 
 

 
 
We have a new interesting class of function here, whose values flop flop between two values. A 
more scientific way to say this is that the values ​
cycle ​
between two values. Some people say 
the function is ​
periodic​

 
We can now update our “world map” of functions to include periodic functions.  
 
 
 

Chaos 
We’re now ready to explore a really interesting behaviour of functions, which was only really 
appreciated in the last 100 years of history. Given that many mathematical ideas go back 
thousands of years BC, this is really remarkable. It’s amazing that here we are, having covered 
some fairly basic concepts using only school mathematics, and we can now explore some really 
interesting behaviour of functions that seemed to elude mathematicians for those thousands of 
years. 
 
Let’s look at an iterative function which has was developed by scientists trying to model 
population growth. Its’ called the Logistic Map, but the name doesn’t really explain much so let’s 
not worry about it. The following diagram shows this function. 
 

 
 
This function seems to contains strange new symbols but don’t worry it doesn’t contain any new 
concepts that we haven’t already done. Let’s explain it. The input is the same as before, its the 
number we put into the machine to get an output, another number. We’ve now given a name to 
the input and called it x.  
 
Mathematicians often call things x when they really just want to say “any number” or 
“something” but want to use less words. They’re not just being lazy, it’s a neat way of saying 
something that applies to numbers in general. An example is saying “if x is a whole number, 
then 2x is always even”. But why did we bother naming the input x when we haven’t before? We 
did this because we use this input value more than once in the function and it would get terribly 
wordy if we didn’t have a concise way of recalling the input value.  

www.allitebooks.com
 
Looking at the function we recognise some parts of it easily. We can see that we need to take 
the input value x from 1. That’s the part shown as (1­x). Then we can see we need to multiply it 
by the input value again. That’s the x * (1­x) part.  
 
It does seem odd that we’ve used the input value twice, but that’s fine, there’s nothing weird or 
rule breaking about it. In fact the function we used before “multiply by 2” could have been written 
as “x + x” which is the same thing as multiplying x by 2, and uses the input value twice.  
 
All this leaves us with the part where we have to multiply the x * (1­x) with something called r. 
Again mathematicians like to give short names to things they don’t want or need to be specific 
about. So here r is just a number we haven’t specified. It could be 1, or it could be 2, or it could 
be a small 0.25 or a big 7.18. We do however need to stick to a value we choose for the 
duration of all the iterations of this function, and make sure we’ve told anyone reading our 
results which one we chose. 
There’s one more thing. The diagram of the function says the seed value for x must be between 
0 and 1. That’s fine, mathematicians sometimes do define functions which are only valid for 
certain ranges of input. Nothing will prevent us from trying seed values greater than 1 or less 
than 0 but the function was designed to be used for seed values between 0 and 1. 
 
So let’s try it. We need to make two choices, firstly the value of r we’ll stick to, and secondly the 
starting value of x we use as the first input. We’ll choose a starting value of x as 0.2 and set r as 
1. This time we’ll also do more iterations than the 10 we did before; we’ll do 50 iterations. 
 
Because this function seems like it’s a little more complex than those we looked at before, we’ll 
show the table for the first 10 and the last 10 iterations. And to avoid any doubt, let’s explain the 
very first iteration. We start with x as 0.2 and r=1. Then r.x.(1­x) is 1 * 0.2 * (0.8) = 0.16 which is 
the output value. This is then put back into the function as input for the next iteration which gives 
0.1344, and so on. 
 
 
Function “r.x.(1­x)”, initial value x=0.2, r=1   

Iteration  Value 


0.2 (initial value) 

0.16 

0.1344 

0.11633664 

0.10280242619351 

0.092234087362238 

0.083726960490693 

0.076716756577683 

0.070831295837884 

0.06581422336781 
10 
0.061482711370302 
… (not showing iterations 11 to 40) 
... 
41 
0.020671254252617 
42 
0.020243953500241 
43 
0.019834135846921 
44 
0.019440742902127 
45 
0.01906280041754 
46 
0.018699410057781 
47 
0.018349742121272 
48 
0.018013029085355 
49 
0.017688559868525 
50 
0.017375674718303 
 
 
Let’s plot a graph to visualise how the function behaves. 
 
 
 
The values seem to get smaller but at a slowing rate, like a gentle children’s slide. Nothing 
exciting here, we’ve seen this kind of behaviour before. 
 
Let’s try this again but this time set r as 2, not 1 as we did above. The following is the resultant 
graph of successive function values. 
 

 
 
This is surprising! The same function but with the innocuous parameter r changed from 1 to 2 
has changed the behaviour entirely. With r=1 we had the values converging towards zero, now 
we have them converging towards 0.5. We didn’t change the function, only the value of one 
parameter within the function, and we got different behaviour. 
 
We’ve tried r=1 and r=2, now try r=3. Will we be surprised again? The following is the graph for 
this function with r set to 3. 
 

 
 
Wow! The same simple innocent looking function, has now given us behaviour which oscillates, 
like the periodic flip­flopping function we saw earlier. Again, we didn’t change the function to get 
this very different behaviour, we simply modified the value of one of its parameters 
 
It’s really worth taking a step back here to appreciate what we’ve done. We’ve found a function 
which is really simple in its makeup. It’s doing nothing more than really basic school maths, 
multiplying and subtracting. And by varying one part of it, the parameter r, we’ve had the 
function behave in very different ways. We’ve seen it converge to zero, converge to a finite 
non­zero value, and we’ve seen it show flip­flopping oscillatory behaviour. This is amazing 
because we’ve managed to crack open really interesting and varied behaviour from a really 
simple function. We didn’t need advanced mathematical operators, or a large complex function 
of many parts. Just three bits multiplied together, r, x, and (1­x). 
 
For those of us who suffered through school plotting boring uneventful graphs of equations like 
y=x+3 or y=(x­3)(x+4) this is a real discovery. We’ve opened a crack into a much more 
interesting world, one with unexpected behaviours around each corner. 
 
Could there be more? Let’s try the same function and try r set to 4.  
 
 
 
Whoa! What’s going on here? Has there been an error? Did my computer go wrong? The 
answer is no, nothing went wrong. Try it yourself. The behaviour we’re seeing appears 
unpredictable, unruly, random. There is no discernible pattern like a gentle convergence, or 
even a rapid divergence, not even something we can pick out as a regular periodic oscillation. 
What we have found, is ​ chaos​ . This is one of the major discoveries of the last hundred years, 
and we did it here too. 
 
The thing to note about this is that the behaviour of the function can vary drastically with small 
changes in one of the starting conditions, in this case the parameter r. Mathematicians say that 
this function is highly sensitive to initial conditions. You may have heard the popular phrase, 
“​the butterfly effect​”, which suggests that the weather system is similarly highly sensitive to 
some conditions, so that the tiny air movements caused by the wings of a butterfly in one 
continent can lead eventually to tornados in another continent.  
 
There are two amazing things here. First that such rich and varied behaviour can emerge from 
such innocently looking simple mathematical functions. Second that such behaviour was only 
really discovered and studied in the last 100 years when the basic mathematics to do so has 
been around for thousands of years, practised by great ancient civilisations. 
 
We need to update our world map of function behaviours to now include chaos. 
 

 
 

Milestone Check 
Let’s pause for a moment and see where we are. We’ve done a lot of work, what’s left? Where 
are we on this journey to the Mandelbrot Set. 
 
We’ve built up almost all the key mathematical concepts needed to understand and make our 
own Mandelbrot set. We’ve covered the idea of functions, iterating them repeatedly to get a 
sequence of values, different types of behaviour including convergence, divergence, oscillation 
and chaotic behaviour. These are almost all the ideas we need to understand.  
 
The remaining one concept is about changing the things we apply these functions to. We’ve 
applied these functions to numbers. That’s what most people do, and that’s what we do lots and 
lots when we’re at school or at work. But there isn’t a reason why we couldn’t invent functions 
which work not on ordinary numbers but on very different things, like words for example. We 
could have functions which count the letters in a word, or join them together to make compound 
words like “top­floor”, or even join lots together to make sentences. These functions are just 
machines that do some work, after all. 
 
What we’re doing here is challenging ourselves to let go of habits and specifics, and think more 
generally, to let go of the comfortable world of numbers that we’ve been using since we were 
small children, and go on a holiday to another land with different kinds of objects. The idea of 
functions as machines that do something to objects and give a result is generic enough to apply 
when we move away from the familiar number system. 
 
We’re going to try to apply functions to an extension of the normal numbers called complex 
numbers. It’s a terrible name because they’re not complex. They have 2 pieces to them, and it 
would have been better if history had called them 2d numbers or something else that was 
actually descriptive. 
 

Complex Numbers 
We’re now going to introduce the last idea we need to understand before we can make our own 
Mandelbrot set. 
 
The big idea is simple. We previously had functions which we thought of as machines. These 
machines took a number as input, did something using this input, and then pushed out an 
output number. We’re now going to challenge ourselves and see if we can work in a world 
where the basic units of currency aren’t the numbers we’ve been used to but something else. 
This might seem like a difficult thing to do, especially as we’ve been working with numbers like 
2, 4, 10.4, ⅗
, ­16 and so on, since we were very young children. Our entire world seems to work 
on these numbers, from fuel prices to the size of our shirts, from the length of our mortgages to 
the rate of interest on our credit cards.  
 
Can it be possible to live in a different universe, where functions take an entirely different kind of 
animal as input? Well yes. Think of a function which operates on words. Words aren’t numbers. 
and yet it’s not so hard to think of a useful function which counts the letters in a word, or 
perhaps takes two words and joins them together. So it’s not so far fetched to contemplate 
functions which work on things that aren’t the very familiar numbers we’ve been used to. 
 
The objects we’re going to look at are actually not that different to ordinary numbers. They’re 
called complex numbers. I really dislike this name as there’s nothing complex about them, and 
the name puts off a lot of people. The term “complex” doesn’t even portray any aspect of these 
things, so it’s not even informative. I wonder how many books entitled “Complex Analysis” have 
scared potential readers away? Anyway, rant over, let’s make a gentle start. 
 
The normal numbers we’ve been very used to have only one direction to them. They can only 
describe one aspect of any physical object. They can’t describe two or more aspects at the 
same time. For example, we might say that a road is 10 miles long, or a box contains 15 apples. 
We can’t use those same numbers, 10 or 15, to say anything about the road’s width or the 
weight of those apples. For that we need another number, and that’s fine. We are very happy to 
use pairs of numbers to describe the length and width of a swimming pool, say (5,25) to mean it 
has a width of 5m and a length of 25 metres. The important point here is that a single ordinary 
number can’t tell you both, it can only tell you about one physical aspect. Mathematicians like to 
call these object, these numbers, ​ 1­dimensional​ , and for once the name is actually informative. 
 
Complex numbers were intentionally designed to be ​ 2­dimensional​ . That is a single complex 
number would have within it 2 parts that told us about 2 different things. In fact I wish they were 
called “2­d” numbers or something informative like that, instead of the horrible “complex” 
numbers. I’m ranting again! 
 
If we had to write a complex number, what would it look like? It would have to have 2 parts, so 
why not something like the following? 
 
(2, 3)  
 
That should work, shouldn’t it? In fact you could indeed write complex numbers like this, and in 
the early history people did. If you recall doing vectors at school mathematics, this isn’t very 
different at all. Vectors could be composed of more than one component, and complex numbers 
can be thought of as vectors with 2 parts.  
 
As it happens, history took a different course and the following become the convention for 
writing complex numbers. If you ever think how strange it looks, just keep in mind that it’s only 
an accident of history that complex numbers came to be written like this. Myself I still think the 
term “complex” was a bad accident of history. 
 

 
 
The illustration shows a complex number with the 2 parts we expected. The first part that looks 
like a familiar number 2.The second part also has a familiar number 3 but it’s got an “i” added to 
it. Well someone had to think of something to distinguish the two otherwise we wouldn’t know 
which of the two numbers referred to the first or second part, the width or the length if we using 
the earlier swimming pool analogy. We could have written it as (2a, 3b) or (2x + 3y) which would 
have been perfectly fine. Again it’s just how history turned out that the first part was not given a 
special appendage, but the second part was given an “i”.  
 
Even weirder are the names that seemed to have become attached to these parts. The first part 
is now commonly called the “real” part, and the second part is called the “imaginary” part. Trying 
to find meaning in these names isn’t fruitful, so let’s not worry too much about the names 
themselves. 
 
Naming conventions aside, it’s worth remembering where we started this discussion. We 
wanted an object which told us about two different independent things. That’s the most 
important thing to remember about complex numbers. The two parts are different, and always 
remain different, like apples and oranges. You can’t compare apples and oranges, which is why 
we need to write them both down separately. We can compare apples with apples, and collect 
them together if we find sets of them. Mathematicians call these apples and oranges 
independent​ . The real and imaginary parts of a complex number, like apples and oranges, are 
independent. You can’t combine them, and you need to keep track of them separately. Two 
oranges + 3 apples doesn’t equal 5 apples. This insight will help us when we try to do arithmetic 
with complex numbers. 
 
So what can we do with these new kind of object, these complex numbers? Can we add them? 
Can we multiply them? Can we subtract and divide them? The answer to this question is yes but 
the reason why is interesting as we’ll see. Mathematicians are quite fond of inventing new kinds 
of objects, and when they do, the challenge for them is not finding out whether they can add and 
subtract these objects but whether the rules they’ve defined for them allow them to do arithmetic 
in a way that’s consistent.  
 
Let’s dig a little bit deeper into this. We may not be conscious of it, but we are already very 
familiar with the rules governing the familiar normal numbers. These rules tell us that 2+3 is the 
same as 3+2. These rules tell us that multiplying two negative numbers gives a positive number, 
for example, ­3 * ­4 = +12. These rules also tell us that dividing by zero is undefined, 12/0= ?.  
 
These are the ​ rules of arithmetic​ , and we need to stick to them, otherwise law and order would 
break down and anything would go, which might be fun for a short while but would eventually 
confuse everyone and not be productive. Rules allow us to do mathematics which is 
unambiguous and have other people agree with us on the answers. These rules need to be 
consistent, we can’t have rules that contradict each other.  
 
As an example of consistent rules framework, consider criminal law or financial regulations for 
companies. We know these rules need to unambiguous and consistent. If they weren’t then it 
would be impossible for citizens to agree what was legal or not, and even worse for the police 
and regulators to decide if a crime had been committed or not.   
 
So for complex numbers, the key question was not whether we can add or multiply them, but 
instead, what were the consistent and logical rules governing arithmetic, rules that didn’t 
produce contradictory results.  
 
As it turns out, most mathematicians have reached a consensus around the rules of arithmetic 
for complex numbers. These rules are simple, and very familiar if you did a little bit of algebra or 
vectors at school.  
 
The following table shows the rules for adding, subtracting and multiplying. We’ve left out 
dividing because it is a little bit more involved, and actually we don’t need it for the purposes of 
making our own Mandelbrot set.  
 
 
Operation  How to do it 

Addition   
  +​
(a + bi) ​ (c + di) = (a+c) + (b+d)i 
Add the two complex numbers   
(a + bi) and (c + di)  That is, add the real and imaginary parts 
independently. 
 

Subtraction   
  ­​
(a + bi) ​ (c + di) = (a­c) + (b­d)i 
Subtract the complex number (c + di) from    
(a + bi)  That is, subtract the real and imaginary parts 
independently. 
 

Multiplication   
2​
  *​
(a + bi) ​ (c + di) = (ac + adi + bci + dbi​ ) 
Multiply the two complex numbers  = (ac­bd) + (ad+bc)i 
(a + bi) * (c + di)   
That is, expand out the terms and apply the 
2​
special rule that i​ is ­1. Then collect real and 
imaginary parts to make a neat answer. 
 
 
If these rules leave you a little lost, let’s go back to something really familiar. All these rules are 
doing is helping us to addition, subtraction and multiplication for complex numbers in a way that 
makes sense for us if we’re only used to doing arithmetic with ordinary numbers. They do this by 
breaking down the task into smaller easier tasks, each one only using ordinary number 
arithmetic. Why all the brackets? The brackets are needed to keep the real and imaginary parts 
collected together neatly, so we don’t lose them. But what do we mean when we expand 
brackets? It’s easiest to think about a simple example 3 * (4 + 5). We could do the addition first 
to make 3 * 9 = 27. Another way is to expand this as (3*4) + (3*5) which is each element of the 
bracketed sum multiplied by 3 individually. This is 12 + 15 = 27 as we expected. Why would we 
do this the long way around? It’s useful when the things inside the brackets can’t be combined, 
like apples and oranges, or the real and imaginary parts of a complex number. It is common for 
mathematicians to break everything out into such small pieces then collect all the similar kinds 
of things with the hope of ending up with a much tidier result. 
 
So the rules for complex numbers are exactly the same as for normal algebra but with only one 
extra special rule applied which is that whenever we come across an imaginary part multiplied 
2​
by an imaginary part, the resultant i​  is replaced by ­1.  
 
All this may look really difficult but it’s really nothing more than the school algebra we learned 
when adding and multiplying expressions like x, y, (x+y), (3x + 4y), and so on. Exactly the same 
2​
except with the special rule about i​  being the same as ­1. 
 
It’s worth that there are no more special rules for working with complex numbers around the 
2​
corner. Normal algebra with this special rule that i​  = ­1 is all there is to working with complex 
numbers. 
 
Let’s help this settle in our minds by gently working through some examples of addition, 
subtraction and multiplication. 
 
Example 1: Add two complex numbers. (2 + 3i) ​ +​
 (4 + 5i) 
Let’s apply our school algebra here, and expand this out first: 
 
(2 + 3i) + (4 + 5i) = 2 + 3i + 4 + 5i 
 
Again like school algebra, let’s collect terms. This means bringing together objects or animals of 
the same type. In this case this means collecting real parts and imaginary parts. 
 
(2 + 3i) + (4 + 5i) = 2 + 3i + 4 + 5i = (2+4) + (3+5)i = ​ (6 + 8i) 
 
That was as easy as doing something familiar from school like (2x + 3y) + (4x + 5y) = (6x + 8y). 
 
Example 2: Subtraction (8 + 6i) ​ ­​
 (5 + 4i) 
Again let’s apply the same school algebra and expand out the terms with the aim of collecting 
similar animals together later. 
 
(8 + 6i) ­ (5 + 4i) = 8 + 6i ­5 ­4i 
 
Collecting terms gives us the very familiar 
 
(8 + 6i) ­ (5 + 4i) = 8 + 6i ­5 ­4i = (8­5) + (6­4)i = ​(3 + 2i) 
 
Again that was as easy as doing school algebra like (8x + 6y) ­ (5x +4y) = (3x + 2y) 
 
Example 3: Multiplication (8 + 6i) ​ *​
 (5 + 4i) 
 
Lets do what we always do and expand out the terms. 
 
2
(8 + 6i) * (5 + 4i) = 40 + 32i + 30i + 24i​  
 
Before we collect terms in the way that we are familiar with, we must apply that single special 
2​
rule for complex numbers. Whenever we see an i​  we must replace ti with a ­1.  
 
2​
(8 + 6i) * (5 + 4i) = 40 + 32i + 30i + ​ 24i​  ​= 40 + 32i + 30i ­​
24 
 
Now we can collect the terms as usual 
 
2​
(8 + 6i) * (5 + 4i) = 40 + 32i + 30i + 24i​  = 40 + 32i + 30i ­24 = ​(16 + 62i) 
 

 
Visualising Complex Numbers 
Before we move onto functions which operate on complex numbers, let’s see how we might 
visualise complex numbers. We found earlier that visualising the sequences of values from 
iterative functions helps us to quickly get a feel for the behaviour of a function in general terms. 
 
The plain old numbers we’ve used since we were children are 1 dimensional as we’ve already 
discussed. That means that can be used to describe one physical aspect of an object, such as 
length or width, but not both at the same time. Visualising these familiar numbers is easy, we 
can plot a bar of the right length on a chart, or a dot at the right height on an x­y graph. We did 
this when we plotted the value of functions as they evolved over many iterations. We plotted the 
1­dimensional output values at the right height vertically above the horizontal axis representing 
iterations. 
 
Because complex numbers are two dimensional, that is they have 2 independent parts, any 
visualisation must be able to show both of these parts. Why not simply use the familiar x­y plot 
and have the x­axis represent the real part, and the y­axis represent the imaginary part? You 
can indeed do this, and this is in fact the most common way to show complex numbers. In fact 
because complex numbers have 2 independent parts, they can be used as coordinates on a 
2­dimensional plane such as your graph paper or your computer screen. 
 
Let’s plot a couple of examples. The following plots show (3 + 2i) and (­2 ­ 2i). There’s nothing 
unfamiliar here, these are just like plotting coordinates (x,y), and this time we’re using the real 
part as the horizontal x value and the imaginary part as the vertical y value. 
 

 
 
It’s useful to ask how far these points are from the origin. If you remember doing vectors then 
this is the same as asking what the magnitude of the vector was, irrespective of direction. The 
same idea applies to complex numbers. The magnitude of a vector or a complex number tells 
you one thing, its a 1­dimensional quantity, and that is its size. A 1­dimensional quantity can’t 
tell you which direction a vector was pointing, nor can it tell you whether the real or imaginary 
part of the complex number contributed most to its magnitude. Nevertheless, it’s a useful 
quantity to know. Like the wind, it’s sometimes useful just to know that its going to be a strong 
80mph and we don’t care which direction it’s blowing because our trees will suffer regardless. 
 
The following diagram illustrates this familiar idea of a magnitude. Just like vectors, we work out 
the magnitude by squaring each horizontal and vertical component, summing these squares, 
and taking the square root. This is just the Pythagoras theorem many of us learned at school for 
working out the long side of a right angled triangle from its shorter sides. So for the example 
2​ 2​
shown, the magnitude is the square root of ( 3​  + 4​) = sqrt(25) = 5. 
 

 
 
Visualising how a function changes a complex value over many iterations might be a challenge 
because paper and computer screens only allow us to see 2 dimensions easily. There are two 
ways to do this as shown below. 
 

 
 
The first way we can visualise the evolution of complex numbers is simply to plot them on the 
grid as we did above and see if we can follow successive iterations. If the values move around 
gently we can see the progression, but if they are densely packed or jump around wildly then we 
can’t easily follow their evolution. Adding connecting lines helps. Some people call this kind of 
plot an ​orbit plot​

 
The second way discards the real and imaginary components and instead combines them into 
the magnitude, as we did earlier, and these are plotted against the iteration number, just as we 
have been doing for many of the plots earlier. 
 
In reality, when exploring complex numbers, looking at both kinds of plot together is useful to 
get the most insight visually. 
 

Complex Functions 
Now that we can do the basic operations with complex numbers and visualise the results, we 
can now try to define iterative functions in the way we did for normal numbers. 
 
We’re doing this to see if we can find interesting behaviour, just as we did before. 
 
We’ll work with a function that’s slightly simpler than the Logistic Map we explored earlier, but 
retains a parameter we can tune. We’ll call it the Test Map for now. 
 

 
 
This looks just like the functions we worked with before. There is a machine which takes an 
input, does something to it, and throws out an output. In this case however, the function works 
on complex numbers, not just normal numbers.  
 
Let’s unpack how this function might work on complex numbers. First we need to see what that 
2​
z​  + c looks like in terms of real and imaginary parts. 
 
Any complex number z consists of two parts (a + bi), where a is the real part and bi is the 
imaginary part. The function squares this complex number, which means the multiplying it by 
2​ 2​ 2​
itself. So z​ is (a + bi)(a+bi) = (a​ ­ b​
) + (2ab)i. We worked through how to multiply complex 
numbers earlier. We then add the complex number c, which we keep constant just like we did 
2​ 2​ 2​
with the r parameter for the Logistic Map. If c = (e + fi) then z​ + c becomes (a​  ­ b​  + e) + (2ab + 
f)i. 
 
The diagram also states that the starting value of z is always zero. What does this mean if it is a 
complex number. It just means that both real and imaginary parts are zero, (0 +0i). It’s become 
conventional to shorten this to simply zero, and everyone understands you mean that both parts 
are zero.  
 
If we have no choice about the starting value of z, only the complex number c remains to vary 
and explore. We can investigate how this Test Map behaves with different c. As a reminder, 
varying c means trying different values for both it’s real and imaginary parts. Because c is 
2­dimensional, we’re exploring not points on a 1­dimensional line, but a 2­dimensional plane. 
You can probably guess already that the Mandelbrot set lives in such a 2­dimensional plane of 
complex numbers. 
 
Now let’s try this function with an example, just to be really sure we understand the calculations. 
2​ 2​ 2​
Let’s set z = (1 + 2i) and c = (10 + 11i). Using the above results, z​  becomes  (1​  ­ 2​) + (2*1*2)i 
2​
= (­3 +4i), and so z​  + c becomes (7 + 15i).  
 
Because we’re new to iteratively applying a function to complex numbers, let’s try iterating the 
Test Map a few examples of c. 
 
Example 1: c = (2 + 2i) 
The following table sets out the iterations of the Test Map with c set to (2+2i) 
 

Function: z2​ + c,        
for complex z, c, 
seed z=(0+0i), 
c set to (2 + 2i) 

iteration  real  imaginary  magnitude 

0 (initial value)  0  0  0 
1  2  2  2.82842712474619 
2  2  10  10.1980390271856 
3  ­94  42  102.95630140987 
4  7074  ­7894  10599.8449045257 
5  ­12273758  ­111684310  112356709.793491 
 
The table shows the initial value for z as (0+0i) as required by the definition of the Test Map 
function ­ we don’t have a choice about the initial value of z. The magnitude of this z is also 
zero, worked out using Pythagoras’ formula as we did earlier. 
 
To work out the next iteration of z we use this current value and also the value of c, set at (2+2i) 
for this example. This leads to an output value of (2+2i). Iterating again leads to (2+10i), and so 
on, as shown in the table. We can see the by looking at the table that the real and imaginary 
parts of the Test Map output grow in size quickly. The column of magnitudes for each output 
shows that the complex numbers are getting further and further away from the origin point (0+0i) 
at an ever quickening pace. This looks just like the early example of divergence we saw using 
ordinary numbers.  
 
Indeed this Test Map function does diverge for c=(2+2i). Let’s plot an orbit plot and a magnitude 
plot to confirm it. 
 

 
 
The orbit plot does show the outputs getting larger and larger because they are moving further 
and further away from the origin at (0+0i). What is surprising is that the curve coils around, 
almost like a backwards running clock. This is not unusual for functions working on complex 
numbers, but does surprise us if we’ve been used to looking at relatively uneventful graphs of 
boring functions working on ordinary numbers.  
 
The second plot showing the magnitude of the Test Map function outputs does indeed confirm 
the magnitude diverges. In fact it blows up so rapidly that we were only able to plot the fifth 
iteration before the magnitude reached almost 120,000,000. The plot might be misleading as it 
seem to show zero magnitude for iterations before the fifth one.  The magnitudes are in fact 
non­zero but since they are much smaller than the output 112,356,709 they appear like zero in 
comparison when plotted. 
 
Example 2: c = (0.4 + 0.4i) 
The following table sets out the iterations of the Test Map with c set to (0.4+0.4i) 
 

Function: z2​ + c,        
for complex z, c, 
seed z=(0+0i), 
c set to (0.4 + 0.4i) 
iteration  real  imaginary  magnitude 

0 (initial value)  0  0  0 
1  0.4  0.4  0.565685424949238 
2  0.4  0.72  0.82365041127896 
3  0.0416  0.976  0.976886155086661 
4  ­0.55084544  0.4812032  0.731428204582674 
5  0.471874179078554  ­0.130137176866816  0.489490475580398 
6  0.605729556078194  0.277183252996741  0.666137261267182 
7  0.690077739364831  0.735796177580052  1.00876325334951 
8  0.33481127142546  1.41551312571545  1.45457072586597 
9  ­1.49157882159919  1.34785949868043  2.01035633886789 
10  0.808082152860167  ­3.62087736544608  3.70995278425089 
11  ­12.0577561298287  ­5.45193275342464  13.2330288911604 
12  116.065912138556  131.876151154039  175.677588791963 
 
The magnitudes seem to be growing but not at the rapid rate as before. Let’s see what the orbit 
and magnitude plots show us. 
 

   
 
The orbit plot is interesting. It shows the Test Map outputs apparently orbiting not far from the 
origin before finally relenting to some external force and diverging. The magnitude plot shows 
this too, with the magnitude actually falling after the third iteration, before relenting and diverging 
after about the eighth iteration.  
 
Could there be values of c which result in orbits which don’t eventually diverge? Which are 
somehow trapped in an orbit, and don’t escape? 
 
Example 3: c = (­0.3 + 0.4i) 
Lets not waste space with the table and jump straight to the resultant plots for the Test Map with 
c set to (­0.3 + 0.4i). 
 
 
 
The orbit plot now shows the values first circulating a point and then falling into it, almost like an 
asteroid getting trapped by the gravity of a planet, circulating it before falling into it. The Test 
Map for c=(­0.3+0.4i) converges to a non­zero value. If we did present the table of values, we’d 
see it approached a value of z=(­0.284 + 0.255i) approximately. 
 
We can see the value of plotting magnitude plots now. The plot shows the magnitude oscillating 
before settling down and approaching 0.3819 approximately. This is characteristic of orbits 
which get trapped and fall towards an ​ attractor​ point. The word attractor is actually used by 
mathematicians to describe points which seem to pull in successive values of an interactive 
function. 
 
These kinds of orbit plots remind me of a spider circling a bath drain before falling into it! 
 
When we were exploring different kinds of behaviours for functions working with ordinary 
numbers, we found divergence, convergence, oscillation and chaotic behaviour. I wonder if we 
can find oscillatory behaviour for complex functions? 
 
Example 4: c = (0.3 + 0.5i) 
Again jump straight to the resultant plots for the Test Map with c set to (0.3 + 0.4i). 
 

   
 
The orbit plot shows the values visiting approximately the same four points repeatedly in turn. 
So this is not a divergence, nor is it a convergence to a single point. Instead of falling into a 
point attractor, the values from this Test Map seem happy to cycle around these four points in 
turn. This is a more interesting kind of attractor.  
 
The magnitude plot reflects the periodic nature of the orbit.  
 
What is not clear is whether with this, or similar orbits, is whether these orbits will remain cycling 
or whether they are converging to a single points very slowly. The above plots were from 50 
iterations, so it would take many many more to see any convergence if it was there at all.  
 

The c=(0.33 + 0.577i) Neighbourhood 
Now that we know how to apply iterative functions to complex numbers, and follow sequence of 
outputs visually using orbit and magnitude plots, let’s now look more closely at the behaviour of 
the same Test Map function for values of c close to (0.33 + 0.577i).  
 
What do we mean by “close to” when talking about complex numbers? Well, the ordinary 
numbers 1.4 and 1.6 are close to 1.5 compared to the number 99.8 which is much farther from 
1.5. In the same way, we can think of complex numbers which are close together. We do this by 
picking real and imaginary parts which differ very slightly from each other. If you think back to 
complex numbers as grid references on a 2­dimensional flat map, then such complex numbers 
are close together on this 2­dimensional plane.  
 
Let’s consider the Test Map function for the three values of c as (​
0.32​ + 0.577i), (​
0.33​
 + 0.577i), 
and (​0.34​ + 0.577i). The imaginary parts of these three choices don’t change but the real part 
changes by 0.01. These are close together compared to a large complex number like (100 + 
100i). 
 
The following diagram shows these three choices for c represented on the 2­dimensional 
complex plane. You can see that because the imaginary part doesn’t change, the three points 
are at the same height. The only difference is small changes in the horizontal real value. 
 
 
 
Mathematicians call this ​ exploring the neighbourhood​  of c=(0.33 + 0.574i), and their choice of 
words actually conveys the right sense. 
 
Let’s look at just the orbit and magnitude plots for these three orbits. 
 
For c = (0.32 + 0.577i): 

   
We can see that the Test Map output values do escape and diverge, despite circulating around 
a finite point initially. The magnitude plot confirms the eventual escape and divergence. 
 
For c = (0.33 + 0.577i): 

www.allitebooks.com
   
We can see that for this value of c, the Test Map values don’t escape and diverge. They seem 
to have a roughly stable periodic orbit, and the magnitude plot confirms this.  
 
How do we know that the values don’t escape at a later iteration, perhaps after thousand 
iterations, or maybe a billion iterations? We can’t easily say for sure. If the orbit obviously 
collapses or explodes then we have some certainty about the ultimate fate, If the orbit is only a 
roughly regular then we can’t be as certain. This uncertainty may seem uncomfortable but we 
can live with it for the purposes of making our own Mandelbrot set.  
 
In fact, if you came up with quick mathematical shortcut to knowing the ultimate fate of output 
values from iterative functions working on complex numbers, you’d have done something 
mathematicians still haven’t found. As it is, we too often have to do the hard work of calculating 
many iterations and seeing how confident we are in further projecting the results we have. 
 
For c = (0.34 + 0.577i): 

   
For this choice of c, only 0.01 real part units far from the previous one, the orbits again escape 
after initially going round a fixed point. The magnitude plot has the now familiar signature of a 
divergent sequence. 
 
What does this all tell us? It tells us that close to c = (0.33 = 0.577i) the behaviour of the Test 
Map iterative function different drastically. Remember when we found functions that were 
sensitive to even small changes in starting conditions? This Test Map is highly sensitive to 
choices of c.  
 
The three points we just tested are all on a the same horizontal line because we didn’t change 
the imaginary values. So let try exploring two further points just above and below the middle 
(0.33 + 0.577i) point. That will give us a fuller view of how the Test Map function behaves in the 
neighbourhood of this middle point. We’ll choose points 0.01 imaginary part units above and 
below the middle point. 
 
For c = (0.33 + 0.587i): 

 
For this choice of c just 0.01 imaginary part units greater than the middle point, the orbit 
circulates then diverges. The magnitude plot confirms this. The divergence is actually much 
sooner than at the other choices of c. How quickly or slowly an orbit takes to escape and 
diverge is worth keeping in mind as something to distinguish otherwise similar behaviours. 
 
For c = (0.33 + 0.567i): 

   
For this c just below the middle point, we see a very regular periodic oscillation, and the 
magnitude plot confirms this.  
 

Divergence Atlas 
We did a lot of work in that last section exploring the neighbourhood of the point (0.33 + 0.577i) 
to see how the Test Map behaved when applied iteratively. Let’s summarise the results by 
drawing a different kind of diagram. For each point we tested, we’ll colour it black if it appeared 
to converge or at least not escape, and we’ll colour it blue if the sequence of Test Map values 
exploded and diverged. We’ll call this diagram an atlas, as it tells us about the land of complex 
numbers by colouring regions according to how they behave. We saw at this idea of colouring 
regions marking common behaviour when we looked at the simple function “square the input” 
for ordinary numbers.  
 

 
 
Ok so it’s not a very complete atlas, but its a start. The five coloured points look simple, but you 
now know the work that went into them. For each point we iterated the Test Map function to see 
if the values escaped and diverged, or whether they converged or at least remained in an orbit 
without escaping for all the while we kept iterating.  
 
You may be wondering why I’ve chosen my words carefully in that last sentence. It’s because 
we don’t know for certain whether a fairly regular and stable orbit won’t break out and diverge at 
a much later iteration. We know this because we saw examples ourselves of apparently stable 
orbits suddenly exploding. This is why it is more correct to say that a point we test either does 
diverge, or that for all the iterations we’ve done it hasn’t yet. 
 
We chose the word atlas to avoid confusion by using the word map which we’ve used a few 
times already more properly when referring to functions which take an input, do something and 
pop out an output.  
 
What does this small atlas show us? It doesn’t show us much, but it teases us to the possibility 
that the regions of convergent and divergent points might be interesting shapes, not just a 
boring circle or square.  
 

We’re ready! 
All the hard work learning new concepts and crunching through calculations is mostly behind us. 
We have enough now to make our own Mandelbrot. At last! 
 

 
   
Now We Can Make Our Own Mandelbrot 
 

Completing the Atlas 
The Mandelbrot set is simply the points on the atlas we started making that don’t diverge. 
 
That’s it! It’s as simple as that. If we complete the atlas we started and mark the regions that 
diverge and those that we don’t think diverge we have plotted the Mandelbrot set. 
 
It’s worth restating that last point, because too often the simple explanation of what the 
mandelbrot set is isn’t presented well. 
 
The mandelbrot set is the set of complex numbers, for which the iterated function 
described above doesn’t diverge.  
 
Because complex numbers can be thought of as coordinates on a flat 2­dimensional surface, 
this particular set of numbers can be marked out by visually, by colouring them a colour distinct 
from those numbers for which the iterated function does diverge. This coloured atlas of 
diverging and non­diverging regions is the most common representation of the map.  
 
The previous section chose some points in the neighbourhood of (0.33 + 0.577i) and coloured 
them according to whether they diverged or not. Let’s make a fuller atlas, showing many points 
in a preselected box. What location and size of box shall we choose? Let’s try a box of width 10 
units wide along the real axis, and 10 units high along the imaginary axis, and lets test and 
colour many points 0.1 units apart. This means the bottom left corner of this atlas is at (­5 ­5i) 
and the top right is at (5 + 5i).  
 
Naively we might expect a box or a circle or other boring shape to show which points diverge 
and which ones don’t. We know we’re in for a surprise because the points we tested in the 
neighbourhood of (0.33 + 0.577i) were coloured in a way that suggested an atlas that wasn’t 
going to be boring. 
 
The following is the result. 
 
 
 
This is interesting! The black region in the middle isn’t a boring circle or square, or any other 
regular shape. Remember this is the region which has the complex numbers which don’t 
diverge when iterated with the Test Map function. The surrounding white space are the points 
which do escape and diverge.  
 
It does make some sense that large initial values of the parameter c result in divergence, a bit 
like large initial values diverging under the “square it” function we saw earlier. Similarly, it makes 
sense that small values don’t diverge, again like small values under the “square it” function. 
 
 
 
The unusual behaviour here is that we would have expected a circular border between these 
two regions. What we see instead is a strange shape! It kind of looks like a beetle with arms and 
legs.  
 
2​
This is amazing. An extremely simple function “z​  + c” when iterated over complex numbers 
seems to result in a strange insect like shape. Have we unlocked something about the way 
simple laws of nature lead to organic natural looking forms? 
 
When researchers saw their first glimpse of this Mandelbrot set, they were convinced they’d 
made an error. When they realised that there was no error, the magnitude of what they had 
discovered dawned on them. They had discovered an extremely rich shape generated by 
extremely simple mathematics. 
 
Let’s improve the picture we have. Let’s reframe it by choosing a rectangle closer to the shape, 
from (­2.25 ­ 1.5i) to (0.75 + 1.5i). Let’s also improve the detail by testing points 0.005 apart 
along the real and imaginary axes, a hundred fold increase in the number of points tested. The 
resulting image is this. 
 
Mandelbrot Set: bottom left (­2.25 ­ 1.5i), top right (0.75 + 1.5i) 
 
 
Behold! This is our first proper view of the Mandelbrot set. 
 
You can see the amazing level of detail. You can see self similarity in the patterns, but in a way 
that isn’t exact repetition like a synthetic boring object, but more like an object created by 
nature. You can in fact see what looks like smaller versions of the big shape itself, attached by 
what look like very fine threads. The object is haunting in its intricacy and natural beauty. And all 
this from a very simple mathematical function. 
 
Let’s zoom in and look at some sections of this shape. We can do this again by choosing a new 
rectangle and testing many points within it. 
 
Example 1: bottom left (­1.5 ­0.5i), top right (­0.5 +0.5i) 

 
 
This closer view of the first “head” shows detail that doesn’t appear to diminish. Also visible are 
yet more smaller shapes that look similar to the whole set, but placed on what look like very thin 
threads. 
 
Example 2: bottom left (0.0 ­0.9i), top right (0.6 ­0.3i) 
 
 
This view of one of the bulbs shows more of the filaments with more bulbous shapes attached to 
them. Again the detail doesn’t diminish. 
 
Example 3: bottom left (­0.22 ­ 0.70i), top right (­0.21 ­0.69i) 
 
 
This is close up just under the top bulb, and shows intricate swirling shapes, in contrast to just 
endless bulbs with smaller bulbs. The detail appears to be diminishing but this is because we 
set an artificial limit to the number of iterations to apply to a test point. If we increased this 
number, the detail would return. We make a trade of between the detail visible and the effort to 
do all those calculations. 
 
Colour 
If you recall the introduction to this book, it showed the Mandelbrot set with coloured gradients 
around it. Those colours are not arbitrary but actually mean something. They indicate not just 
that the points diverge, but how quickly they do this. A rough and ready way to do this is to keep 
a note of the number of iterations it took for the magnitude of the function output values to grow 
beyond our chosen threshold of 4.0. This way, a quick divergence with fewer iterations would be 
given a different colour than a slow divergence with many iterations. 
 
You could choose a larger threshold than 4 but once the magnitude of the complex number has 
increased beyond 4, we know the function diverges. Actually you can work this out by looking at 
the mainview of the Mandelbrot set. The circle described by complex numbers with magnitude 4 
is outside the main shape, meaning the points with that and larger magnitudes always diverge. 
 
Let’s replot the same views above, but colouring the points according to how quickly they 
escape, if at all.  
 
Coloured Mandelbrot Set: bottom left (­2.25 ­ 1.5i), top right (0.75 + 1.5i) 
 
 
This colour coding to show how quickly, or slowly, points diverge makes clearer the very fine 
filament structures that weren’t clear before. You can see now that all the bulbs of the 
Mandelbrot set are connected. That is, there is only one shape with fine detail around the 
edges, and there are no parts that break away from the main shape.  
 
Coloured Example 1: bottom left (­1.5 ­0.5i), top right (­0.5 +0.5i) 
 
 
This close up again highlights the intricate structures, both bulbous and filament like. The 
filaments look like electrical lightning.  
 
Coloured Example 2: bottom left (0.0 ­ 0.9i), top right (0.6 ­ 0.3i) 
 
 
 
Coloured Example 3: bottom left (­0.22 ­ 0.70i), top right (­0.21 ­0.69i) 
 
 
This much closer view really emphasises the intricate detail, much more so than the 
non­coloured view.  
 

The Recipe 
The recipe for making your own mandelbrot is summarised here. Mathematicians use the word 
algorithm​ for recipe. Let’s show it as a diagram then explain it in plain English. 
 
 
 
1. Pick a rectangle on the complex plane.  
If you select the rectangle with bottom left corner at (­2.25 ­1.5i) and top right corner at (0.75 + 
1.5i) you’ll get a good view of the Mandelbrot set. If you chose a rectangle that’s far away from 
the centre of the Mandelbrot, or is completely within the set, then you won’t see anything 
interesting. 
 
2. Each point in this rectangle is a complex number representing c, the parameter of our 
iterated function.  
You should pick a reasonable number of points, evenly spaced out. Too many and you’ll have 
lots of unnecessary calculations to do without adding much detail. Too few points and you’ll 
have gaps in your plot and insufficient detail. 
 
2​
3. For each of these points, c, iterate the function z​  +c many times.  
The complex number z starts at zero, or more properly (0 + 0i). Keep a note of the completed 
iterations. 
 
4. Stop iterating when either (i) you’ve reached the maximum number of iterations you’ve 
set yourself, or (ii) the magnitude of the function output grows more than 4. 
If the magnitude grows greater than 4, the point has diverged and you don’t need to keep 
calculating further iterations as they’ll diverge further, and may even grow so big as to cause an 
error in your calculator or computer. 
If you’ve reached the maximum iterations, the point c very likely doesn’t diverge.  
 
5. Colour the point c using the number of iterations reached to indicate either (i) the rate 
of divergence, or (ii) non­divergence for points within the set. 
Remember that we have an upper limit on the number of iterations. If it is reached then the 
iterations did not diverge and so the point is likely to be within the Mandelbrot set. If the 
iterations are prematurely stopped because the magnitude of z has broken the limit we set of 4, 
then the orbit does diverge, and the iteration count we did reach indicates how slow or fast the 
divergence happens. A small iteration count means a rapid divergence. 
You could chose other colouring schemes if you wanted to experiment. 
 
 
   
Part 2: DIY 
 
In this section we’ll be making the Mandelbrot set ourselves using computers to do the 
calculating and plotting. 
 
We’ll introduce the Python programming language, and use the IPython environment to 
experiment and eventually develop our instructions to calculate and plot the Mandelbrot Set. 

   
Working with Python 
In this section we’ll go through the steps to practically make our own Mandelbrot set.  
 
We’ll use a computer because, as you know from the before, there will be many thousands of 
calculations to do, and many points to plot. Computers are good at doing many calculations very 
quickly, and they make plotting charts and pictures easy too. 
 
We will tell a computer what to do using instructions that it can understand. Computers find 
normal human languages hard to understand precisely and without ambiguity. In fact humans 
have trouble with precision and ambiguity when communicating with each other using these 
human languages, so computers have very little hope of doing better! 
 

Python 
We’ll be using a computer language called ​ Python​ . Python is a good language to start with 
because it is relatively easy to learn, it is easy to read and understand. It is also very popular, 
and used across many different fields, from genetics research to global scale technology 
infrastructures. Python is increasingly being taught in schools, including for use with the 
Raspberry Pi, also popular in teaching. In fact you could do all exercises in this book using a 
Raspberry Pi. 
 
There is a lot that you can learn about Python, or any other computer language, but here we’ll 
remain focussed on making our own Mandelbrot set, and only learn just enough about Python to 
achieve this.  
 

Interactive Python, IPython 
Rather than go through the error­prone steps of setting up Python for your computer, then all 
the various extensions to help do mathematics and graph plotting, I’d recommend you use a 
prepackaged solution, called ​IPython​. IPython contains the Python programming language and 
several common numerical and graph plotting extensions, including the ones we’ll need. 
IPython also has the advantage of presenting interactive notebooks, which behave much like 
pen and paper notepads, ideal for trying out ideas and seeing the results, and then changing 
some of your ideas again. This keeps the unnecessary stuff like program files, interpreters and 
libraries away from us. We’re more interested in working with an electronic mathematical 
notebook that can plot graphs, and not with that other geeky stuff.  
 
In fact, I’d recommend you don’t even install anything on your computer if you can avoid it, and 
use online versions of IPython accessed purely through a web browser. This has many 
advantages. It means you don’t have to change or install anything on your computer. It also 
means you can use any computer at any time because your work is kept online. Trendy people 
call this “working in the cloud”.  In fact you can use anything that has a suitable web browser, be 
it a tablet, smartphone, or even a Raspberry Pi. This is just like using webmail, online shopping 
and social networking sites, which you can use from any device with a suitable browser, and 
without installing software. 
 
I’m using the online IPython from ​ http://wakari.io​
 who currently offer limited, but good enough for 
us, free trial accounts. If you must install your own IPython, if you don’t have easy internet 
connectivity for example, the ​ http://ipython.org​ site gives you some options for where you can 
get prepackaged IPython. I’m using the one from Anaconda package from Continuum.io when I 
don’t have access to the web and wakari.io. 
 

A Very Gentle Start with Python 
We’ll assume you now have access to IPython, following the instructions at wakari.io or at 
ipython.org. 
 
Notebooks 
Once we’ve fired it up and clicked “New Notebook”, we’re presented with an empty notebook as 
follows. 
 

 
 
The notebook is interactive, meaning it waits for you to ask it to do something, does it, and then 
presents back your answer, and waits again for your next instruction or question. It’s like a robot 
butler with a gift for arithmetic that never gets tired. 
 
If you have want to do something that is even mildly complicated, it makes sense to break it 
down into sections. This makes it easy to organise your thinking, and also find which part of the 
big project went wrong. For IPython, these sections are called cells. The above IPython 
notebook has an initial empty cell, and you may be able to see the typing caret blinking, waiting 
for you to type your instructions into it. 
 
Lets instruct the computer! Let’s ask it to multiply two numbers, say 2 times 3. Let’s type “​ 2 * 
3​” into the cell and click the run cell button that looks like a audio play button. The computer 
should quickly work out what you mean by this, and present the result back to you as follows. 
 

 
 
You can see the answer “​ 6​” is correctly presented. We’ve just issued our first instruction to a 
computer and successfully received a correct result. Our first computer program! 
 
Don’t be distracted by IPython labelling your question as “In [1]” and its answer as “Out [1]”. 
That’s just it’s way of reminding you what you asked (input) and and what it replied with (output). 
The numbers are the sequence you asked and it responded, useful for keeping track if you find 
yourself jumping around your notebook adjusting and reissuing your instructions. 
 
Basic Python 
We really meant it when we said Python was an easy computer language. In the next ready cell, 
labelled “In [ ]”, type the following code and click play. The word ​ code ​
is widely used to refer to 
instructions written in a computer language. If you find that moving the pointer to click the play 
button is too cumbersome, like I do, you can use the keyboard shortcut ctrl­enter, instead. 
 
print “Hello World!” 
 
You should get a response which simply prints the phrase “Hello World!” as follows. 
 
 
 
You can see that issuing the second instruction to print “Hello World!” didn’t remove the 
previous cell with its instruction and output answer. This is useful when slowly building up a 
solution of several parts.  
 
Now lets see what’s going on with the following code which introduces a key idea. Enter and run 
it in a new cell. If there is no new empty cell, click the button with the downward pointing arrow 
labelled “Insert Cell Below”, not to be confused with the one labelled “Move Cell Down”. 
 
x = 10 
print x 
print x+5 
 
y = x+7 
print y 
 
print z 
 
“x = 10​
The first line ​ ” looks like a mathematical statement which says x is 10. In Python this 
means that x is set to 10, that is, the value 10 is placed in a virtual box called x. That 10 stays 
there until further notice. We shouldn’t be surprised by the “​ print x​ ” because we used the 
print instruction before. It should print the value of x, that is “10”.  Why doesn’t it just print “x”? 
Because the tendency of Python is to evaluate whatever it can, and x can be evaluated to the 
value 10 so it prints that.  The next line “print x+5” evaluates x+5, which is 10+5 or 15, so we 
expect it to print “15”.  
 
The next bit “y = x+7” again shouldn’t be difficult you work out if we follow this idea that Python 
evaluates whatever it can. We’ve told it to assign a value to a new box labelled y, but what 
value? The expression is x+7, which is 10+7, or 17. So y holds the value 17, and the next line 
should print it.  
 
What happens with the line “print z” when we haven’t assigned a value to it like we have with x 
and y? We get an error message which is polite and tells us about the error of our ways, trying 
to be helpful as possible so we can fix it. I have to say, most computer languages have error 
messages which try to be helpful but don’t always succeed.  
 
The following shows the results of the above code, including the helpful polite error message, 
“name z is not defined”.  
 

 
 
These boxes with labels like x and y, which hold values like 10 and 17, are called ​ variables​ . 
Variables in computer languages are used to make a set of instructions generic, just like 
mathematicians use expressions like “x” and “y” to make general statements.  
 
Automating Work 
Computers are great for doing similar tasks many times ­ they don’t mind and they’re very quick 
compared to humans with calculators! 
 
Let’s see if we can get a computer to print the first ten squared numbers, starting with 0 
squared, 1 squared, then 2 squared and so on. We expect to see the a print out something like 
0, 1, 4, 9, 16, 25, and so on.  
 
We could just do the calculation ourselves, and have a set of instructions like “print 0”, “print 1”, 
“print 4”, and so on. This would work but we would have failed to get the computer to do the 
calculation for us. More than that, we would have missed the opportunity to have a generic set 
of instruction to print the squares of numbers up to any specified value. To do this we need to 
pick up a few more new ideas, so we’ll take it gently. 
 
Issue the following code into the next ready cell and run it.  
 
range(10) 
 
You should get a list of ten numbers, from 0 up to 9.  This is great because we got the computer 
to do the work to create the list, we didn’t have to do it ourselves. We are the master and the 
computer is our slave! 
 

 
 
You may have been surprised that the list was from 0 to 9, and not from 1 to 10. This is because 
many computer related things start with 0 and not 1. It’s tripped me up many times when I 
assumed a computer list started with 1 and not 0. Creating ordered lists are useful to keep count 
when performing calculations, or indeed applying iterative functions, many times.   
 
You may have noticed we missed out the “print” keyword, which we used when we printed the 
phrase “Hello World!”, but again didn’t when we evaluated 2*3. Using the “print” keyword can be 
optional when we’re working with Python in an interactive way because it knows we want to see 
the result of the instructions we issued. When Python is used in other contexts, where there is 
no human having a two way dialogue with Python, then instructions are carried out but the 
results are not necessarily printed out, and in that case the “print” keyword asks Python to print 
out the result. 
 
A very common way to get computers to do things repeatedly is by using code constructs called 
loops​. The word loop does give you the right impression of something going round and round 
potentially endlessly. Rather than define a loop, it’s easiest to see a simple one. Enter and run 
following code in a new cell. 
 
for n in range(10): 
print n 
pass 
print “done” 
 
There are three new things here so let’s go through them. The first line has the “range(10)” that 
we saw before. This creates a list of numbers from 0 to 9, as we saw before. The “for n in” is the 
bit that creates a loop, and in this case it does something for every number in the list, and keeps 
count by assigning the current value to the variable n. We saw variables earlier and this is just 
like assigning n=0 during the first pass of the loop, then n=1, then n=2, until n=9 which is the 
last item in the list.  
 
The next line “print n” shouldn’t surprise us by simply printing the value of n. We expect all the 
numbers in the list to be printed. But notice the indent before “print n”. This is important in 
Python as indents are used meaningfully to show which instructions are subservient to others, in 
this case the loop created by “for n in ...“. The “pass” instruction signals the end of the loop, and 
the next line is back at normal indentation and therefore not part of the loop. This means we 
only expect “done” to be printed once, and not ten times. The following shows the output as we 
explained it. 
 

 
 
It should be clear now that we can print the squares by printing “n*n”. In fact we can make the 
output more helpful by printing phrases like “The square of 3 is 9”. The following code shows 
this change to the print instruction repeated inside the loop. Note how the variables are not 
inside quotes and are therefore evaluated. 
 
for n in range(10): 
    print "The square of", n, "is", n*n 
    pass 
print "done" 
 
The result is shown as follows. 
 
 
 
This is already quite powerful! We can get the computer to potentially do a lot of work very 
quickly with just a very short set of instructions. We could easily make the number of loop 
iterations much larger by using range(100) or even range(100000) if we wanted. Try it! 
 
Can we relate this loop to the iterated functions we were looking at much earlier in this guide? 
The main thing we have to do is to keep the output value of a function and feed it back into the 
function without losing it as we go round the loop. The following code does this, and we’ll 
explain it. 
 
# function "triple it" 
# initial value of x is 2 
x = 2 
print "initial x = ", x 
for n in range(10): 
    # update x with the current value of x multiplied by 3 
    x = x * 3 
    print x 
    pass 
 
The first line begins with a hash symbol #. Python ignores any lines beginning with a hash. 
Rather than being useless, we can use such lines to place helpful comments into the code to 
make it clearer for other readers, or even ourselves if we came back to the code at a later time. 
Working through the code, we can see that x is set to the initial value 2 and is printed out. Then 
a loop is iterated 10 times, as we saw before. The code inside this loop multiplies the current 
value of x and assigns this new value to x again. Each updated x is printed for us to see. This 
effect of this loop is just like the iterated functions we saw earlier with the output being used as 
input for the next iteration.  
 

 
 
We can see that rather than printing out the triples 6, 9, 12, 15, 18 and so on, the results are 
what we expect if the output of the application of the function “triple it” is fed back into this 
function as input. So, 2*3 is 6. This 6 is fed back as input, so the next output is 6*3 or 18, and so 
on. 
 
Complex Numbers 
We’re getting closer to implementing the recipe for making our our Mandelbrot. We now need to 
be able to do calculations with complex numbers. 
 
Python is a really good choice because it can work with those 2­part numbers we discussed 
called complex numbers. We don’t need to tell Python about the special rules for expanding out 
2​
brackets, collecting similar terms, and the extra special part about i​  being replaced by ­1. 
Python, unlike many other computer languages, can work with complex numbers out of the box.  
 
Let’s try it. The following code shows how to create a complex number variable. We use the 
form “complex(a,b)” to tell Python we mean (a + ib) where a is the real part and b is the 
imaginary part of the complex number.  
 
# assign the complex number (2+3i) to c 
c = complex(2,3) 
print c 
 
# print c multiplied by (1 ­ 4i) 
print c * complex(1,­4) 
 
# print c squared 
print c*c 
 

 
 
The code shows how (2+3i) is assigned to c and printed. What might surprise us is that the 
printout says (2+3j) and not (2+3i). It is common to use j to denote the imaginary part of a 
complex number in the engineering community, whereas i is more prevalent in the mathematics 
community. They both mean the same thing. I suppose the language designers for Python 
chose j and it stuck, and there was never a good enough reason to change. Perhaps i was too 
easily misread as 1. In any case, the use of j instead of i is harmless. 
 
The code also shows that multiplying complex numbers is easy. In the old days we didn’t have 
this luxury and if you wanted your computer to calculate with complex numbers you’d have to 
explicitly teach it how to, using the rules we discussed earlier in this guide.  
 
Functions 
We spent a lot of time earlier working with mathematical functions. We thought of these as 
machines which take and input, do some work, and pop out the result. And those functions 
stood in their own right, and could be used again and again.  
 
Many computer languages, Python included, make it easy to create reusable computer 
instructions. Like mathematical functions, these reusable snippets of code stand on their own if 
you define them sufficiently well, and allow you to write shorter more elegant code. Why shorter 
code? Because invoking a function by its name many times is better than writing out all the 
function code many times. And what do we mean by sufficiently well defined? It means being 
clear about what kinds of input a function expects, and what kind of output it produces. Some 
functions will only take numbers as input, so you can’t supply it with a word made up of letters. 
 
Again, the best way to understand this simple idea of a function is to see a simple one and play 
with it. Enter the following code and run it. 
 
# function that takes 2 numbers as input 
# and outputs their average 
def avg(x,y): 
    print "first input is", x 
    print "second input is", y  
    a = (x + y) / 2.0 
    print "average is", a 
    return a 
 
Lets talk about what we’ve done here. The first two lines starting with # are ignored by Python 
but for us can be used as comments for future readers. The next bit “def avg(x,y)” tells Python 
we are about define a new reusable function. That’s the “def” keyword. The “avg” bit is the name 
we’ve given it. It could have been called “banana” or “pluto” but it makes sense to use names 
that remind us what the function actually does. The bits in brackets (x,y) tells Python that this 
function takes two inputs, to be called x and y inside the forthcoming definition of the function. 
Some computer languages make you say what kind of objects these are, but Python doesn’t do 
this, it just complains politely later when you try to abuse a variable, like trying to use a word as 
if it was a number, or other such insanity.  
 
Now that we’ve signalled to Python that we’re about to define a function, we need to actually tell 
it what the function is to do. This definition of the function is indented, as shown in the code 
above. Some languages use lots of brackets to make it clear which instructions belong to which 
parts of a program, but the Python designers felt that lots of brackets weren’t easy on the eye, 
and that indentation made understanding the structure of a program instantly visual and easier. 
Opinions are divided because people get caught out by such indentation, but I love this 
innovation. It’s one of the best ideas to come out of the geeky world of computer programming! 
 
The definition of the avg(x,y) function is easy to understand as it uses only things we’ve seen 
already. It prints out the first and second numbers which the function gets when it is invoked. 
Printing these out isn’t necessary to work out the average at all, but we’ve done it to make it 
really clear what is happening inside the function. The next bit calculates (x+y)/2,0 and assigns 
the value to the variable named a. We again print the average just to help us see what’s going 
on in the code. The last statement says “return a”. This is is the end of the function and tells 
Python what to throw out as the functions output, just like machines we considered earlier.  
 
When we ran this code, it didn’t seem to do anything. There were no numbers produced. That’s 
because we only defined the function, but haven’t used it yet. What has actually happened is 
that Python has noted this function and will keep it ready for when we want to use it. 
 
In the next cell enter “avg(2,4)” to invoke this function with the inputs 2 and 4. By the way, 
invoking a function is called ​
calling a function​ in the world of computer programming, and we’ll 
do that too as it’s very common. The output should be what we expect, with the function printing 
a statement about the two input values and the average it calculated. You’ll also see the answer 
on it’s own, because calling the function in an interactive Python sessions prints out the returned 
value. The following shows the function definition and the results of calling it with avg(2,4) and 
also bigger values (200, 301). Have a play and experiment with your own inputs. 
 

 
 
You may have noticed that the function code which calculates the average divides the sum of 
the two inputs by 2.0 and not just 2. Why is this? Well this is a peculiarity of Python which I don’t 
like. If we used just “2” the result would be rounded down to the nearest whole number. This 
would be fine for avg(2,4) because 6/2 is 3, a whole number. But for avg(200,301) the average 
is 501/2 which should be 250.5 but would be rounded down to 250. This is all just very silly I 
think, but worth thinking about if your own code isn’t behaving quite right. Dividing by “2.0” tells 
Python we don’t want it to round down to whole numbers. 
 
Let’s take a step back and congratulate ourselves. We’ve defined a reusable function, one of 
the most important elements of both mathematics and in computer programming. 
 
Arrays 
Arrays are just tables of values. Like tables, you refer to particular cells according to the row and 
column number. If you think of spreadsheets, you’ll know that cells are referred to in this way, 
B1 or C5 for example, and the values in those cells can be used in calculations, C3+D7 for 
example.  
 
 
 
We’ll use arrays to represent the complex plane on which the Mandelbrot set is plotted, so let’s 
get familiar with them. Enter and run the following code. 
 
a = zeros( [3,2] ) 
print a 
 
This creates an array of shape 3 by 2, with all the cells set to the value zero and assigns the 
whole thing to a variable named a. We then print a. We can see the representation of this array 
full of zeros in what looks like a table with 3 rows and 2 columns. 
 

 
 
Now let’s modify the contents of this array and change some of those zeros to other values. The 
following code shows how you can refer to specific cells to overwrite them with new values. It’s 
just like referring to spreadsheet cells or a street map grid references.  
 
a[0,0] = 1 
a[0,1] = 2 
a[1,0] = 9 
a[2,1] = 12 
print a 
 
The first line updates the cell at row zero and column zero with the value 1, overwriting 
whatever was there before. The other lines are similar updates, with a final printout with “print 
a”. The following shows us what the array looks like after these changes.  
 
 
 
Now that we know how to set the value of cells in an array, how do we look them up without 
printing out the entire array? We’ve been doing it already. We simply use the expressions like 
a[1,2] or a[2,1] to refer to the content of these cells which we can print or assign to other 
variables. The code shows us doing just this. 
 
print a[0,1] 
v = a[1,0] 
print v 
 
You can see from the output that the first print instruction produced the value 2.0 which is what’s 
inside the cell at [0,1]. Next the value inside a[1,0] is assigned to the variable v and this variable 
is printed. We get the expected 9.0 printed out. 
 

 
 
The column and row numbering starts from 0 and not 1. The top left is at [0,0] not [1,1]. This 
also means that the bottom right is at [2,1] not [3,2]. This catches me out sometimes because I 
keep forgetting that many things in the computer world begin with zero not 1.If we tried to refer 
to a[ 3,2] we’d get an error message telling us we were trying to locate a cell which didn’t exist. 
We’d get the same if we mixed up our columns and rows. Let’s try accessing a[0,2] which 
doesn’t exist just to see what error message is reported.  
 
 
 
Plotting arrays 
Just like large tables or lists of numbers, looking at large arrays isn’t that insightful. Visualising 
them helps us quickly get an idea of the general meaning. One way of plotting 2­dimensional 
arrays of numbers is think of them as flat 2­dimensional surfaces, coloured according to the 
value at each cell in the array. You can choose how you turn a value inside a cell into a colour. 
You might choose to simply turn the value into a colour according to a colour scale, or you might 
colour everything white except values above a certain threshold which would be black.  
 
Let’s try plotting the small 3 by 2 array we created above. Enter and run the following code. 
 
imshow(a, interpolation="nearest") 
 
The instruction to create a plot is imshow(), and the first parameter is the array we want to plot. 
In the old days, plotting arrays was much more involved. The kids these days don’t know how 
easy they have it. That last bit “interpolation” is there to tell Python not to try to blend the colours 
to make the plot look smoother, which it does by default. Let’s look at the output. 
 
 
 
How exciting! Our first plot shows the 3 by 2 sized array as colours. You can see that the array 
cells which have the same value also have the same colour. When we plot the Mandelbrot set, 
we’ll be using this very same imshow instruction to visualise an array of values. 
 
The IPython package has a rich set of tools for visualising data. You should explore them to get 
a feel for the wide range of plots, and even try some of them. Even the imshow() instruction has 
many options for plotting for us to explore, such as using different colour palettes.  
 
We’ve now covered enough basic Python to start building up the instructions to calculate and 
print a Mandelbrot set. 
 

Mandelbrot Set in Python 
We’ll build up the set of instructions to calculate and plot a Mandelbrot set, by breaking the task 
down into smaller parts. This approach is encouraged in all of computing. It helps clarify thinking 
about the problem to be solved, encourages the creation of well developed reusable code, and 
reduces errors through working on smaller problems rather than one large complex problem. 
 
2​
The Iterative Function z​ +c 
Let’s start at the core of the Mandelbrot calculation. We know from before that each point of the 
2​
Mandelbrot set is tested to see if it diverges or not, when the z​+c function is applied repeatedly.  
 
As a reminder, the complex number c represents the point being tested. Like all complex 
numbers it has two parts, a real part and an imaginary part. Together these can be thought of as 
coordinates or a grid reference on a 2­dimensional surface. The function starts with a complex 
number z set to zero, or more specifically (0 + 0i).  
 
When the function is repeatedly applied, with the output put back in as input, the resulting 
values may diverge rapidly, or they may follow an orbit which is doesn’t escape. As we saw 
earlier, we could choose colours for each point depending on whether the point diverges or not. 
This produced some intricate plots using only black and white. We then changed what we 
plotted, and coloured according to how quickly a point diverged. This produced the beautiful 
plots of the Mandelbrot set and it’s coloured surrounding regions.  
 
This means the Python function we want to write returns the number of iterations it takes to 
2​
diverge. The function still needs to calculate successive values of z​ +c, it just doesn’t have to 
2​
return them. A good way to see if a point will diverge is to see if the output values of the z​ +c 
function get larger than 4 in magnitude. If it does, we don’t have to keep iterating to see if the 
orbits might come back and the values not diverge. If you look at plots of the Mandelbrot set you 
can see that any point sufficiently far away from the centre will always diverge. The only ones 
that don’t are closer to the centre point at (0 + 0i). A distance of 4 is a safe choice to be sure 
that any point which ever end up beyond that distance from the centre will always diverge. Why 
not choose a threshold of, say, 100 instead of 4. There wouldn’t be anything mathematically 
wrong with that, but choosing a lower but still valid threshold of 4 means we reduce significantly 
the amount of unnecessary calculations to be done. 
 

 
 
Let’s start writing some code. The definition of the core calculating function must take the 
chosen point represented by complex c, and return the number of iterations taken to breach a 
threshold on its way to divergence. So the start and end of this function look like the following. 
 
def mandel(c): 
.. 
.. 
return iterations 
 
The mandel function takes the parameter c, the complex number representing the point to be 
tested for divergence. The function returns the number of iterations it took to breach the 
threshold. What if the point doesn’t diverge and has a nice tight orbit? Will we keep running the 
iterations forever because the threshold will never be breached? Well if we did that we’d never 
progress beyond that single point being tested, and eventually our code would fail as it ran out 
of space to keep track of the iterations. We need a way of stopping the calculations when we 
are satisfied the point won’t diverge. A rough and ready, but good enough way, is to define the 
maximum number of iterations the function is to be applied. It must be large enough to convince 
us that the point won’t diverge, remembering that earlier we did see some cases of a belated 
divergence after an initial period of what looked like a safe orbit.  
 
We could set this maximum iteration number once and for all, or we could make it a parameter 
we pass into the mandel(c) function, so that we can easily change it if needed. The function 
would then look something like like mandel(c, maxiter). Why would we need to change it? Well, 
as you explore the Mandelbrot set’s fine detail, you need more iterations to decide if a point will 
diverge or not, and to get a more accurate view of the rate of divergence. Too few iterations and 
the finer details, when plotted, are not sufficiently defined. Two points close to each other may 
appear like they don’t diverge, but with more iterations it may become apparent that one does 
and the other doesn’t. This distinction defines the detail that is uncovered and plotted. 
 

 
 
Let’s write some more of this mandel(c, maxiter) function and explain it. Look at the following. 
 
def mandel(c, maxiter): 
    z = complex(0,0) 
   
    for iteration in xrange(maxiter): 
        … 
        … 
        … 
        pass 
 
    return iteration 
 
We’ve now updated the mandel() function to take the complex c point to be tested, and also the 
maximum iterations as maxiter. We set the starting value of z to be zero, or more precisely 
(0+0i). Then we write the “for ..” code loop which iterates a maximum of maxiter times, keeping 
count in the variable named iteration. The end of the function is still returning the iteration count, 
whether that reaches the maximum maxit, or is stopped sooner by a magnitude threshold test.  
 
2​
What’s left is to fill in the code describing the iterated function z​+c and the check to see if the 
threshold has been breached. These are easy so let’s write them out and explain them. 
 
 
def mandel(c, maxiter): 
    z = complex(0,0) 
   
    for iteration in xrange(maxiter): 
        z = (z*z) + c 
   
        if abs(z) > 4: 
                break 
                pass 
   
        pass 
 
    return iteration 
 
Here we’ve added the “z = (z * z) + c” instructions which calculates the next value of z based on 
the current value and the chosen c. We then check to see if the magnitude, or absolute value 
denoted abs() in Python, of c is greater than 4, and if it is, the instruction “break” simply breaks 
out of the “for” loop. Once this happens there are no more instruction after the loop, and so the 
mandel(c,maxiter) function returns the value of iteration to whoever called it in the first place. If 
the point doesn’t diverge, then abs(z) is never more than 4, so the for loop simply keeps running 
until the count reaches the maximum iterations, and it is this maximum that is then finally 
returned by the mandel(c, maxiter) function. 
 
The following shows the mandel() function in a cell, and an example call of this function mandel( 
2​
complex(0.5, 0.5), 40) returning the value 5. That is, the z​ +c iterative  function was tested at the 
point (0.5 + 0.5i) with a maximum limit of 40 iterations. The returned value of 5 is the number of 
2​
iterations it took for the magnitude of the output of z​+c to breach the threshold telling us the 
point diverges. Enter the code and try it for some other values of c and maxiter.  
 

 
 
If we were being pedantic we’d note that the return value from mandel() is in fact the one less 
than the actual iterations because the count starts at 0 not 1. We won’t bother changing the 
return value to “iteration + 1” because it doesn’t make a difference to which points are identified 
as diverging or not, and the slight change in colour that is plotted is also not worth fretting about.  
 
Along this vein, you may also notice that the test to see if the magnitude of the values output 
2​
from z​ +c at each iteration is calculated according to the Pythagorean definition, that is, the 
square root of the sum of the two parts squared. Again, you could shave off some calculation 
effort by not taking the square root and just comparing the sum of the squares with 16. We won’t 
bother because the code is simpler with abs(z) and these days computers are so fast that we 
won’t be waiting long for the calculations to complete. In the 90s, Mandelbrot sets took hours to 
plot on home computers, not seconds! Avoiding unnecessary calculations was a serious task. 
 
The Atlas 
We’ve defined the Python function which does the important calculations to test whether a point 
on a two dimensional plane is within the Mandelbrot set or not, and if not, what colour it should 
be assigned to indicate how fast it diverges.  
 
Points on this two dimensional plane, as we discussed earlier, can be represented by complex 
numbers because  they have two independent parts, the real and imaginary parts, to act like 
coordinates or grid references. Mathematicians call this the ​ complex plane​ , and again I dislike 
the term “complex” because it’s not complicated and only puts people off. We called it the atlas 
of regions earlier when we were trying to grasp these ideas as gently as possible. 
 
We now need to define in Python which part of this complex plane we are interested in because 
we can’t plot the entire plane as that goes on forever in each direction. Rectangular or square 
sections are easiest because the shape matches our computer screens, and the complex 
numbers are already in a rectangular form with one part describing the horizontal distance and 
the other the vertical distance from the origin. 
 
We also need to divide up this section into regularly spaced points. Again there are an infinite 
number of points in any rectangle or square and we need to constrain ourselves to a finite 
amount of work. Regular spacing means we can easily represent these points as pixels in an 
image.  
 
Let’s play with a Python function that conveniently creates a series of numbers from a starting 
value, up to an upper value, spaced regularly apart. In a new cell enter and run the code 
“linspace( 0.0, 5.0 , 5)” to see what happens.  
 

 
 
The linspace function has taken the starting point 0.0 and an endpoint 5.0 and divided it such 
that there are 5 evenly spaced points, including the endpoints. Five points means 4 sections, 
just as 3 points means 2 sections, that start, middle and end. This readymade linspace() Python 
function is a really good start to defining the section of the complex plane we are interested in 
and dividing it up into evenly spaced points to test and plot.  
 
Let’s plough on. We can use the convenient linspace function to define a rectangular section of 
the complex plane by using it once for the horizontal side of the section and again for the 
vertical side. The following diagram illustrates this to make it clearer to see. 
 

www.allitebooks.com
 
 
Let’s imagine we want a rectangle with bottom left at (­2,­2) and the top right at (4,2). This has a 
horizontal length of 6, and a vertical height of 4. Let’s divide the horizontal length into 12 
sections, and the vertical into 8. The following Python code shows how you create a list of each 
of these dividing points along the horizontal and vertical sides using the linspace() function. 
 

 
 
The horizontal points are all spaced 0.5 units apart, and the vertical points are 1 whole unit 
apart.  
 
But these lists only divide the sides. How can they be used to define all the points we want to 
test inside a rectangular section? We do this by taking combinations of points from these lists. 
All the combinations will result in a list of all the points in the rectangle of interest. We can 
combine these lists in a systematic way using Python loops. Let’s do it using the same rectangle 
and divisions we’ve just defined. In the next IPython cell enter and run the following code. 
 
x_list = linspace( ­2.0, 4.0, 13) 
y_list = linspace( ­2.0, 2.0, 5) 
 
for x in x_list: 
    for y in y_list: 
        print x,y 
        pass 
    pass 
 
You can see that we first create lists of the x and y coordinates using the now familiar linspace() 
function, and assign these lists to variables named x_list and y_list. If you printed these 
variables you’d get the same output as we saw before. Next we can see the familiar Python 
loops. The outer loop works through the x_list and the inner loop works through the y_list. The 
inside of the loops only prints the current x and y values. In English, what this is doing is “for 
each value in the x_list go through the y_list, and for each of combination print out the values”. 
This does mean the y­list is walked through many times, once for every item in the x_list. You 
can see that if we were doing a lot of work inside the central loop, such as calculating the 
mandel() function, this results in a lot of work. It’s just as well a computer is doing it and not us 
with a pencil and paper!  
 
The output of this code is quite long as there are many combinations of x and y. The following 
shows what my notebook looks like. 
 

 
 
You can see the list of all points in the rectangle of interest starting with (­2, ­2), (­2, ­1), (­2,0) .. 
and so on.  
 
We’ve made good progress, and we’re almost there. We have the mandel() function to test 
given points, and we now have a means to create such points. Next we need to find a way of 
associating these points with the pixels in an array of colour values that could be plotted using 
the imshow() function we used earlier. 
  
 
Complex Plane to Image Translation 
Why do we need a translation? Why can’t we just plot the rectangular region of the complex 
plane? Surely this is a perfectly reasonable request of a computer? There are two reasons.  
 
The first is that the complex plane region is just a list of points, or complex numbers, and these 
don’t have a colour associated with them to plot. We need to give the imshow() plotting function 
something which contains colour information.  
 
Secondly, the imshow() function expects to plot a 2­dimensional array, not a long list of complex 
numbers like the ones we created earlier. It expects an array where the contents of an array cell 
represent the colour to be plotted, and the position of the cell in terms of row and column is the 
position in the image plotted. 
 
It’s worth saying that we could work with long lists of complex numbers and associated colour 
values, including plotting them, if we used different extensions to Python. However we won’t 
here as we want to keep things simple and use only the most common extensions. 
 
So we need to to create an array of the right size to cover the desired region of the complex 
plane that we previously defined using the linspace() functions. The following diagram shows 
how these two are related. 
 

 
 
You can see from the diagram that the bottom left point of the complex plane region is 
represented by the cell at position [0,0] of the array. That was easy to agree with. What about 
the top right point of the complex plane region? If it is at, say for example (0.77 + 0.44i), what 
row and column of the array would this be? We can’t even use the real and imaginary parts of 
the complex number to represent the row and column because the values are fractional, and 
even worse, they are less than 1! We can’t have a row that is number 0.77, we need whole 
numbers!  
 
Given that the rows and columns of the plotted array need to increment in whole units, we can 
simply place each of the evenly spaced points between the bottom left and top right into the 
array. So if the points were 0.5 units apart on the complex plane, they would be 1 unit apart in 
the array. So this means the array has the same number of columns as the number of divisions 
along the horizontal side of the region. Similarly it has the same number of columns as the 
number of divisions of the vertical side of the rectangular region. The previous diagram also 
illustrates this. 
 
It’s easy to get confused between rows and columns, and trying to remember which one 
represents the real horizontal axis and which one the vertical imaginary axis of the complex 
plane. We won’t worry too much because the worst that can happen is the Mandelbrot set is 
plotted on its side which is really easy to rectify. 
 
Let’s now define the complex plane region. Enter and run the following code. It makes sense to 
place this at the top of your IPython notebook because it sets out up front which region you are 
interested in. Use the button marked as “Insert cell above” to create a new cell at the top. 
 
# set the location and size of the complex plane rectangle 
xvalues = linspace(­2.25, 0.75, 1000) 
yvalues = linspace(­1.5, 1.5, 1000) 
 
# size of these lists of x and y values 
xlen = len(xvalues) 
ylen = len(yvalues) 
 
The first instruction creates a list of 1000 points evenly placed between ­2.25 and 0.75, 
inclusive. These will be the horizontal divisions of the rectangle, and we’ll call the list xvalues. 
Similarly yvalues is the list of 1000 evenly spaced points between ­1.5 and 1.5. This rectangle 
with bottom left (­2.25 ­ 1.5i) and top right (0.75 + 1.5i) is chosen as it nicely frames the 
Mandelbrot set. You can later choose your own rectangle to explore the set. Choosing a smaller 
width and height means you are zooming into the set, as if using a microscope. 
 
The last two lines simply take the length of the lists and assign them to variables. The len() of a 
list [1,2,3] is 3 because it has 3 elements. The variable xlen is becomes 1000 because xvalues 
contains 1000 points and so len(xvalues) is 1000. Why didn’t we just say xlen = 1000? Because 
it is good practice in computer programming to set changeable parameters once and 
automatically derive subsequent values. If we didn’t it becomes cumbersome to change all 
references to this number of subdivisions, and if we forget, we cause incorrect calculations to 
happen. This way, if we want to change the number of subdivisions from 1000 to say 500 we 
only change the code once. 
 
The following code creates the array of colour values. We can see it is created to have a size of 
xlen by ylen, so each cell represents one of the evenly spaced points on the complex plane. 
Enter and run it in a new cell at the bottom of the notebook. 
 
atlas = empty((xlen,ylen)) 
 
We’re almost there! All that remains is to fill this array with colour values and plot it using 
imshow(). What values do we put int? Well we know the colour value has to be related to the 
number of iterations it takes a point to diverge so why not simply use the returned value from 
the mandel() function? Let’s do it. 
 
Add the following code to the same cell as you created the atlas array. 
 
for ix in xrange(xlen): 
    for iy in xrange(ylen): 
   
        cx = xvalues[ix] 
        cy = yvalues[iy] 
        c = complex(cx, cy) 
   
        atlas[ix,iy] = mandel(c,40) 
   
        pass 
    pass 
 
You’ll recognise that this code is simply two loops, one inside the other. The loops count 
through the rows and columns of the atlas array using variables ix and iy. These counts are 
perfect for referring to the contents of the array which are also counted from 0 to xlen­1, and not 
1 to xlen. You may have noticed we use xrange instead of range. The range would work but for 
very large lists xrange is more efficient because it doesn’t actually create a list, but gives you the 
contents as you ask for them. This is an under­the­hood detail and you don’t need to worry 
about it if you don’t want to. 
 
These two loops allow us to refer to every cell of the array using atlas[ix,iy]. The code inside the 
loops uses the counts ix and iy to look up the actual complex number to be tested by the 
mandel() function. The real and imaginary parts were in the xvalues and yvalues lists we 
created earlier, and can be dug out using xvalues[ix] and yvalues[iy].  
 
Let’s be really clear about what ix and iy do for us. Because the loops take ix and iy through all 
the possible values in the atlas array, and the array was deliberately created to match all the 
points in the complex plane we wanted to test, the array cell atlas[ix,iy] corresponds to the 
complex number in the region of interest with real part xvalues[ix] and imaginary part yvalues[iy]. 
You can see the code constructing the complex number c using these values.  
 
The last part inside the loops is updating the contents of the array with the return value from the 
mandel() function.  
 
That’s it! We’re done! Now let’s see the results! In a new cell, enter the following code. 
 
figsize(18,18) 
imshow(atlas.T, interpolation="nearest") 
 
The first line sets the size of the plot to 18 by 18 because the default is too small. The imshow 
instruction plots the array. As before we are telling Python not to smooth the colours or blend 
them, just show them as they are. We also refer to atlas with a “.T” appended to it. That’s 
because the array is plotted on its side compared to what we want to see.  
 
Run the code and you’ll see the Mandelbrot set. 
 
 
 
You can zoom into parts of the Mandelbrot set by changing the bottom left and top right points 
of the complex plane region. We simply change the code which sets the xvalues and yvalues. 
For example using the rectangle from earlier in this guide with (­0.22 ­ 0.70i) bottom left and 
(­0.21 ­0.69i) as top right means setting the following xvalues and yvalues as follows: 
 
# set the location and size of the atlas rectangle 
xvalues = linspace(­0.22, ­0.21, 1000) 
yvalues = linspace(­0.70, ­0.69, 1000) 
 
 
The resulting image was quite undefined because we set too low a value for maximum 
iterations. Changing it from 40 to 120 is done as follows: 
 
atlas[ix,iy] = mandel(c,120) 
 
The result is a more detailed image, as follows. It’s really quite beautiful! 
 

 
 
 
Mandelbrot Set in Python 
The following presents the complete Python code we’ve built up to plot our own Mandelbrot 
fractals for you to look over. I’ve added comments to help remind you what each code section 
does. 
 
# loads the numerical and plotting extensions to Python 
# needed if you're using a locally installed IPython, not for some 
online IPython providers 
%pylab inline 
 
# set the location and size of the atlas rectangle 
xvalues = linspace(­2.25, 0.75, 1000) 
yvalues = linspace(­1.5, 1.5, 1000) 
 
# size of these lists of x and y values 
xlen = len(xvalues) 
ylen = len(yvalues) 
 
# mandelbrot function, takes the fixed parameter c and the maximum 
number of iterations maxiter, as inputs 
def mandel(c, maxiter): 
    ​ # starting value of complex z is 0+0i before iterations update it 
   ​  z = complex(0,0) 
   
    ​ # start iterating and stop when it's done maxiter times 
    ​ for iteration in xrange(maxiter): 
   
        ​ # the main function which generates the output value of z 
from the input values using the formula (z^2) + c 
        ​ z = (z*z) + c 
   
        ​ # check if the (pythagorean) magnitude of the output complex 
number z is bigger than 4, and if so stop iterating as we've diverged 
already 
        ​ if abs(z) > 4: 
            break 
            pass 
        pass 
   
   ​  # return the number of iterations we actually did, not the final 
value of z, as this tells us how quickly the values diverged past the 
magnitude threshold of 4 
    ​ return iteration 
 
# create an array of the right size to represent the atlas, we use 
the number of items in xvalues and yvalues 
atlas = empty((xlen,ylen)) 
 
# go through each point in this atlas array and test to see how many 
iterations are needed to diverge (or reach the maximum iterations 
when not diverging) 
for ix in xrange(xlen): 
    for iy in xrange(ylen): 
   
       ​
 # at this point in the array, work out what the actual real 
and imaginary parts of x are by looking it up in the xvalue and 
yvalue lists 
        ​
cx = xvalues[ix] 
        cy = yvalues[iy] 
        c = complex(cx, cy) 
   
        ​
# now we know what c is for this place in the atlas, apply 
the mandel() function to return the number of iterations it took to 
diverge 
        # we use 40 maximum iterations to stop and accept the 
function didn't diverge 
        ​
atlas[ix,iy] = mandel(c,40) 
   
        pass 
    pass 
 
 
# set the figure size 
figsize(18,18) 
 
# plot the array atlas as an image, with its values represented as 
colours, peculiarity of python that we have to transpose the array 
imshow(atlas.T, interpolation="nearest") 
 

Exploring the Mandelbrot Set 
You should explore the Mandelbrot set, and see the beautiful patterns, the infinite intricate detail 
for yourself. You’ll see parts of the set that no­one else has seen precisely because the set is 
infinitely detailed.  
 
You could use the Python code we’ve developed, but it’s a little clunky working out the 
coordinates of the rectangles you want to zoom into. It would be better if you could just point 
and click at the part you were interested in zooming into. 
 
In fact there are many computer applications available for you to explore the Mandelbrot set. I’d 
recommend XaoS from ​ http://xaos.sourceforge.net​
, which is really easy to use, and so fast that 
it animates the effect of you zooming, or falling, deeper and deeper into the detail of the 
Mandelbrot set.  
 
You’ll have seen earlier than I’m a fan of applications which don’t need installing but are purely 
usable through a web browser. There’s a developing version of XaoS usable through a modern 
web browser at ​ http://jblang.github.io/XaoSjs​. 
 
 
 
 
 

 
   
Part 3: Even More Fun 
 
In this part we’ll take the ideas we’ve already developed and take them further, just for fun! 
 
We’ll introduce the Julia sets, relatives of the Mandelbrot set. We’ll be uncovering some of the 
intimate connections between the two. 
 
We’ll also see if we can construct three dimensional versions of the flat fractals we’ve developed 
already. In doing so we’ll be trying to invent some new mathematics. How exciting! 

   
Julia Sets 
Julia sets are closely related to the Mandelbrot Set. Before we dive into talking about them, let’s 
have a look at a few. All of these are produced by the code we’ve developed here. 
 

 
 
 
 
 
 
 
 
 
 
You can see that they are different to the Mandelbrot set, and yet there is something about them 
that is similar. The patterns are sometimes very different, and sometimes very similar to those of 
the Mandelbrot set. You can also see that some Julia sets are a single object like the 
Mandelbrot, but some are many pieces, with some even becoming so fragmented they are 
almost like dust.  
 
It might not be obvious that whilst there is only one Mandelbrot, there are many, infinitely many, 
Julia sets.  
 
Recipe 
The recipe for creating Julia sets is the same as that for the Mandelbrot set except for one key 
difference.  
 
Let’s remind ourselves of the recipe for the Mandelbrot set. We choose a rectangle on the 
complex plane and choose many evenly spaced points to test to see if they are part of the 
2​
Mandelbrot set, or not. We do this by seeing if repeated iteration of a function z​ +c, where c is 
the point being tested, results in the orbit escaping and diverging, or not. And if it does, we 
colour the point according to how fast the point diverges.  
 
This recipe is essentially the same for making Julia sets. The difference is that the roles of the z 
and c are reversed. Instead of c representing the point on the complex plane being tested, it is 
kept constant for all the points being tested. Similarly instead of z starting from zero it starts as 
the complex number representing point being tested.  
 
That’s it! That’s the only difference. The following diagram reinforces this simple difference. 
 

 
 
The following shows the calculating function julia(z, c, maxiter), based on the mandel(c, maxiter) 
function. 
 
def julia(z, c, maxiter): 
    for iteration in xrange(maxiter): 
        z = (z*z) + c 
        if abs(z) > 4: 
            break 
            pass 
        pass 
    return iteration 
 
You can see that z doesn’t start at (0+0i) anymore but is a parameter passed to the function. 
The parameter c is also passed but is a fixed complex number and not a number representing 
the point being tested, because z does that now. 
 
The Python program to plot Julia sets is presented here with the differences to the Mandelbrot 
program highlighted in bold or crossed out. 
 
# loads the numerical and plotting extensions to Python 
# needed if you're using a locally installed IPython, not for some 
online IPython providers 
%pylab inline 
 
# set the location and size of the atlas rectangle 
xvalues = linspace(​ ­2, 2​ , 1000) 
yvalues = linspace(​ ­2, 2​ , 1000) 
 
# size of these lists of x and y values 
xlen = len(xvalues) 
ylen = len(yvalues) 
 
# value of c (unique for each Julia set) 
c = complex(­0.35, 0.65) 
 
# julia function, takes the fixed parameters z and c and the maximum 
number of iterations maxiter, as inputs 
def julia(z, c, maxiter): 
    ​# starting value of complex z is 0+0i before iterations update it 
   ​ z = complex(0,0) 
   
    ​# start iterating and stop when it's done maxiter times 
    ​for iteration in xrange(maxiter): 
   
        ​ # the main function which generates the output value of z 
from the input values using the formula (z^2) + c 
        ​ z = (z*z) + c 
   
        ​ # check if the (pythagorean) magnitude of the output complex 
number z is bigger than 4, and if so stop iterating as we've diverged 
already 
        ​ if abs(z) > 4: 
            break 
            pass 
        pass 
   
   ​
 # return the number of iterations we actually did, not the final 
value of z, as this tells us how quickly the values diverged past the 
magnitude threshold of 4 
    ​
return iteration 
 
# create an array of the right size to represent the atlas, we use 
the number of items in xvalues and yvalues 
atlas = empty((xlen,ylen)) 
 
# go through each point in this atlas array and test to see how many 
iterations are needed to diverge (or reach the maximum iterations 
when not diverging) 
for ix in xrange(xlen): 
    for iy in xrange(ylen): 
   
       ​
 # at this point in the array, work out what the actual real 
and imaginary parts of x are by looking it up in the xvalue and 
yvalue lists 
        ​
zx​
 = xvalues[ix] 
        ​
zy​
 = yvalues[iy] 
        ​
z​
 = complex(​
zx, zy​

   
        ​
# now we know what c is for this place in the atlas, apply 
the mandel() function to return the number of iterations it took to 
diverge 
        # we use 80 maximum iterations to stop and accept the 
function didn't diverge 
        ​
atlas[ix,iy] = ​
julia​
(z,c,80) 
   
        pass 
    pass 
 
 
# set the figure size 
figsize(18,18) 
 
# plot the array atlas as an image, with its values represented as 
colours, peculiarity of python that we have to transpose the array 
imshow(atlas.T, interpolation="nearest") 
 
 
Try plotting different Julia sets by changing the c parameter. Remember it is the single 
parameter c which uniquely defines the Julia set. Is there a connection between the Julia sets 
defined by this c parameter and the Mandelbrot set?  
 
The Connection between Julia and Mandelbrot Sets 
Experimenting with plotting Julia sets for different values for c reveals that some of them are a 
single set and others are fragmented into a few or many pieces. If you remember that the 
Mandelbrot set lives on a complex plane you might be tempted to choose your c based on 
where the point lies inside or near the Mandelbrot set. If you did, you’d see that the Julia sets 
that come from c inside the Mandelbrot set are single unfragmented sets. Similarly, those Julia 
sets that come from c outside the Mandelbrot set are fragmented. And the further you move c 
away from the Mandelbrot set the more fragmented and like dust the Julia sets get. 
 
In this way, the Mandelbrot set is a kind of guide to Julia sets. The following diagram illustrates 
this connection between the Mandelbrot set and Julia sets.  
 

 
Mandelbrot and Julia Mountains 
 
Let’s try to turn the 2­dimensional flat images of the Mandelbrot and Julia sets into 3 
dimensions. One way to do this is to use the colour information in each image array to represent 
altitude, the height of a landscape above sea level as it were. We should then see mountainous 
landscapes shaped by the values of arrays filled by the Mandelbrot or Julia calculations. 
 

Surface Plot 
Let’s try it on a very simple array first. The following code prepares a 3 by 2 array. 
 
a = zeros( [3,2] ) 
a[0,0] = 1 
a[0,1] = 2 
a[1,0] = 4 
a[2,1] = 3 
print a 
 
Plotting a simple flat image based on these values, as earlier, using imshow(a, 
interpolation="nearest") results in the following plot as expected. 
 

 
 
Now lets plot this same array in 3 dimensions, with the third dimension given by the value of 
each cell. To do this we need to use a new extension to Python called mayavi. Sadly the purely 
web based IPython services provided remotely can’t plot 3­dimensional plots as they need your 
computer’s graphics hardware to do the hard work. You’ll need to use a locally installed IPython.  
 
Telling IPython that we want to use mayavi uses the import instruction, just as before. The 
special paylab instruction is to ensure the common set of numerical extensions are 
automatically loaded in the local IPython.  
 
%pylab inline 
import mayavi.mlab 
 
The instructions to plot a surface are simple. 
 
mayavi.mlab.surf(a, warp_scale="auto") 
mayavi.mlab.show() 
 
The first instruction prepares the surface plot and allows IPython to automatically scale the 
heights. The second instruction is needed to actually show the plot. This time the result will 
appear in a separate window outside your browser. You can do quite a lot to this 3­d plot, 
including rotating it around and changing the lighting which illuminates it. The following shows 
the above small array plotted in this way, and again rotated using the mouse. Try it! 
 

   
 
For easy reference, the entire code for creating a simple 3 by 2 array and plotting a 
3­dimensional plot of it as as follows: 
 
%pylab inline 
import mayavi.mlab 
 
a = zeros( [3,2] ) 
a[0,0] = 1 
a[0,1] = 2 
a[1,0] = 4 
a[2,1] = 3 
 
mayavi.mlab.surf(a, warp_scale="auto") 
mayavi.mlab.show() 
 
 

Mandelbrot Mountains 
We now apply this same idea to the larger arrays created by the Mandelbrot code we wrote 
earlier. We simply add the new instructions to create the 3­dimensional plots, remembering to 
import the mayavi extension too. It’s worth keeping the previous imshow() instruction to see the 
flat view too. The instructions are as follows. The warp_scale was adjusted to 1.0 to give a 
reasonable height, the automatic setting created hills that were a little too steep. 
 
mayavi.mlab.surf(atlas.T, warp_scale=1.0) 
mayavi.mlab.show() 
 
The output is quite nice, and the following shows the plot rotated around by dragging with a 
mouse. 
 
 
 
 
 
 
 
These 3­dimensional height fields as some people call them, give an interesting perspective of 
the Mandelbrot set.  
 
Let’s try that again but with the original rectangle zooming into details of the Mandelbrot set, and 
also change the colour palette by using the interactive menus. 
 
 
 
 
 
 
 
 
 
Some of these landscapes are quite haunting. Let’s try the same idea with Julia sets. 
 

Julia Mountains 
The following shows various Julia fractals rendered as height fields, using a range of zooms and 
colour palettes. 
 
 
 
 
 
 
 
 
 

 
 

Gentler Landscapes 
Some of the landscapes we created were a little spiky and noisy. Let’s see if we calm them 
down, smooth off the sharp edges, and reduce the cragginess a little, all in the hope of creating 
a perhaps more gentle, more appealing, landscape.  
 
One way to do this is to calculate a new image array, based on the original one, but with each 
new value somehow smoothed based on it’s neighbours values. A kind of local average, as it 
were. Let’s consider this last point a little more. If we calculated the average value for the entire 
array, by adding up all the values and dividing by the number of array elements, we would have 
just one single value. This would be the same everywhere and make for a flat boring landscape. 
Instead we want to calculate the average over a smaller group of neighbouring array elements, 
perhaps a 3 by 3 square or a bigger circle. Engineers and scientists who work with images or 
signals do this kind of thing fairly often to try to reduce noise. 
 
Python provides a collection of such filters that can be applied to an array of values, often useful 
when they are in fact images. A common smoothing filter is a slightly more sophisticated version 
of the local average we just described, called a ​ Gaussian​ blur filter. If you work with image or 
photo editing applications like Photoshop or GIMP then you’ll be familiar with applying a 
Gaussian blur to smooth an image. We won’t go into the details of why Gaussian blur filters are 
so useful and common but you can think of them as local averages, just as we described above, 
but with greater weight given to those array elements closer to the one you’re calculating.  
 
Enough talk, let’s get on with it. We’ll need to import the Python extension at the top of our code 
as follows: 
 
import scipy.ndimage 
 
The following shows how the Gaussian blur filter can be used to create a smoothed image array 
from the original, which we call atlas in our previous code. The value 2 is the strength of the 
smoothing 
 
smoothed_atlas = scipy.ndimage.gaussian_filter(atlas.T, 2) 
 
We can plot this as a flat image just as before using the imshow function. 
 
# set the figure size 
figsize(18,18) 
 
# create a smoothed image of the original by applying a 
Gaussian blur filter 
smoothed_atlas = scipy.ndimage.gaussian_filter(atlas.T, 2) 
 
# plot the array atlas as an image, with its values represented 
as colours, peculiarity of python that we have to transpose the 
array 
imshow(smoothed_atlas, interpolation="nearest") 
 
Similarly we can plot the 3­dimensional landscape just as before using the mayavi extensions. 
 
mayavi.mlab.surf(smoothed_atlas, warp_scale=0.9) 
mayavi.mlab.show() 
 
The following shows images for before and after the Gaussian smoothing filter is applied for the 
Julia set generated by c=(­0.768662 + 0.130477i), calculated in the rectangle with bottom left 
(­1­1i) and top right (1+1i). 
 
Before Gaussian blur filter: 
 
2­dimensional plot: 
 
 
3­dimensional landscape plot: 
 
 
 
After Gaussian blur filter: 
 
2­dimensional plot: 
 
 
3­dimensional landscape plot: 
 
 
The same but zoomed in closer: 

 
 
 
Try New Things Yourself 
I’d encourage you to explore other filters to see if they make interesting images. Perhaps you 
2​
might explore different functions aside from z​ +c which was the basis for both the Mandelbrot 
and Julia fractals.  
 
And remember, you can’t do any harm by experimenting and playing. Trying new things and 
testing out crazy ideas is how new mathematical discoveries are made. What’s the worst that 
can happen? 
 
As a teaser, here’s an image produced by one of the filters provided by the same extension that 
we got the Gaussian filter from. It’s beautiful! 
 

 
Epilogue 
What a journey! 
 
We started by opening our eyes to the natural world around us, noticing what kinds of things 
held our interest, things that we found beautiful. We realised that fractals tread a fine line 
between boring predictable order and the noisy anarchy of disorder.  
 
We then started playing with function, using nothing more than school level mathematics. We 
tried iterating these functions, not a difficult idea but one that surprised us with the wide range of 
behaviours we saw from apparently simple functions. We saw orbits blowing up (divergence) 
and settling down (convergence). We were surprised to discover periodic orbits, surprised 
because there was all this richness of behavior from very simple functions that we never saw at 
traditional school maths lessons. Then discovered something that mathematicians and 
scientists only really appreciated in the last 100 years or so, despite mathematics being 
thousands of years old. That thing was chaos and chaotic behaviour.  
 
We then gently applied these ideas of iterating functions to a new kind of number, called 
confusingly a complex number. We learned that they were nothing to be afraid of at all but just 
two normal numbers joined together. We could do calculations like addition and multiplication 
with them just like the normal mathematics we know, except for one simple special rule.  
 
2​
We then focussed only on the z​ +c function, iteratively applied to complex numbers. We found 
that the orbits showed a range of behaviours, from divergence, convergence, periodic and 
chaotic orbits. We made an atlas, a kind of guide, to show through colour, how each point in the 
complex plan behaves ­ and we found the Mandelbrot and Julia sets. 
 
I really hope you found the journey easy, interesting, at times exciting and surprising, and with 
results that were pleasing and beautiful, haunting even.  
 
I would welcome your comments, feedback to improve the guide, ideas for exploring in different 
directions. I’d especially welcome your feedback on any part of the journey that was difficult or 
could have been better explained. If your feedback significantly improves the next edition, I’ll 
send you a copy for free.  
 
Join the conversation at: 
http://makeyourownmandelbrot.blogspot.com 
 
 
   
Resources 
 
XaoS 
A free open source fractal explorer for Windows, Linux and Mac. It’s really good at animating a 
diving session, as you fall deeper and deeper into some part of the Mandelbrot set. 
http://matek.hu/xaos/doku.php 
 
IPython 
A free open source package of the Python programming language together with commonly used 
extensions for numerical and graphical work.  
http://ipython.org/ 
 
Wakari.io 
An online version of IPython, with free trial accounts. Used for many of the Mandelbrot plotting 
examples in this guide. 
http://wakari.io 
 
 

www.allitebooks.com

You might also like