Python language and Fibonacci

Spending a bit of time familiarising myself with the Python language. The mathematics libraries are quite amazing. Bit of a change after PHP and Powershell etc. The first use of it was to use beautiful soup to read in some data from a web site (scraping it into a format that was useful) and “rearrange” it onto a world map (http://www.jetsoft.net.au/gps_distance/). The GPS mapping functions are quite complete and all the choices of projections and map data are very interesting.

Once I had that working I got interested on the mathematical and plotting functions.

I then wrote something to draw fibonacci “spirals”, the interpolation library (spline) does a lot of the heavy lifting. I joined the centres rather than the corners, dont know if that makes much difference but was more interested in the “shape” than the detail. It also shows the ratio of the most recent two terms in a plot to the right of the spiral. You can see how quickly it converges.

import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection
import matplotlib as mpl
import numpy as np
from scipy.interpolate import spline 
import numpy as np
import time
		
plt.ion()
class DynamicUpdate():
	min_xy = 0
	max_xy = 0
	numpoly= 30
	square = [ [ 1,1 ] , [ 1,  0 ], [ 0 , 0 ] , [ 0 , 1 ] ]
	edges = {
	0: "T",
	1: "R",
	2: "B",
	3: "L",
	}
	

	def on_launch(self):
		#Set up plot
		self.figure=plt.figure()
		self.ax = plt.subplot2grid( (1,4),(0,0), colspan=3)
		self.ax1 = plt.subplot2grid( (1,4),(0,3) )
		self.ax.set_autoscaley_on(True)
		self.ax1.set_autoscaley_on(True)
		self.ax.grid()

	def on_running(self, sqs,  z  , cpx, cpy, cpsizes, cpratios ):
		#coll = PolyCollection( sqs, array=z, cmap=mpl.cm.jet, edgecolors='k')
		#del self.ax.collections[:]
		self.ax.clear()
		self.ax.set_title('Fibonacci sequence,' + str(len(sqs)) +' terms, centre points joined. ' + str( cpsizes[ len(sqs)-1]) )
		self.ax1.clear()
		self.ax1.set_title('Ratio ' + str(cpratios[len(sqs)-1]) )
		# add all the sqs as a collection of polynomials
		coll = PolyCollection( sqs , array=z, cmap=mpl.cm.jet, edgecolors='k' , alpha=0.5)
		self.ax.add_collection(coll)
		# plot the centre points of each square and join with a line
		self.ax.plot(cpx, cpy, '-o' )
		# Now add a smoothed (spline) to the plot. 
		n=range(0,len(sqs))
		if ( len(sqs) > 3 ) :
			nn=np.linspace(0,len(sqs)-1,20*len(sqs))
			nx=spline(n,cpx,nn)
			ny=spline(n,cpy,nn)
			self.ax.plot(nx,ny,'x')

		# force tp be a square, and make 0,0 always central
		self.ax.relim()
		self.ax.autoscale_view()
		self.ax.set( adjustable='box-forced', aspect='equal')
		newlim=max(abs(self.min_xy), self.max_xy)
		self.ax.set_xlim(-newlim, newlim)
		self.ax.set_ylim(-newlim, newlim)

		self.ax1.plot(cpratios,n, 'o' )
		self.ax1.set_ylim( 0, self.numpoly )
		
		plt.tight_layout()
		self.figure.canvas.draw()
		self.figure.canvas.flush_events()

	#create sqs
	def __call__(self):
		z=np.array([])
		cpx=[]
		cpy=[]
		cpsizes=[]
		cpratios=[]
		color_ratio=250/self.numpoly
		sqs=[]
		self.on_launch()
		tnm2=1
		tnm1=0
		#want the first one to be at 1,0, next one to left, imaginary 0 size block at 2,1 but have to have "forced" 1 size block to start it off
		posx= .5
		posy = .5
		edge=1
		for j in np.arange(0,self.numpoly,1):
			size=tnm2+tnm1
			edge=(edge+1) % 4
			myedge = self.edges.get(edge)
			# need to work out position depending on which edge we should be on (T, R, B , L )
			if myedge == 'T':
				# if on top then x is same corner and y is previous Y plus size 
				posx=posx
				posy=posy+tnm1
			elif myedge == 'R':
				#if on right x is previous x plus size, y is previous y minus size1 plust size 2?
				posx=posx+tnm1
				posy=posy-tnm2
			elif myedge == 'B':
				# if at bottom x is prev minus size previous
				posx=posx-tnm2
				posy=posy-size
			elif myedge == 'L':
				posx=posx-size
				posy=posy
			else:
				print 'Invalid Edge'
				posx=posx+size
				posy=posy+size
			tnm2=tnm1
			tnm1=size
			nsq=np.zeros( (4,2) )
			nsq=nsq  + self.square
			nsq = nsq * size 
			nsq =  ( nsq )  + [ posx, posy]
			sqs.append(nsq)
			# z is color
			z=np.append( z, float ( (250 * ( ( j-1)%2 ) ) + j*color_ratio) )
			# store centre points of each square
			cpx.append( posx+size/2.0 )
			cpy.append( posy+size/2.0 ) 
			cpsizes.append( size )
			myratio=1
			if ( tnm2 > 0 ) : 
				myratio=float(tnm1)  / float(tnm2)
			cpratios.append(  myratio)
			print "count, size, posx, posy",j, size, posx, posy
			self.min_xy = min(min(self.min_xy,posx),posy)
			self.max_xy=max(max(self.max_xy,abs(posx+size)),abs(posy+size))
			
			self.on_running( sqs, z , cpx, cpy , cpsizes, cpratios )
			time.sleep(1)
		return sqs

d = DynamicUpdate()
d()

the output looks like this (and doesn’t change a lot no matter how much you zoom in).

fibanim16

About Jeff Turner

Technical director of Nano Tera Network Solutions.
This entry was posted in Uncategorized. Bookmark the permalink.