Creating Julia Set images in Python

Today, I’ve been experimenting with creating Julia Set images in Python.

Montage of Julia Set images

Each of the four images above shows the same square region of the complex plane; between -2 and +2 on the real axis and between -2j and +2j on the imaginary axis. Each pixel location in each image represents a different complex value, z. The grey level of each pixel is determined by generating an iterative sequence of complex values using the equation below. The starting value z_0 is simply set equal to z (i.e. the point in the complex plane where the pixel is located).

z_{n+1} = z_n^2 + c

The actual image produced depends on the value of the complex parameter c, as shown in the four images above, each of which used a different value of c. The same value of c is used for every pixel in a given image.

In my implementation, each pixel starts out with a grey level of 255 (i.e. pure white). With each iteration of the formula, the grey level of the pixel is reduced by 5. Iteration continues until either the pixel value reaches zero or the magnitude of z_n exceeds a threshold (I picked 10 as the threshold value, more or less arbitrarily).

The following python code generates a single Julia Set image for a specific value of the parameter c (specified on line 17 of the program).

# - Generate a Julia Set image
# Written by Ted Burke
# Last updated 10-2-2012

import numpy

# Specify image width and height
w, h = 200, 200

# Specify real and imaginary range of image
re_min, re_max = -2.0, 2.0
im_min, im_max = -2.0, 2.0

# Pick a value for c
c = complex(0.0,0.65)

# Generate evenly spaced values over real and imaginary ranges
real_range = numpy.arange(re_min, re_max, (re_max - re_min) / w)
imag_range = numpy.arange(im_max, im_min, (im_min - im_max) / h)

# Open output file and write PGM header info
fout = open('julia.pgm', 'w')
fout.write('P2\n# Julia Set image\n' + str(w) + ' ' + str(h) + '\n255\n')

# Generate pixel values and write to file
for im in imag_range:
	for re in real_range:
		z = complex(re, im)
		n = 255
		while abs(z) < 10 and n >= 5:
			z = z*z + c
			n -= 5
		# Write pixel to file
		fout.write(str(n) + ' ')
	# End of row

# Close file

Julia Set Animation

Julia Set animation

Having created some static images using the program above, I then moved on to creating the animation shown on the right, which comprises a sequence of Julia Set images.

The python code below is a modified version of the previous program that generates a sequence of 100 numbered PGM files. Each file is a Julia Set image created using a different value for the parameter c.

These are the 100 individual frames:
Montage of 100 Julia Set images used as frames in an animation

This is the Python code used to generate the images shown above as 100 separate numbered files (001.pgm, 002.pgm, and so on up to 100.pgm):

# - Generates Julia Set images
# Written by Ted Burke
# Last updated 10-2-2012

import numpy

# Specify image width and height
w, h = 200, 200

# Specify real and imaginary range of image
re_min, re_max = -2.0, 2.0
im_min, im_max = -2.0, 2.0

# Generate evenly spaced values over real and imaginary ranges
real_range = numpy.arange(re_min, re_max, (re_max - re_min) / w)
imag_range = numpy.arange(im_max, im_min, (im_min - im_max) / h)

# Frame counter
frame = 0

# Iterate over a range of c values
for c_im in numpy.arange(0.0, 1.0, 0.01):
	# Increment frame counter
	frame += 1
	# Open file and write PGM header info
	filename = "{0:03d}.pgm".format(frame)
	print filename
	fout = open(filename, 'w')
	fout.write('P2\n# Julia Set image\n' + str(w) + ' ' + str(h) + '\n255\n')
	# Generate pixel values
	for im in imag_range:
		for re in real_range:
			z = complex(re, im)
			c = complex(0.0,c_im)
			n = 255
			while abs(z) < 10 and n >= 5:
				z = z*z + c
				n = n - 5
			# Write pixel value to file
			fout.write(str(n) + ' ')
	# Close file

Assuming that the only PGM files in the current directory are the numbered files generated by, the individual images can be combined into a single animated gif file using ImageMagick’s convert command, as follows:

convert -delay 10 *.pgm julia.gif

To modify the animation so that it sequences back and forth through the frames (rather than simply jumping back to first frame once it reaches the end of the sequence), I used the following command:

convert julia.gif -coalesce \( -clone -2-1 \) -quiet -layers OptimizePlus -loop 0 julia.gif


The composite image of four individual Julia Set images shown at the beginning of this post was created using ImageMagick.

I began by running the program four times with different c values (0.6j, 0.65j, 0.7j, 0.75j). I renamed these files as

  • julia_c0.60.pgm
  • julia_c0.65.pgm
  • julia_c0.70.pgm
  • julia_c0.75.pgm

I then added a label to each image as follows:

convert julia_c0.60.pgm -gravity South -annotate +5+5 'c = 0 + 0.6j' julia_label_c0.60.png
convert julia_c0.65.pgm -gravity South -annotate +5+5 'c = 0 + 0.65j' julia_label_c0.65.png
convert julia_c0.70.pgm -gravity South -annotate +5+5 'c = 0 + 0.7j' julia_label_c0.70.png
convert julia_c0.75.pgm -gravity South -annotate +5+5 'c = 0 + 0.75j' julia_label_c0.75.png

Finally, I combined the four labeled images into a single PNG image using the following command:

convert \( julia_label_c0.60.png julia_label_c0.65.png +append \) \( julia_label_c0.70.png julia_label_c0.75.png +append \) -append julia_montage.png
This entry was posted in Uncategorized and tagged , , , , , , , , , , , . Bookmark the permalink.

18 Responses to Creating Julia Set images in Python

  1. Pingback: The Julia Set » Tim Kerins Science and Sums

  2. Nkansah, Emmanuel says:

    good work

  3. zeddicus says:


  4. quapka says:

    Very nice! I am working on something similar, take a look:

    • batchloaf says:

      Wow, I love those!

      There’s lots of other interesting stuff on your website too.


      • quapka says:

        Thanks a lot! It is actually a project to one of our school subject I took with my friend- that’s why there is almost everything twice. I looked at other your articles and those projects look great. I am hoping I’ll find some time during the summer holiday to look into electronics together with programming, should be fun since I am pretty much analfabet in electronics. Particularly I like this one, but it looks pretty hard for a starting project. But it might serve me as a goal to achieve in the, hopefully near, future.


      • batchloaf says:

        Hi Jan,

        Yes, I wondered at first why it was divided in two like that, but then I saw your two names in the footer at the bottom which explained it.

        If you’re interested in learning about electronics, I strongly recommend picking up an Arduino. It’s the easiest way to get started on your own because there are loads of very well documented projects online and many libraries to support interfacing to different devices (including LCD and other screens).

        Anyway, best of luck with your summer projects and thanks again for sending the link.


  5. somada141 says:

    Beautiful stuff Ted! I’m so ‘stealing’ your code for my post but I’m gonna link back here giving due credit 😀

    • batchloaf says:

      Thanks somada141,

      I’ve been reading some of your posts on VTK – very interesting indeed! I’ll have to give it a try. I’m following your blog now so that I can keep an eye on your updates.


      • somada141 says:

        Thanks Ted (name’s Adam btw)! I have a few post-ideas for VTK which I hope you’ll find interesting but I don’t want to be held responsible for your descent into madness once you start dealing with that infernal toolkit 🙂

      • batchloaf says:

        Hi Adam,

        Ha ha yes, based on what I’ve read so far, it looks like it can be a bit of a brain bender! Anyway, I look forward to reading more about it.


  6. Pingback: NumPy to VTK: Converting your NumPy arrays to VTK arrays and files | PyScience

  7. madiba says:

    Hi am working on a school project ,need some clarification
    on line 17 ,c value takes two argument ,in my question it just =z^2 +c , for c=0.626
    so my question is ,is the first argument default (0.0) as in my case do i use
    c(0.0,0.626) or
    ooh and tnx for article really helped

    • batchloaf says:

      Hi madiba,

      Glad to hear you found this article useful. I’m not sure how much you know about complex numbers, so apologies in advance if you already know everything I’m about to explain…

      Those two arguments on line 17 (the values 0.0 and 0.65) are actually the real and imaginary parts of what we call a complex number.

      A real number is actually just what we normally think of as a number. It can be positive or negative; it can be a whole number or a fraction; or it can even have an infinite number of decimal places (like π does, for example); but it’s still basically just a regular old number. For example, the following are all real numbers:

      1, 176, -5, 7.513, -3.42, π, 2π, ¾

      One important property of every real number other than zero is that when you square it (multiply it by itself) the answer is always positive (and also a real number). This is the case even when the original number was negative. For example,

      2 × 2 = 4
      -3 × -3 = 9
      4.7 × 4.7 = 22.09
      -½ × -½ = ¼

      An imaginary number is a much more exotic thing altogether – it’s a number that produces a negative answer when you square it! I find it extremely difficult to picture what that actually means. How can you square a number and get a negative answer?! In fact, it’s so difficult to picture it that imaginary numebrs didn’t really catch on until the late 1700s when geniuses like Euler and Gauss (who are really fascinating to read about) used them to solve some imporant problems, which I guess persuaded mathematicians that they really are useful.

      Anyway, the most important imaginary number is the imaginary unit, normally just written as i. (Note: electrical engineers like me normally use the letter j instead of i because we already use i for electric current. However, for clarity I’ll use the letter i here since that’s what everyone else uses.) In a nutshell, i is basically the square root of -1. In other words, when you multiply i by itself, the answer is -1. Again, this is very difficult to picture, but please bear with me. By definition, i has the following property:

      i × i = -1

      Or to write it another way,

      i2 = -1

      We write every other imaginary number as a multiple of i. For example, the square root of -4 is 2i. Similary, the square root of -22.09 is 4.7i. So imaginary numbers are basically written as the product of a real number and i.

      Now, if that’s not already confusing enough for you, let’s take things up another notch… 😉

      A complex number is a number with real and imaginary parts. In other words, it’s basically just a real number added to an imaginary number. Here are some examples of complex numbers:

      2 + 3i
      3.5 - 7.2i
      517.0 + 113.4i

      It’s worth pointing out that all real and imaginary numbers are actually complex numbers too, where either the real or imaginary part is equal to zero. For example,

      The real number 2 = 2 + 0i
      The real number -47.5 = -47.5 + 0i
      The imaginary number 7i = 0 + 7i

      At this point, if you’re thinking that complex numbers seem crazy and pointless, then you’re exactly where I was when I was when I was in school. Take my word for it though, they’re extrememly useful in real practical applications. As an electrical engineer, I use complex numbers almost every day to represent things like AC electrical currents and voltages, or different frequency components of an audio or biomedical signal. Without getting bogged down in the details, we use them a lot when we need to represent something that can’t be completely represented by just one number – especially when something has a magnitude and an angle, which complex numbers are particularly good at representing in a convenient way. A lot of the day-to-day calculations that engineers use complex numbers for would (ironically) be an awful lot more complicated if we didn’t use complex numbers.

      When we multiply two complex numbers together (or divide one by another), the result is always a complex number. You basically just multiply out the terms. For example,

      (2 + 3i) × (4 - 2i)
           = (2 × 4) + (2 × -2i) + (3i × 4) + (3i × -2i)
           = 8 - 4i + 12i + 6
           = 14 + 8i

      Note: In case you were confused by (3i × -2i) being equal to 6, remember that (i × i) is -1 and (3 × -2) is -6 and finally (-1 × -6) is 6.

      A complex variable is just a variable that can store a complex number (both real and imaginary parts). Mathematicians use the capital letter Z to represent the set of all complex numbers, so people tend to use the lower-case letter z a lot as a name for a complex variable. Personally, I have a habit of using z1, z2, z3, etc to represent multiple complex variables when I don’t have a special reason for using another letter. For example, I could rewrite the example complex multiplication above as…

      z1 = 2 + 3i
      z2 = 4 - 2i
      z3 = z1 × z2 = 14 + 8i

      Complex numbers are very frequently depicted as points on the complex plane, which is basically just an x-y plane where the x-axis is real and the y-axis is imaginary. Actually, we normally just refer to the two axes as the real axis and the imaginary axis. The real and imaginary parts of a complex number become its x and y coordinates on the complex plane. When we talk about the magnitude of a complex number, we just mean its distance from the origin (the point 0,0) in the complex plane. Similarly, when we talk about the angle of a complex number, we just mean the angle between the positive half of the real axis and the straight line from the origin to the point.

      Complex numbers have some interesting and useful properties that are not obvious at first glance. For example, when you multiply two complex numbers together (let’s call them z1 and z2), the magnitude of the product is the product of the magnitudes of the two numbers. However, the angle of the product is the sum of the angle of z1 and the angle of z2. Ok, this part is too complicated to explain in a comment like this, so let me get back on track…

      Because complex numbers are so incredibly useful (even though they’re also so widely misunderstood) many modern programming languages have built in features for using them. C didn’t originally have any special way of dealing with them, which meant that you needed to use two variables to represent each complex number (one for the real part and one for the imaginary part), but they added complex numbers to C a few years back. As far as I know, Python has had built-in support for complex numbers since day 1 and it does an outstanding job of managing them.

      In the first example program above (written in Python, obviously) c and z are both complex variables. Line 17 creates a complex value with real part equal to 0 and imaginary part equal to 0.65i and assigns that value to the variable c. Mathematically, we might write…

      c = 0.0 + 0.65i

      Furthermore, line 30 creates another complex value and assigns it to the variable z. That line is inside a nested while loop, so it actually happens over and over again with different combinations of the values re and im. In line 32, the bit that says “abs(z)” gets the magnitude of the complex number z. Also, on line 33, the calculation “z = z*z + c” is a complex calculation because z and c are both complex.

      It’s difficult to fully understand the Mandelbrot and Julia sets without understanding complex numbers, because the iterative process that generates those mind-blowing patterns is actually intimately connected to the operations of complex multiplication and addition. Geometrically, complex multiplication can be thought of as scaling and rotation in the complex plane. Ok, I realise that I’m getting lost in the details again.

      If you already know all this, I apologise again – hopefully it will be useful to someone else though! On the other hand, if you don’t know about complex numbers I strongly recommend that you look it up on Khan Academy or YouTube or wherever – I’m sure you’ll find some much clearer explanations than this.

      Ok, that’s it. Best of luck with your project!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s