Back
Close

How to plot the Mandelbrot set

[CG]Maxime
10.5K views

Adding colors to the Mandelbrot Set

In order to add some colors, one could associate a color for each possible value of iterations.

In the following example, we are switching from RGB colors to HSV (hue, saturation, value) colors. This allows us to change the color easily by modifying only the hue.

Use of HSV colors
from PIL import Image, ImageDraw
from mandelbrot import mandelbrot, MAX_ITER
# Image size (pixels)
WIDTH = 600
HEIGHT = 400
# Plot window
RE_START = -2
RE_END = 1
IM_START = -1
IM_END = 1
im = Image.new('HSV', (WIDTH, HEIGHT), (0, 0, 0))
draw = ImageDraw.Draw(im)
for x in range(0, WIDTH):
for y in range(0, HEIGHT):
# Convert pixel coordinate to complex number
c = complex(RE_START + (x / WIDTH) * (RE_END - RE_START),
IM_START + (y / HEIGHT) * (IM_END - IM_START))
# Compute the number of iterations
m = mandelbrot(c)
# The color depends on the number of iterations
hue = int(255 * m / MAX_ITER)
saturation = 255
value = 255 if m < MAX_ITER else 0
# Plot the point
draw.point([x, y], (hue, saturation, value))
im.convert('RGB').save('output.png', 'PNG')
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Smooth coloring

In the previous example, you can see bands of color. To remove these bands, we can use a fractional escape count, also known as "normalized iteration count". The theory is a bit difficult, if you are interested in the mathematics, you should read this article entitled "Renormalizing the Mandelbrot Escape".

The mandelbrot function must be modified to add to the result 1 - log(log2(abs(z))) where z is the last computed value of the sequence (abs(z) > 2).

Smooth coloring
from math import log, log2
MAX_ITER = 80
def mandelbrot(c):
z = 0
n = 0
while abs(z) <= 2 and n < MAX_ITER:
z = z*z + c
n += 1
if n == MAX_ITER:
return MAX_ITER
return n + 1 - log(log2(abs(z)))
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

You can also increase the value of MAX_ITER to improve the rendering.

Histogram coloring

In the previous codes, the colors are not equaly distributed. That's particularly true when MAX_ITER is high. To improve the situation, the number of pixels for each iteration number is counted up. For each iteration number, a color will be associated by giving a wider range of colors for iteration numbers that concerns more pixels.

Histogram and smooth coloring
from PIL import Image, ImageDraw
from mandelbrot import mandelbrot, MAX_ITER
from collections import defaultdict
from math import floor, ceil
def linear_interpolation(color1, color2, t):
return color1 * (1 - t) + color2 * t
# Image size (pixels)
WIDTH = 600
HEIGHT = 400
# Plot window
RE_START = -2
RE_END = 1
IM_START = -1
IM_END = 1
histogram = defaultdict(lambda: 0)
values = {}
for x in range(0, WIDTH):
for y in range(0, HEIGHT):
# Convert pixel coordinate to complex number
c = complex(RE_START + (x / WIDTH) * (RE_END - RE_START),
IM_START + (y / HEIGHT) * (IM_END - IM_START))
# Compute the number of iterations
m = mandelbrot(c)
values[(x, y)] = m
if m < MAX_ITER:
histogram[floor(m)] += 1
total = sum(histogram.values())
hues = []
h = 0
for i in range(MAX_ITER):
h += histogram[i] / total
hues.append(h)
hues.append(h)
im = Image.new('HSV', (WIDTH, HEIGHT), (0, 0, 0))
draw = ImageDraw.Draw(im)
for x in range(0, WIDTH):
for y in range(0, HEIGHT):
m = values[(x, y)]
# The color depends on the number of iterations
hue = 255 - int(255 * linear_interpolation(hues[floor(m)], hues[ceil(m)], m % 1))
saturation = 255
value = 255 if m < MAX_ITER else 0
# Plot the point
draw.point([x, y], (hue, saturation, value))
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

And that's all for the Mandelbrot Set! And if you like the Mandelbrot Set, you'll love the Julia Sets!

Create your playground on Tech.io
This playground was created on Tech.io, our hands-on, knowledge-sharing platform for developers.
Go to tech.io
codingame x discord
Join the CodinGame community on Discord to chat about puzzle contributions, challenges, streams, blog articles - all that good stuff!
JOIN US ON DISCORD
Online Participants