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).