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