In [1]:
%pylab inline
import csv
import pandas as pd
from scipy.interpolate import SmoothBivariateSpline
from scipy.optimize import minimize
from mpl_toolkits.mplot3d import Axes3D
In [2]:
def single_angle_gap(xTest,yTest,xData,yData,xScale,yScale):
xi = xScale * (xData - xData.min()) / xData.ptp()
yi = yScale * (yData - yData.min()) / yData.ptp()
xVal = xScale * (xTest - xData.min()) / xData.ptp()
yVal = yScale * (yTest - yData.min()) / yData.ptp()
dx = xi - xVal
dy = yi - yVal
if any((dx == 0) & (dy == 0)):
gap = 0
return gap
theta = np.arctan(dy/dx)
theta[dx<0] = theta[dx<0] + np.pi
theta[(dx>0) & (dy<0)] = theta[(dx>0) & (dy<0)] + 2*np.pi
theta[(dx==0) & (dy>0)] = np.pi/2
theta[(dx==0) & (dy<0)] = 3*np.pi/2
test = np.sort(theta)
test = np.append(test,test[0] + 2*np.pi)
gap = np.max(np.diff(test))*180/np.pi
return gap
def angle_gap(xTest,yTest,xData,yData,xScale,yScale):
dim = np.core.fromnumeric.shape(xTest)
if np.size(dim) == 0:
gap = single_angle_gap(xTest,yTest,xData,yData,xScale,yScale)
return gap
gap = np.zeros(dim)
if np.size(dim) == 1:
for i in range(dim[0]):
gap[i] = single_angle_gap(xTest[i],yTest[i],xData,yData,xScale,yScale)
return gap
for i in range(dim[0]):
for j in range (dim[1]):
gap[i,j] = single_angle_gap(xTest[i,j],yTest[i,j],xData,yData,xScale,yScale)
return gap
In [3]:
def single_fit_give(xTest,yTest,xData,yData,zData,s=None):
initialFitReturn = SmoothBivariateSpline(xData,yData,zData,kx=2,ky=2,s=s).ev(xTest,yTest)
adjXData = np.append(xData,xTest)
adjYData = np.append(yData,yTest)
posAdjZData = np.append(zData,initialFitReturn + 1)
negAdjZData = np.append(zData,initialFitReturn - 1)
posFitReturn = SmoothBivariateSpline(adjXData,adjYData,posAdjZData,kx=2,ky=2,s=s).ev(xTest,yTest)
negFitReturn = SmoothBivariateSpline(adjXData,adjYData,negAdjZData,kx=2,ky=2,s=s).ev(xTest,yTest)
posGive = posFitReturn - initialFitReturn
negGive = initialFitReturn - negFitReturn
give = np.mean([posGive, negGive])
return give
def fit_give(xTest,yTest,xData,yData,zData,s=None):
dim = np.core.fromnumeric.shape(xTest)
if np.size(dim) == 0:
give = single_fit_give(xTest,yTest,xData,yData,zData,s=s)
return give
give = np.zeros(dim)
if np.size(dim) == 1:
for i in range(dim[0]):
give[i] = single_fit_give(xTest[i],yTest[i],xData,yData,zData,s=s)
return give
for i in range(dim[0]):
for j in range (dim[1]):
give[i,j] = single_fit_give(xTest[i,j],yTest[i,j],xData,yData,zData,s=s)
return give
In [4]:
pylab.rcParams['savefig.dpi'] = 130
In [5]:
# Define thresholds
giveThreshold = 0.5
gapThreshold = 180
In [6]:
with open('cutout_factors','r') as f:
loaded_factor = eval(f.read())
dictArray = array(list(loaded_factor.items()),float)
cutoutRef = dictArray[:,0].astype(int)
ref = argsort(cutoutRef)
factor = dictArray[:,1]
cutoutRef = cutoutRef[ref]
factor = factor[ref]
with open('circle_cutout_factors','r') as f:
loaded_circle_factor = eval(f.read())
circleDictArray = array(list(loaded_circle_factor.items()),float)
circleDiameter = circleDictArray[:,0]
circleFactor = circleDictArray[:,1]
factor = append(factor,circleFactor)
with open('custom_cutout_factors','r') as f:
loaded_custom_factor = eval(f.read())
customDimensionsDict = {'5x13':[5,13],
'5x10':[5,10],
'5x8':[5,8],
'4x13':[4,13],
'4x10':[4,10],
'4x8':[4,8],
'4x6.5':[4,6.5],
'3x13':[3,13],
'3x9':[3,9],
'3x6.5':[3,6.5],
'3x5':[3,5]}
customDataLabelList = list(customDimensionsDict.keys())
custom_factors = [loaded_custom_factor[x] for x in customDataLabelList]
custom_widths = [customDimensionsDict[x][0] for x in customDataLabelList]
custom_lengths = [customDimensionsDict[x][1] for x in customDataLabelList]
factor = append(factor,custom_factors)
In [7]:
# loaded_factor.items()
In [8]:
cutoutRef
Out[8]:
In [8]:
In [9]:
cutout_dimensions = pd.DataFrame.from_csv('new_cutoutdata.csv',index_col =None)
ref = argsort(cutout_dimensions['cutoutRef'].values.astype(int))
width = cutout_dimensions['new_width'].values[ref]
length = cutout_dimensions['new_length'].values[ref]
weight = concatenate((ones(shape(width)), 1*ones(shape(circleDiameter)), ones(shape(custom_widths))))
width = append(width,circleDiameter)
length = append(length,circleDiameter)
nanFill = empty(shape(circleDiameter))
nanFill.fill(nan)
cutoutRef = append(cutoutRef,nanFill)
width = append(width,custom_widths)
length = append(length,custom_lengths)
nanFill = empty(shape(custom_widths))
nanFill.fill(nan)
cutoutRef = append(cutoutRef,nanFill)
# editRef = cutoutRef == 14
# width[editRef] = 4.3
# length[editRef] = 4.6
ratio = width / length
# PonA = 2 * (ratio + 1) / width
R = ratio
PonA = 2*( 3*(R+1) - sqrt( (3*R+1)*(R+3) ) ) / width
In [10]:
circleDiameter
Out[10]:
In [11]:
scatter(circleDiameter,circleFactor)
Out[11]:
In [12]:
scatter(width,PonA)
title('Data so far')
xlabel('Width (cm)')
ylabel('PonA')
Out[12]:
In [13]:
PonA
Out[13]:
In [14]:
# Spline fitting
splineFit = SmoothBivariateSpline(width,PonA,factor,kx=2,ky=2)
In [15]:
# Create surface mesh
xVec2 = linspace(width.min(),width.max(),100)
yVec2 = linspace(PonA.min(),PonA.max(),100)
xMesh2, yMesh2 = meshgrid(xVec2, yVec2)
gapMesh2 = angle_gap(xMesh2,yMesh2,width,PonA,1,1)
giveMesh2 = fit_give(xMesh2,yMesh2,width,PonA,factor)
zMesh2 = splineFit.ev(xMesh2, yMesh2)
ref2 = (gapMesh2>gapThreshold) | (giveMesh2>giveThreshold)
zMesh2[ref2] = nan
In [16]:
# Plot the fit
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
bot = np.amin(factor) - 0.04 * np.ptp(factor)
top = np.amax(factor) + 0.04 * np.ptp(factor)
ax.contour(xMesh2,yMesh2,gapMesh2, offset=bot, levels=[gapThreshold], colors='r',alpha=0.3)
ax.contour(xMesh2,yMesh2,giveMesh2, offset=bot, levels=[giveThreshold], colors='g',alpha=0.3)
proxyGap, = ax.plot([width.min(),width.min()],[PonA.min(),PonA.min()],[bot,bot],'r-',alpha=0.3)
proxyGive, = ax.plot([width.min(),width.min()],[PonA.min(),PonA.min()],[bot,bot],'g-',alpha=0.3)
ax.plot_surface(xMesh2,yMesh2,zMesh2,alpha=0.3,rstride=4,cstride=4)
sc = ax.scatter(width,PonA,factor)
ax.set_title('Fit displayed against width and aspect ratio')
ax.set_xlabel('Width')
ax.set_ylabel('PonA')
ax.set_zlabel('Factor')
legend([proxyGap,proxyGive],['Gap threshold', 'Give threshold'],loc=7,prop={'size':8})
# right = ratio.min()-0.01*ratio.ptp()
# ax.set_ylim(right,1)
ax.set_zlim(bot,top)
ax.view_init(elev=10, azim=-80)
In [17]:
# Remove data and predict
predictedFactor = zeros(shape(width))
predictionAngleGap = zeros(shape(width))
predictionFitGive = zeros(shape(width))
for i in range(len(width)):
x = width[i]
y = PonA[i]
adjWidth = np.delete(width,i)
adjPonA = np.delete(PonA,i)
adjFactor = np.delete(factor,i)
adjSplineFit = SmoothBivariateSpline(adjWidth,adjPonA,adjFactor,kx=2,ky=2)
predictedFactor[i] = adjSplineFit.ev(x,y)
predictionAngleGap[i] = angle_gap(x,y,adjWidth,adjPonA,1,1)
predictionFitGive[i] = fit_give(x,y,adjWidth,adjPonA,adjFactor)
difference = factor - predictedFactor
withinThresholds = ((predictionAngleGap<gapThreshold) &
(predictionFitGive<giveThreshold)
)
In [18]:
# Display table
df = pd.DataFrame(transpose([cutoutRef,width, length, factor, predictedFactor, difference,
predictionAngleGap, predictionFitGive, withinThresholds]))
df.columns = ['Reference','width', 'length', 'factor', 'Predicted Factor', 'Difference',
'Angle Gap', 'Fit Give', 'Within thresholds']
# df.to_csv(path_or_buf = "cutoutdata.csv", index=False)
df
Out[18]:
In [19]:
print("There are", sum(withinThresholds), "points within give and gap thresholds."+
"\nThe standard deviation of the prediction differences for these is", std(difference[withinThresholds]))
In [20]:
# Histogram
fig = plt.figure()
ax = fig.add_subplot(111)
n, bins, patches = hist(difference[withinThresholds])
setp(patches, 'facecolor', 'g', 'alpha', 0.5)
ax.set_xlabel('Prediction differences')
ax.set_ylabel('Frequency')
ax.set_title('Histogram of prediction differences')
Out[20]:
In [21]:
# Visual representation of differences
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(xMesh2,yMesh2,zMesh2,alpha=0.3,rstride=4,cstride=4)
diffColour = copy(difference)
diffColour[~withinThresholds] = nan
colourRange = nanmax(abs(diffColour))
sc = ax.scatter(width,PonA,factor,c=diffColour, vmin=-colourRange, vmax=colourRange,s=50)
colorbar(sc)
ax.set_title('Differences')
ax.set_xlabel('Width')
ax.set_ylabel('PonA')
ax.set_zlabel('Factor')
# ax.set_ylim(right,1)
ax.set_zlim(bot,top)
ax.view_init(elev=10, azim=-80)
In [22]:
diffTest = abs(difference)
diffTest[~withinThresholds] = 0
testRef = argmax(diffTest)
cutoutRef[testRef]
Out[22]:
In [23]:
factor[testRef]
Out[23]:
In [24]:
scatter(width,PonA)
scatter(width[testRef],PonA[testRef],c='red')
Out[24]:
In [25]:
def to_minimise(cut_increase,ref):
test_width = width[ref] + cut_increase
test_PonA = PonA[ref] + cut_increase
return (factor[ref] - splineFit.ev(test_width,test_PonA))
In [26]:
output = minimize(to_minimise,0,args=(testRef,))
output
Out[26]:
In [26]: