Variations of the Mandelbrot set
This resource includes primary and/or secondary research. Learn more about original research at Wikiversity. |
This short article by Dan Polansky explores variations of the Mandelbrot set. It asks: what happens if we change the exponent of the iterative function (away from 2) or if we let the orbits start from a fixed value different from 0?
The results are interesting, some of them bizarre. That a simple formula iterated could result in the curves of the Mandelbrot set is curious enough; the kind of deformations that result from changing these parameters perhaps even more so.
Let us recall: the function being iterated in the standard Mandelbrot set is f(x) = x ** 2 + c, where the iteration process starts at zero. We can instead take e.g. f(x) = x ** 2.1 + c, starting at 0.5 + 0.5i instead of 0.
Exercise: install PyPy and other requirements, copy the Python code below to a local file, and try your own hand in discovering interesting plots. Try different parameter values or even different iteration formulas.
On a subjective note, some people to whom I have shown the images asked whether it was something like Rorschach test. Indeed, one could perhaps produce a series of neo-Rorschach test using this technique.
Gallery
editA gallery follows.
Normal: exponent 2, start from 0:
Exponent 2, starting from 0.5:
Exponent 2, starting from 0.5i:
Exponent 2, starting from 0.5 + 0.5i:
Exponent 2.1, starting from 0.5 + 0.5i:
Exponent 2, starting from 0.3 + 0.3i:
Exponent 2, starting from 0.7 + 0.7i:
Exponent 2, starting from 0.9 + 0.9i:
Part of the above images are covered in the animation File:Mandelbrot Set Animation 1280x720.gif.
Plotting code
editThe images above were plotted using the following Python code, run using PyPy JIT compiler rather than the standard CPython. For this code, the speed difference from using PyPy is huge; the speed with PyPy in plotting a 2000 x 2000 pixel image is pleasant, unlike with CPython. We make use of pure-Python PNG-creation library purepng. To be fair to CPython, the plotting could turn rather tolerable if it would use vectorization using numpy. The code is very straightforward, like code one might find written in Basic in a popular computing magazine decades ago.
import png # purepng
import math, cmath
import sys
# Adapted from https://github.com/cbertram/mandelbrot/blob/master/mandelbrot.py, which is copyright Christian Betram under MIT license.
# Uses purepng pure-Python library ==> runs in PyPy, astronomically faster than in CPython.
preset = 1
if preset == 1:
name = "MandelbrotSetVariant.png"
width, height = 2000, 2000
centerX, xSize = -0.5, 3
centerY, ySize = 0, 3
maxIterCount = 256 * 2
z0 = 0
baseX = centerX - xSize / 2.0
baseY = centerY + ySize / 2.0
def setUpColors1(maxIterCount):
# Use gray and a single hue
red, green, blue = [0] * maxIterCount, [0] * maxIterCount, [0] * maxIterCount
for iterCount in xrange(maxIterCount):
a = (maxIterCount - iterCount) % 32
b = (maxIterCount - iterCount) % 64
if a == b:#b < a
a = 32 - a
baseColor = a * 7 + 31
redFactor = a / 32.0
greenFactor = (0.5 + redFactor * 0.5)
red[iterCount] = int(baseColor * redFactor)
green[iterCount] = int(baseColor * greenFactor)
blue[iterCount] = baseColor
return red, green, blue
def setUpColors2(maxIterCount):
# Cycle various hues to better see iteration count escape boundaries
red, green, blue = [0] * maxIterCount, [0] * maxIterCount, [0] * maxIterCount
for iterCount in xrange(maxIterCount):
m = iterCount
baseColor = (maxIterCount - m) % 256
if m % 5 == 0:
red[iterCount] = int(baseColor * 0.75)
green[iterCount] = baseColor
blue[iterCount] = baseColor
elif m % 5 == 1:
red[iterCount] = int(baseColor * 0.75)
green[iterCount] = int(baseColor * 0.75)
blue[iterCount] = baseColor
elif m % 5 == 2:
red[iterCount] = baseColor
green[iterCount] = baseColor
blue[iterCount] = int(baseColor * 0.75)
elif m % 5 == 3:
red[iterCount] = baseColor
green[iterCount] = int(baseColor * 0.75)
blue[iterCount] = int(baseColor * 0.75)
elif m % 5 == 4:
red[iterCount] = int(baseColor * 0.75)
green[iterCount] = baseColor
blue[iterCount] = int(baseColor * 0.75)
return red, green, blue
def setUpColors3(maxIterCount):
# Use a single hue and very slowly decreasing color brightness
red, green, blue = [0] * maxIterCount, [0] * maxIterCount, [0] * maxIterCount
for iterCount in xrange(maxIterCount):
a = (maxIterCount - iterCount) % 256
b = (maxIterCount - iterCount) % 512
if a == b:
a = 255 - a
baseColor = a
redFactor = a / 256.0
greenFactor = (0.5 + redFactor * 0.5)
red[iterCount] = int(baseColor * redFactor)
green[iterCount] = int(baseColor * greenFactor)
blue[iterCount] = baseColor
return red, green, blue
def iterate(z0, c, maxIterCount):
z = z0
iterCount = 0
while iterCount < maxIterCount:
z = z ** 2 + c
#z = z ** 1 + c
#z = z ** 2.1 + c
if z.real**2 + z.imag**2 > 4:
return iterCount
iterCount += 1
return None
def main():
red, green, blue = setUpColors1(maxIterCount)
image = []
for h in xrange(height):
if h % 10 == 0:
sys.stdout.write(str(100 * h / height) + "% complete \r")
sys.stdout.flush()
row = [0] * width * 3
for w in xrange(width):
x = baseX + w * float(xSize) / width
y = baseY - h * float(ySize) / height
m = iterate(z0, complex(x, y), maxIterCount)
if m is None:
row[3 * w] = 0
row[3 * w + 1] = 0
row[3 * w + 2] = 0
else:
row[3 * w] = red[m]
row[3 * w + 1] = green[m]
row[3 * w + 2] = blue[m]
image.append(row)
print ""
with open(name, "wb") as file1:
w = png.Writer(width, height, greyscale=False)
w.write(file1, image)
if __name__ == "__main__":
main()
Plotting prerequisites
editOne option for installing prerequisites is this:
1) Install PyPy
2) Install pip for PyPy: pypy -m ensurepip
3) Use pip to install purepng: pypy -m pip install purepng
Links:
- python - Install pip on pypy, stackoverflow.com
- purepng, pypi.org
Further reading
edit- Mandelbrot set, wikipedia.org
- Plotting algorithms for the Mandelbrot set, wikipedia.org
- Mandelbrot set with variations, blbadger.github.io
- Mandelbrot set, rosettacode.org