9
\$\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

\$\endgroup\$
  • \$\begingroup\$ What version of Python are you using? \$\endgroup\$ – SuperBiasedMan Oct 13 '15 at 11:00
  • \$\begingroup\$ @SuperBiasedMan 3.whatever_the_latest_release_is \$\endgroup\$ – James Fenwick Oct 13 '15 at 11:01
  • \$\begingroup\$ @JamesFenwick That would be 3.5 \$\endgroup\$ – Justin Oct 14 '15 at 18:19
3
\$\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.

\$\endgroup\$
2
\$\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)
    
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.