Home > Graphics, Python, Strange Attractors > Even Stranger Attractors

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
        self.coefficients = [random.choice([random.random()*4-2,
                        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:


    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"
            # catch negative numbers... the "IndexError" won't
            # do this resulting in "wrap-around" images
            imgarray[plotmap(x), plotmap(y)] += 1
        except IndexError:
            #print "break!"
        #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!"
  1. No comments yet.
  1. January 8, 2010 at 11:17 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: