Even Stranger Attractors
Today I attempted to improve on my previous strange attractor script.
One of the drawbacks of the previous script was the high number of false positives. Thousands of images were being saved to my hard drive but only a few of those were truly strange attractors. The rest were loops, spots, or spiral patterns. I solved this problem by only saving images where at least 1% of the pixels have been visited.
The other drawback was the system of simply painting each visited pixel white directly on an image object, allowing for only a vague silhouette of the strange attractor. A better technique is to record how often each pixel has been visited in an array, and then create an image where the colour of each pixel corresponds to how often it has been visited. This results in much more attractive images reminiscent wispy smoke.
Coming along nicely I think, although more work is needed on the coloring. Source code for this version follows. Note that if you would like to try running this Python script you will need to have both Numpy and Python Imaging Library installed. Also please note that this is not yet the most tidy or efficient code… I’ve left plenty of room for improvement!
import Image import random from math import floor import numpy as np SIZE = 400 img_index = 0 class Formula(object): def __init__(self, seed): self.seed = seed random.seed(seed) self.coefficients = [random.choice([random.random()*4-2, 0, 1])for x in range(6)] self.a, self.b, self.c, self.d, self.e, self.f = tuple(self.coefficients) def __call__(self, x, y): # return a*(x**2) + b*x*y + c*(y**2) + d*x + e*y + f return self.a*(x**2)\ + self.b*x*y\ + self.c*(y**2)\ + self.d*x\ + self.e*y\ + self.f def plotmap(x): # scales the x or y up to an integer that fits in our image array catchSize = 1 return int((x+catchSize)*(SIZE/(catchSize*2))) MAXVAL = 1000 while True: random.seed() seed = int(random.random() * 10000000) f = Formula(seed) seed = int(random.random() * 10000000) g = Formula(seed) x, y = random.random(), random.random() imgarray = np.zeros([SIZE, SIZE], int) while imgarray[plotmap(x), plotmap(y)] < MAXVAL: x, y = f(x, y), g(x, y) if not(plotmap(x) and plotmap(y)): #print "break" break # catch negative numbers... the "IndexError" won't # do this resulting in "wrap-around" images try: imgarray[plotmap(x), plotmap(y)] += 1 except IndexError: #print "break!" break else: #print sum(imgarray[imgarray==True].flatten()), SIZE **2 imgarray = np.array(imgarray / (MAXVAL/256.), np.uint8) if sum(imgarray[imgarray==True].flatten()) > (SIZE **2) * .01: ## only save image if a certain percentage of the total area ## has been coloured. img = Image.fromarray(imgarray, "L") img.save("a_%06d_%d_%d.png" % (img_index, f.seed, g.seed), "PNG") img_index += 1 print "SAVED!"