Tuesday, November 20, 2012

Fibovisual

Fibonacci


We started this series (no pun intended) by providing a simple Python script that gave us the Fibonacci numbers less than 50.

As previously mentionned, the code was (save as fibonacci.py):

a, b = 0, 1
print a,
while b < 50:
    print b,
    a, b = b, a + b

We would then run it as:
$ python fibo.py

Fibospeak


We then added a way to speak those same numbers (save as fibospeak.py):


import os

def say(something):
    os.system('espeak -ven+f2 "{0}"'.format(something))

a, b = 0, 1
say(a)
while b < 50:
    say(b)
    a, b = b, a+b

Everything below the line in the middle of the code is pretty much the same, except we use say() instead of print. We defined say() in the first part of our code.

As part of our original challenge, we offered an alternate challenge, for those who are more visual:

Fibocairo


We will be using pycairo. We will visualize the Fibonacci numbers, but without using actual numbers. We will draw big dots instead.

There is some basic setup to do before we can use it to, say, draw a line, or save an image. We wont go into all the details, there are some good tutorials on the pycairo site. But just to get an idea here is an excerpt:

import cairo

WIDTH = 350
HEIGHT = 450

surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)  
ctx = cairo.Context(surface)  
ctx.set_line_width(DOTSIZE)  
ctx.set_source_rgb(1, 0, 0) # red  

We create a surface (which we will later save as a PNG) that is 350 by 450 (we use constants to define those, ALLCAPS is the standard for constants in Python) then create a context from that surface. We could scale it, as is demoed in the tutorial on the pycairo site, but we will stay with pixels for right now so we dont make things more complicated than they need to be.

We will replace our say() function from our previous example, by a new one, which we will call drawdots().

DOTSIZE = 3


def drawdots(ctx, qty):  
    """ generate a vertical sequence of qty number of dots """  
    ctx.save() # save our position before doing anything  
    ctx.set_line_width(DOTSIZE)  
    ctx.set_source_rgb(1, 0, 0) # RED color  
    for _ in xrange(qty):  
        ctx.rectangle(-DOTSIZE, -DOTSIZE, DOTSIZE, DOTSIZE)  
        ctx.stroke()  
        ctx.translate(0, DOTSIZE * 4) # move down 4 times dotsize  
    ctx.restore() # restore our position  

We are passing the context to this function, so we can do stuff to it. First, we save it (so we can restore it at the end). We set the line width to 3 and the color to red (1,0,0 in RGB). We are ready to do the work, we will loop for the Fibonacci number that is passed (qty).

Note: we didn't do a for i in xrange() because we don't need an actual value. The "standard" way to discard a variable in a loop like this is to use the underscore (_). It keeps pylint happy instead of complaining about a variable that is defined, but not used. It is as if I was saying for whatever in xrange(). Just like in the spoken language when somebody replies "whatever!", it implies whatever, i don't care. The same applies here.

Inside the loop, I am preparing a small rectangle (a square, really), painting it and moving down on my surface with ctx.translate().

Let us now move on to the last part, the main loop we have covered several times by now:

   a, b = 0, 1  
   ctx.translate(30, 30) # for item 0, skip over some space  
   while b < 50:  
     ctx.translate(30, 0)  
     drawdots(ctx, b)  
     a, b = b, a + b  

All that we have changed is that instead of printing, we translate (move) and drawdots.

Putting it all together (save as fibocairo.py):

#!/usr/bin/env python
""" Representing Fibonacci numbers visually, as big dots """

import cairo

# hardwired limit
LIMIT = 50
DOTSIZE = 3
# These work for the current limits.
# You will need to adjust these if the above are changed.
# It is not linear and depend in both x and y on Fibonacci numbers.
WIDTH = 350
HEIGHT = 450


def drawdots(ctx, qty):
    """ generate a vertical sequence of qty number of dots """
    ctx.save() # save our position before doing anything
    ctx.set_line_width(DOTSIZE)
    ctx.set_source_rgb(1, 0, 0) # RED color
    for _ in xrange(qty):
        ctx.rectangle(-DOTSIZE, -DOTSIZE, DOTSIZE, DOTSIZE)
        ctx.stroke()
        ctx.translate(0, DOTSIZE * 4) # move down 4 times dotsize
    ctx.restore() # restore our position


def main():
    """ our main loop to generate a PNG file with a """
    # here, we are just setting up cairo
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
    ctx = cairo.Context(surface)

    # where the actual work is done
    a, b = 0, 1
    ctx.translate(30, 30) # for item 0, skip over some space
    while b < 50:
        ctx.translate(30, 0)
        drawdots(ctx, b)
        a, b = b, a + b

    surface.write_to_png('fibocairo.png') # done, write to png
 
if __name__ == "__main__":
    main()

The line:
   surface.write_to_png('fibocairo.png') # done, write to png

is where we save the surface to a png file. There are other formats supported by pycairo.

Visual?


I did say it would be visual, didn't I. The last line of the main() function saves the surface to fibocairo.png, and this is how it looks:




Perhaps it is not as impressive as the code looks...

Fibotangle


So let us try drawing rectangles that we will rotate around a point, as a visual representation. Perhaps this will look a little bit more interesting...

Instead of a drawdots() function we will write a draw(). We are not drawing dots, nor any other typical shape here, so we'll just leave it a generic draw().

 def draw(ctx, fibo):  
   """ a rotational shape based on fibo number of rectangles """  
   for i in xrange(fibo):  
     ctx.save()  
     ctx.rotate(i * 2 * math.pi / fibo)  
     ctx.rectangle(-20, -50, 20, 50)  
     ctx.stroke()  
     ctx.restore()  

The main loop that we've covered in the past few examples does have to change now. The shapes are much bigger and we need to start a new line everytime we've drawn 5 shapes.

 
   # where the actual work is done  
   a, b = 0, 1  
   ctx.translate(0, 120)  
   ctx.save()  
   ctx.translate(120, 0) # for item 0, skip over some space  
   count = 0  
   while b < 50:  
     count += 1  
     if count == 5:  
       ctx.restore()  
       ctx.translate(0, 120)  
       ctx.save()  
       count = 0  
     ctx.translate(120, 0)  
     draw(ctx, b)  
     a, b = b, a + b  

We've added a counter, we increment it in the loop. We could have used a modulo instead of a counter and comparison to 5, but the logic would have been more obtuse. We will cover an example of that in the future, however.

Putting it all together, we get (save to fibotangle.py):

 #!/usr/bin/env python  
 """ Representing Fibonacci numbers visually, as rotated rectangles """  
   
 import cairo  
 import math  
   
 # hardwired limit  
 LIMIT = 50  
   
 WIDTH = 720  
 HEIGHT = 320  
   
   
 def draw(ctx, fibo):  
   """ a rotational shape based on fibo number of rectangles """  
   for i in xrange(fibo):  
     ctx.save()  
     ctx.rotate(i * 2 * math.pi / fibo)  
     ctx.rectangle(-20, -50, 20, 50)  
     ctx.stroke()  
     ctx.restore()  
   
   
 def main():  
   """ our main loop to generate a PNG file with a """  
   # here, we are just setting up cairo  
   surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)  
   ctx = cairo.Context(surface)  
   ctx.set_line_width(3)  
   
   # where the actual work is done  
   a, b = 0, 1  
   ctx.translate(0, 120)  
   ctx.save()  
   ctx.translate(120, 0) # for item 0, skip over some space  
   count = 0  
   while b < 50:  
     count += 1  
     if count == 5:  
       ctx.restore()  
       ctx.translate(0, 120)  
       ctx.save()  
       count = 0  
     ctx.translate(120, 0)  
     draw(ctx, b)  
     a, b = b, a + b  
   
   surface.write_to_png('fibotangles.png') # done, write to png  
   
 if __name__ == "__main__":  
   main()  

And what does it look like?


This is way more interesting. The complexity level just adds something that is much more satisfying to the eye, than just a series of dots, or numbers.

Showing this around, I usually get a comment that the last three look like flowers, perhaps a rose, a daisy and a sunflower. Interestingly, many daisies and sunflowers have 34 petals (our last shape) and 55, 89 and 144 are all possible counts of florets on a sunflower, all Fibonacci numbers. It is a fact that many flowers have a number of petals from the Fibonacci sequence. It is not a coincidence, it is tied to the golden angle, spirals and phyllotaxis.

Anyway, just mentioning this as an interesting anecdote, as the answer to where you can find the Fibonacci numbers around us (question #2 of the original challenge), and to introduce our next math concept. There is math all around us in nature.

It is in the title


When I concluded the first article on Fibonacci numbers, I had a section with this title:
Bucolic Mix

And we were talking (literally) about Fibonacci numbers. Bucolic Mix was one remix that Moby did of a Brian Eno song. One reader thought I was perhaps making a reference to Moby's 257 zero song (using recordings from numbers stations - that's a story for another post).

Good guess, but I was simply making a reference to the title of that Brian Eno song:

Fractal Zoom (Bucholic Mix)

Yes, we are about to talk about Fractals. Order in chaos, you know: On fractals (next article)

No comments:

Post a Comment