10
\$\begingroup\$

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

black and white mandelbrot set

asked Oct 12, 2015 at 21:13
\$\endgroup\$
3
  • \$\begingroup\$ What version of Python are you using? \$\endgroup\$ Commented Oct 13, 2015 at 11:00
  • \$\begingroup\$ @SuperBiasedMan 3.whatever_the_latest_release_is \$\endgroup\$ Commented Oct 13, 2015 at 11:01
  • \$\begingroup\$ @JamesFenwick That would be 3.5 \$\endgroup\$ Commented Oct 14, 2015 at 18:19

2 Answers 2

4
\$\begingroup\$

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.

answered Oct 13, 2015 at 9:19
\$\endgroup\$
3
\$\begingroup\$
  • 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)
    
answered Oct 13, 2015 at 10:54
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.