Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Mandelbrot/Julia set in Processing/Python.
# IF YOU WANT A JULIA SET, SET isMandelbrot TO False.
# Copyright (c) 2015 Ethan White. Licensed under 3-clause BSD.
# Requires the Python mode for Processing.
import time
import math
# Fudge factors
startSize = (1000, 1000)
widthMultFudge = float(4)
heightMultFudge = float(4)
widthAddFudge = 10
scaleAddFudge = complex(2, 2)
escapeFudge = 2.0 # The maximum possible absolute value that a point can reach before it is assumed to be growing indefinitely; anything >= 2 works. Trying < 2 is fun, though.
minTimePerIteration = 0 # The minimum time, in seconds, between iterations. Zero disables this feature.
isMandelbrot = True # If set to true, `iterator` is ignored and is assumed to be precisely pt.complex**2 + pt.initialComplex; to remove the overhead of function calls.
iterator = lambda pt: pt.complex**5 + 0.544 # The function that is iterated on each point. A Point object is passed in. The one it starts out with is a Julia set.
# If isMandelbrot is true, this is ignored, and a Mandelbrot set is drawn instead, although one could draw a Mandelbrot set with iterator,
# too; it's just an optimization to avoid the overhead of function calls.
# 0.544 is not in the Mandelbrot set.
# Here are some other possible Julia sets that are interesting:
# Consider: the Julia set for x^n + c consists of one island if and only if c is in the mandelbrot set
# Here's a function to test if something is in the mandelbrot set:
# def mand(n):
# origN = n
# for i in xrange(10000):
# n = n**2 + origN
# if n.real**2 + n.imag**2 > 4:
# return "Eliminated on iter %s" % str(i)
# return "In mandelbrot"
# iterator = lambda pt: pt.complex**7 + 0.626 # c _not_ in mandelbrot
# iterator = lambda pt: pt.complex**4 + 0.484 # c _not_ in mandelbrot
# iterator = lambda pt: math.e**(pt.complex**3) - 0.621 # c in mandelbrot
# iterator = lambda pt: pt.complex**3 * math.e**(pt.complex) + 0.33333 # c _not_ in mandelbrot
# iterator = lambda pt: pt.complex**3 + 0.85 # c _not_ in mandelbrot
# iterator = lambda pt: pt.complex**2 + 0.25 # c in mandelbrot
# iterator = lambda pt: pt.complex**2 + 0.75 # c _not_ in mandelbrot
# iterator = lambda pt: pt.complex**2 + complex(0.123, 0.745) # c _not_ in mandelbrot
# iterator = lambda pt: pt.complex**3 + complex(0.123, 0.628) # c in mandelbrot
# iterator = lambda pt: pt.complex**2 + 1 # c _not_ in mandelbrot
# iterator = lambda pt: pt.complex**2 - 1 # c in mandelbrot
def complexToPoint(c):
c += scaleAddFudge
return (c.imag * float(width + widthAddFudge) / widthMultFudge, c.real * float(height) / heightMultFudge)
def pointToComplex(pt):
x, y = pt
return complex(float(x) * widthMultFudge / (width + widthAddFudge), float(y) * heightMultFudge / height) - scaleAddFudge
class Point:
def __init__(self, pt):
self.complex = pointToComplex(pt)
self.initialComplex = self.complex
self.pt = pt
self.x, self.y = pt
self.dead = False
def iterate(self):
global escapeFudge
if isMandelbrot:
self.complex = self.complex**2 + self.initialComplex
else:
self.complex = iterator(self)
ret = self.complex.imag**2 + self.complex.real**2 <= escapeFudge**2
if not ret:
self.dead = True
return ret
def drawIfDead(self):
if not self.iterate():
point(self.x, self.y)
return False
return True
points = []
def setup():
startW, startH = startSize
size(startW, startH)
fill(0, 0, 0)
stroke(0, 0, 0)
clear()
for x in xrange(width):
for y in xrange(height):
points.append(Point((x, y)))
iterationNum = 0
# Here are some possible color schemes:
# (Color schemes are arrays of tuples of the form (r, g, b)).
# colors = [(0xff, 0xff, 0xff), (0xdd, 0xdd, 0xdd), (0xbb, 0xbb, 0xbb), (0x99, 0x99, 0x99)] # Completely desaturated color scheme
# colors = [(0xd1, 0xc4, 0xe9), (0x95, 0x75, 0xcd), (0x67, 0x3a, 0xb7), (0x51, 0x2d, 0xa8), (0x31, 0x1b, 0x92)] # 100, 300, 500, 700, and 900 variants of Deep Purple from Material Design
# colors = [(0x95, 0x75, 0xcd), (0x67, 0x3a, 0xb7), (0x51, 0x2d, 0xa8), (0x31, 0x1b, 0x92)] # Same as above, minus the 100 variant
# colors = [(0xff, 0xcc, 0xbc), (0xff, 0x8a, 0x65), (0xff, 0x57, 0x22), (0xe6, 0x4a, 0x19), (0xbf, 0x36, 0x0c)] # 100, 300, 500, 700, 900 of Deep Orange
colors = [(0xff, 0x8a, 0x65), (0xff, 0x57, 0x22), (0xe6, 0x4a, 0x19), (0xbf, 0x36, 0x0c)] # 300, 500, 700, 900 of Deep Orange
# colors = [(0xb2, 0xdf, 0xdb), (0x4d, 0xb6, 0xac), (0x00, 0x96, 0x88), (0x00, 0x79, 0x6b), (0x00, 0x4d, 0x40)] # 100, 300, 500, 700, 900 of Teal
# colors = [(0x4d, 0xb6, 0xac), (0x00, 0x96, 0x88), (0x00, 0x79, 0x6b), (0x00, 0x4d, 0x40)] # 300, 500, 700, 900 of Teal
# colors = [(0xff, 0xe0, 0xb2), (0xff, 0xb7, 0x4d), (0xff, 0x98, 0x00), (0xf5, 0x7c, 0x00), (0xe6, 0x51, 0x00)] # 100, 300, 500, 700, 900 of Orange
# colors = [(0xff, 0xb7, 0x4d), (0xff, 0x98, 0x00), (0xf5, 0x7c, 0x00), (0xe6, 0x51, 0x00)] # 300, 500, 700, 900 of Orange
# colors = [(0xbb, 0xde, 0xfb), (0x64, 0xb5, 0xf6), (0x21, 0x96, 0xf3), (0x19, 0x76, 0xd2), (0x0d, 0x47, 0xa1)] # 100, 300, 500, 700, 900 of Blue
# colors = [(0x64, 0xb5, 0xf6), (0x21, 0x96, 0xf3), (0x19, 0x76, 0xd2), (0x0d, 0x47, 0xa1)] # 300, 500, 700, 900 of Blue
# For minTimePerIteration
lastTimeDrawn = 0
# Last time something was eliminated
lastTimeEliminated = 0
def draw():
global iterationNum
global points
global escapeFudge
global lastTimeDrawn
global lastTimeEliminated
if time.time() - lastTimeDrawn < minTimePerIteration:
time.sleep(minTimePerIteration - (time.time() - lastTimeDrawn))
lastTimeDrawn = time.time()
iterationNum += 1
numDeleted = 0
r, g, b = colors[iterationNum % len(colors)]
fill(r, g, b)
stroke(r, g, b)
for pt in points:
if not pt.dead:
if not pt.drawIfDead():
numDeleted += 1
lastTimeEliminated = iterationNum
print "Eliminated %s on the iteration %s" % (numDeleted, iterationNum)
# Draw the informational overlay
text("ABC", 0, 0)
if iterationNum - lastTimeEliminated > 30:
frameRate(0) # Stop rendering
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.