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

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 is simply set equal to z (i.e. the point in the complex plane where the pixel is located).

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 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).

# # julia.py - 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 fout.write('\n') # Close file fout.close()

### 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:

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):

# # julia_sequence.py - 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) + ' ') fout.write('\n') # Close file fout.close()

Assuming that the only PGM files in the current directory are the numbered files generated by `julia_sequence.py`, 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

### Appendix

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 julia.py 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

Pingback: The Julia Set » Tim Kerins Science and Sums

good work

Thanks Emmanuel!

Ted

thx

wlcm

Very nice! I am working on something similar, take a look: http://www.math-in-python.com/kvapil/complex_fractals

Wow, I love those!

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

Ted

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 https://batchloaf.wordpress.com/2013/04/16/first-attempt-at-printing-to-an-lcd-display-from-a-dspic30f4011/, but it looks pretty hard for a starting project. But it might serve me as a goal to achieve in the, hopefully near, future.

Jan

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.

Ted

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

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.

Ted

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 🙂

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.

Ted

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

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

c(0.626)

ooh and tnx for article really helped

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

realandimaginaryparts of what we call acomplexnumber.A

realnumber 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: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,

An

imaginarynumber is a much more exotic thing altogether – it’s a number that produces anegativeanswer 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:Or to write it another way,

i

^{2}= -1We 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

complexnumber is a number with realandimaginary parts. In other words, it’s basically just a real number added to an imaginary number. Here are some examples of complex numbers: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,

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

extrememlyuseful 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 amagnitudeand anangle, 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,

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…

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 thereal axisand theimaginary axis. The real and imaginary parts of a complex number become its x and y coordinates on the complex plane. When we talk about themagnitudeof a complex number, we just mean its distance from the origin (the point 0,0) in the complex plane. Similarly, when we talk about theangleof 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

soincredibly 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 anoutstandingjob 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…

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

complexcalculation 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!

Ted

thanks you for detail response ,and yes it helped very much .

Great! Glad you found it useful. Best of luck with your project.

Ted