# Mandelbrot Set Fractal

I thought I would give this months community challenge a try. This is my first time using Python. It does take quite a while to run and it's not very colourful but it works.

from PIL import Image, ImageDraw

img = Image.new("RGB", (2400, 2400), "white")
draw = ImageDraw.Draw(img)

max_count = 200
width = img.size[0]
height = img.size[1]

for row in range(height):
for col in range(width):
str_output = ""
c = complex(
(col - float(width)/2.0)*5.0/float(width),
(row - float(height)/2.0)*5.0/float(height)
)
iteration = 0
z = 0
while abs(z) < 2 and iteration < max_count:
z = z**2 + c
iteration += 1
if abs(z) < 2:
draw.point((col, row), fill="black")
else:
draw.point((col, row), fill=(255 - iteration,255 - iteration,255 - iteration))

img.save('mandelbrot.png')


• What version of Python are you using? – SuperBiasedMan Oct 13 '15 at 11:00
• @SuperBiasedMan 3.whatever_the_latest_release_is – James Fenwick Oct 13 '15 at 11:01
• @JamesFenwick That would be 3.5 – Justin Oct 14 '15 at 18:19

Your constants should be in UPPER_SNAKE_CASE

MAX_COUNT = 200
WIDTH = img.size[0]
HEIGHT = img.size[1]


Instead of nested for loops, you can use itertools.product which basically will perform the nested iteration you need:

from itertools import product

for row, col in product(range(height), range(width))


You don't use str_output, you should clean up unused values.

You should have whitespace either side of your mathematical operators and have a space after each comma in a comma separated list of values:

(col - float(width) / 2.0) * 5.0 / float(width),
draw.point((col, row), fill=(255 - iteration, 255 - iteration, 255 - iteration))


You should also keep lines below 79 characters as the Python style guide dictates. You can split lines quite easily when they're in paretheses:

    draw.point((col, row), fill=(255 - iteration, 255 - iteration,
255 - iteration))


Also your mileage may vary on whether or not this is more readable but you could use a ternary for your final if condition. Like this:

    draw.point((col, row), fill=("black" if abs(z) < 2 else
(255 - iteration, 255 - iteration,
255 - iteration))


The formatting is definitely more awkward, but I personally like these structures because it makes it clear that the only difference in the two results is that one condition.

• This feels a bit backwards to me

img = Image.new("RGB", (2400, 2400), "white")
width = img.size[0]
height = img.size[1]


compared to this

WIDTH = 2400
HEIGHT = 2400
img = Image.new("RGB", (WIDTH, HEIGHT), "white")

• You can eliminate all the float calls because you are using Python 3 where true division is the default.

• for loops are generally preferred over while loops. A possible way to arrange the inner loop is this:

z = 0
for iteration in range(MAX_COUNT):
z = z**2 + c
if abs(z) >= 2:
fill = (255 - iteration, 255 - iteration, 255 - iteration)
break
else:
fill="black"
draw.point((col, row), fill=fill)