In [1]:
%pylab

import csv
import pandas as pd

from scipy.interpolate import SmoothBivariateSpline
from scipy.optimize import minimize
from mpl_toolkits.mplot3d import Axes3D


Using matplotlib backend: Qt4Agg
Populating the interactive namespace from numpy and matplotlib

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=3,ky=3,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=3,ky=3,s=s).ev(xTest,yTest)
    negFitReturn = SmoothBivariateSpline(adjXData,adjYData,negAdjZData,kx=3,ky=3,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.25
gapThreshold = 130

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]:
array([  3,   6,  14,  16,  18,  19,  20,  22,  32,  33,  34,  38,  41,
        43,  57,  58,  70,  73,  82,  83, 104, 106, 109, 112])

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

In [10]:
circleDiameter


Out[10]:
array([ 4.,  8.,  9.,  7.,  6.,  5.,  3.])

In [11]:
scatter(circleDiameter,circleFactor)


Out[11]:
<matplotlib.collections.PathCollection at 0x9ca9da0>

In [12]:
scatter(width,ratio)
title('Data so far')
xlabel('Width (cm)')
ylabel('Ratio')


Out[12]:
<matplotlib.text.Text at 0x9c8be10>

In [13]:
# Spline fitting

extendedWidth = np.append(width,length)
extendedLength = np.append(length,width)
extendedFactor = np.append(factor,factor)

splineFit = SmoothBivariateSpline(extendedWidth,extendedLength,extendedFactor,kx=3,ky=3,s=len(width))

In [14]:
# Create surface mesh
xVec2 = linspace(width.min(),length.max(),100)
yVec2 = xVec2
xMesh2, yMesh2 = meshgrid(xVec2, yVec2)

gapMesh2 = angle_gap(xMesh2,yMesh2,extendedWidth,extendedLength,1,1)
giveMesh2 = fit_give(xMesh2,yMesh2,extendedWidth,extendedLength,extendedFactor,s=len(width))

zMesh2 = splineFit.ev(xMesh2, yMesh2)

ref2 = (gapMesh2>gapThreshold) | (giveMesh2>giveThreshold)
zMesh2[ref2] = nan

In [15]:
# 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()],[width.min(),width.min()],[bot,bot],'r-',alpha=0.3)
proxyGive, = ax.plot([width.min(),width.min()],[width.min(),width.min()],[bot,bot],'g-',alpha=0.3)

ax.plot_surface(xMesh2,yMesh2,zMesh2,alpha=0.3,rstride=4,cstride=4)
sc = ax.scatter(width,length,factor)

ax.set_title('Fit displayed against width and aspect ratio')
ax.set_xlabel('Width')
ax.set_ylabel('Length')
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 [16]:
# 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 = length[i]

    adjWidth = np.delete(width,i)
    adjLength = np.delete(length,i)
    adjFactor = np.delete(factor,i)

    
    adjExtendedWidth = np.append(adjWidth,adjLength)
    adjExtendedLength = np.append(adjLength,adjWidth)
    adjExtendedFactor = np.append(adjFactor,adjFactor)
    
    adjSplineFit = SmoothBivariateSpline(adjExtendedWidth,adjExtendedLength,adjExtendedFactor,kx=3,ky=3,s=len(width))
    
    predictedFactor[i] = adjSplineFit.ev(x,y)
    predictionAngleGap[i] = angle_gap(x,y,adjExtendedWidth,adjExtendedLength,1,1)
    predictionFitGive[i] = fit_give(x,y,adjExtendedWidth,adjExtendedLength,adjExtendedFactor,s=len(width))
    
difference = factor - predictedFactor
withinThresholds = ((predictionAngleGap<gapThreshold) & 
                    (predictionFitGive<giveThreshold)
                    )

In [17]:
# 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[17]:
Reference width length factor Predicted Factor Difference Angle Gap Fit Give Within thresholds
0 3 4.498726 6.077114 1.032704 1.030048 0.002656 51.461439 0.069369 1
1 6 6.996235 10.669437 1.001302 0.996180 0.005122 95.966617 0.187965 1
2 14 4.388701 5.288022 1.043027 1.036804 0.006223 52.829822 0.066603 1
3 16 6.107799 10.515871 0.999567 1.002836 -0.003269 92.022289 0.128917 1
4 18 7.602645 10.075798 0.998054 0.993992 0.004063 117.627621 0.128029 1
5 19 5.799849 10.375006 1.001089 1.005332 -0.004244 82.365561 0.120762 1
6 20 4.289047 5.112375 1.037967 1.040530 -0.002563 52.091438 0.066564 1
7 22 5.178076 10.260920 1.011713 1.011028 0.000685 74.092625 0.151667 1
8 32 7.715225 11.165712 0.993330 0.998602 -0.005272 195.358093 0.662580 0
9 33 5.905678 6.209543 1.006789 1.014063 -0.007274 34.548345 0.065907 1
10 34 7.044718 9.674088 0.993330 0.996766 -0.003435 54.775780 0.090477 1
11 38 4.677451 5.724189 1.027190 1.030530 -0.003340 48.171075 0.067928 1
12 41 6.919052 10.011766 0.994829 0.997451 -0.002623 50.044736 0.102311 1
13 43 6.100202 7.735733 1.007783 1.003766 0.004016 28.903904 0.054930 1
14 57 3.574667 4.618824 1.059704 1.053716 0.005988 104.011875 0.119906 1
15 58 5.880419 7.454923 1.008999 1.006675 0.002325 34.506800 0.056605 1
16 70 7.461006 8.363232 0.997190 0.994766 0.002425 62.339140 0.085302 1
17 73 7.294143 9.137754 0.995472 0.995212 0.000261 76.411926 0.089547 1
18 82 6.268781 7.974677 1.000867 1.002230 -0.001363 28.024225 0.055379 1
19 83 5.782263 7.931109 1.010552 1.006076 0.004476 29.433462 0.063083 1
20 104 5.658933 8.328343 1.006601 1.006860 -0.000259 31.042310 0.074283 1
21 106 6.087204 9.708158 1.000871 1.002277 -0.001406 41.939250 0.092832 1
22 109 6.306754 7.827168 1.006979 1.001819 0.005160 28.094473 0.053290 1
23 112 3.538729 4.149551 1.053904 1.059781 -0.005878 122.537399 0.110579 1
24 NaN 4.000000 4.000000 1.045826 1.056066 -0.010240 62.963508 0.073175 1
25 NaN 8.000000 8.000000 0.993360 0.994497 -0.001136 50.140271 0.099087 1
26 NaN 9.000000 9.000000 0.991661 0.992499 -0.000838 151.355774 0.357004 0
27 NaN 7.000000 7.000000 0.996776 1.001437 -0.004661 26.315944 0.047837 1
28 NaN 6.000000 6.000000 1.014436 1.013924 0.000512 30.963757 0.067341 1
29 NaN 5.000000 5.000000 1.030396 1.033089 -0.002693 19.440035 0.064384 1
30 NaN 3.000000 3.000000 1.075771 1.061178 0.014593 270.000000 0.823710 0
31 NaN 4.000000 10.000000 1.029933 1.029542 0.000391 116.565051 0.250079 0
32 NaN 4.000000 8.000000 1.030055 1.032026 -0.001971 101.309932 0.112994 1
33 NaN 4.000000 6.500000 1.040668 1.035902 0.004766 68.198591 0.086731 1
34 NaN 5.000000 10.000000 1.012277 1.013657 -0.001380 56.309932 0.159688 1
35 NaN 3.000000 13.000000 1.049271 1.040177 0.009094 270.000000 0.958982 0
36 NaN 3.000000 5.000000 1.069714 1.059151 0.010563 180.000000 0.329955 0
37 NaN 5.000000 13.000000 1.013374 1.005635 0.007739 214.041258 0.690821 0
38 NaN 3.000000 9.000000 1.053516 1.054706 -0.001190 180.000000 0.710871 0
39 NaN 3.000000 6.500000 1.054423 1.058700 -0.004277 180.000000 0.312802 0
40 NaN 4.000000 13.000000 1.024896 1.028091 -0.003195 180.000000 0.603961 0
41 NaN 5.000000 8.000000 1.017153 1.015118 0.002036 36.869898 0.080694 1

In [18]:
print("There are", sum(withinThresholds), "points within give and gap thresholds."+
      "\nThe standard deviation of the prediction differences for these is", std(difference[withinThresholds]))


There are 32 points within give and gap thresholds.
The standard deviation of the prediction differences for these is 0.00403869252897

In [19]:
# 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[19]:
<matplotlib.text.Text at 0xa49f1d0>

In [20]:
# 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,length,factor,c=diffColour, vmin=-colourRange, vmax=colourRange,s=50)
colorbar(sc)

ax.set_title('Differences')
ax.set_xlabel('Width')
ax.set_ylabel('Length')
ax.set_zlabel('Factor')

# ax.set_ylim(right,1)
ax.set_zlim(bot,top)

ax.view_init(elev=10, azim=-80)

In [21]:
diffTest = abs(difference)
diffTest[~withinThresholds] = 0

testRef = argmax(diffTest)
cutoutRef[testRef]


Out[21]:
nan

In [22]:
factor[testRef]


Out[22]:
1.0458259008956201

In [23]:
scatter(width,length)
scatter(width[testRef],length[testRef],c='red')


Out[23]:
<mpl_toolkits.mplot3d.art3d.Patch3DCollection at 0xa588f60>

In [24]:
def to_minimise(cut_increase,ref):
    
    test_width = width[ref] + cut_increase
    test_length = length[ref] + cut_increase
    test_ratio = test_width / test_length
    
    return (factor[ref] - splineFit.ev(test_width,test_length))

In [25]:
output = minimize(to_minimise,0,args=(testRef,))
output


Out[25]:
      fun: -0.028534658212009623
 hess_inv: array([[1]])
     njev: 5
  message: 'Optimization terminated successfully.'
      jac: array([ 0.])
     nfev: 15
  success: True
   status: 0
        x: array([-1.09765455])

In [ ]: