def __init__(self, parent): LabelFrame.__init__(self, parent, text="Results", width=825, height=485) # Terrible kludgy hack to force the app to stay the right size # Need to work out how to remove self.grid_propagate(False) self.resultsDict = None self.modelType = None self.currentSegment = 0 # Stats frame self.statsFrame = StatsFrame(self, self.padX, self.padY) self.statsFrame.calculate_B.bind("<Button-1>", self._parametersChanged) self.statsFrame.reset_B.bind("<Button-1>", self._parametersReset) def onComboBoxSelect(e): self.currentSegment = e.widget.current() self._updateDisplay(True) self.statsFrame.expSeg_CB.bind("<<ComboboxSelected>>", onComboBoxSelect) # Error frame self.errorSurfaceFrame = ErrorSurfaceFrame(self) self.errorSurfaceFrame.errorSurfaceB.bind("<Button-1>", self._displayErrorSurface) # Graph notebook self.errorSurfaceSeperator = Separator(self, orient=tkinter.HORIZONTAL) self.graphNotebook = ImprovedNotebook(self) self.modelGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.modelGraphFrame.axes.set_ylabel(r'$thickness(m)$') self.regressionGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.regressionGraphFrame.axes.set_ylabel(r'$\log{(thickness(m))}$') self.errorSurfaceGraphFrame = GraphFrame(self.graphNotebook, dim=3) self.errorSurfaceGraphFrame.axes.set_zlabel(r'$error$') self.graphNotebook.addFrame(self.modelGraphFrame, text="Model")
def __init__(self,parent): LabelFrame.__init__(self, parent,text="Results", width=825, height=485) # Terrible kludgy hack to force the app to stay the right size # Need to work out how to remove self.grid_propagate(False) self.resultsDict = None self.modelType = None self.currentSegment = 0 # Stats frame self.statsFrame = StatsFrame(self, self.padX, self.padY) self.statsFrame.calculate_B.bind("<Button-1>", self._parametersChanged) self.statsFrame.reset_B.bind("<Button-1>", self._parametersReset) def onComboBoxSelect(e): self.currentSegment = e.widget.current() self._updateDisplay(True) self.statsFrame.expSeg_CB.bind("<<ComboboxSelected>>", onComboBoxSelect) # Error frame self.errorSurfaceFrame = ErrorSurfaceFrame(self) self.errorSurfaceFrame.errorSurfaceB.bind("<Button-1>", self._displayErrorSurface) # Graph notebook self.errorSurfaceSeperator = Separator(self,orient=tkinter.HORIZONTAL) self.graphNotebook = ImprovedNotebook(self) self.modelGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.modelGraphFrame.axes.set_ylabel(r'$thickness(m)$') self.regressionGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.regressionGraphFrame.axes.set_ylabel(r'$\ln{(thickness(m))}$') self.errorSurfaceGraphFrame = GraphFrame(self.graphNotebook, dim=3) self.errorSurfaceGraphFrame.axes.set_zlabel(r'$error$') self.graphNotebook.addFrame(self.modelGraphFrame, text="Model")
class ResultsFrame(LabelFrame): padY = 5 padX = 30 def __init__(self,parent): LabelFrame.__init__(self, parent,text="Results", width=825, height=485) # Terrible kludgy hack to force the app to stay the right size # Need to work out how to remove self.grid_propagate(False) self.resultsDict = None self.modelType = None self.currentSegment = 0 # Stats frame self.statsFrame = StatsFrame(self, self.padX, self.padY) self.statsFrame.calculate_B.bind("<Button-1>", self._parametersChanged) self.statsFrame.reset_B.bind("<Button-1>", self._parametersReset) def onComboBoxSelect(e): self.currentSegment = e.widget.current() self._updateDisplay(True) self.statsFrame.expSeg_CB.bind("<<ComboboxSelected>>", onComboBoxSelect) # Error frame self.errorSurfaceFrame = ErrorSurfaceFrame(self) self.errorSurfaceFrame.errorSurfaceB.bind("<Button-1>", self._displayErrorSurface) # Graph notebook self.errorSurfaceSeperator = Separator(self,orient=tkinter.HORIZONTAL) self.graphNotebook = ImprovedNotebook(self) self.modelGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.modelGraphFrame.axes.set_ylabel(r'$thickness(m)$') self.regressionGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.regressionGraphFrame.axes.set_ylabel(r'$\log{(thickness(m))}$') self.errorSurfaceGraphFrame = GraphFrame(self.graphNotebook, dim=3) self.errorSurfaceGraphFrame.axes.set_zlabel(r'$error$') self.graphNotebook.addFrame(self.modelGraphFrame, text="Model") def displayNewModel(self, modelType, resultsDict): self.modelType = modelType self.isopachs = resultsDict["isopachs"] self.sqrtAreaKM = [isopach.sqrtAreaKM for isopach in self.isopachs] self.thicknessM = [isopach.thicknessM for isopach in self.isopachs] self.currentParameters = resultsDict self.defaultParameters = deepcopy(self.currentParameters) self.statsFrame.grid(row=0,column=0,padx=10,pady=5,sticky="NESW") self.graphNotebook.grid(row=0,column=1,padx=10, pady=5,sticky="NEW") if self.modelType == Model.EXP: self._displayExp() self.config(text="Results (Exponential)") else: self.errorSurfaceSeperator.grid(row=1, column=0, columnspan=2, padx=20, pady=(20,0), sticky="EW") self.errorSurfaceFrame.grid(row=2, column=0, columnspan=2, padx=10, pady=0, sticky="EW") if self.modelType == Model.POW: self._displayPow() self.config(text="Results (Power law)") elif self.modelType == Model.WEI: self._displayWei() self.config(text="Results (Weibull)") self._updateDisplay(False) def _updateDisplay(self, comboboxUpdate): if not comboboxUpdate: self.modelGraphFrame.clear() self.regressionGraphFrame.clear() thicknessM = [isopach.thicknessM for isopach in self.isopachs] sqrtArea = [isopach.sqrtAreaKM for isopach in self.isopachs] self.modelGraphFrame.plotScatter(sqrtArea,thicknessM,True) self.modelGraphFrame.axes.set_xlabel(r"$\sqrt{Area}$") if self.modelType == Model.EXP: self._updateExp(comboboxUpdate) elif self.modelType == Model.POW: self._updatePow() elif self.modelType == Model.WEI: self._updateWei() def _displayExp(self): fr = self.statsFrame padX = self.padX padY = self.padY fr.expSeg_CB.grid(row=3,column=0,sticky="W",padx=10,pady=padY) vals = ["Segment " + str(i) for i in range(1,self.currentParameters["numberOfSegments"]+1)] fr.expSeg_CB.configure(values=vals) fr.expSeg_CB.current(0) fr.expSegVolume_L.grid(row=4,column=0,padx=10,sticky="W",pady=padY) fr.expSegVolume_E.grid(row=4,column=1,padx=10,sticky="E") fr.equation_L.grid(row=5,column=0,sticky="W",padx=10,pady=padY) fr.equation_E.grid(row=5,column=1,padx=10,sticky="E") fr.equation_L.configure(text="Segment equation:") fr.parameters_L.grid(row=6,column=0,padx=10,pady=padY,sticky="W") fr.expSegStartLimit_L.grid(row=7,column=0,sticky="W",padx=padX,pady=padY) fr.expSegStartLimit_E.grid(row=7,column=1,padx=10,sticky="E") fr.expSegEndLimit_L.grid(row=8,column=0,sticky="W",padx=padX,pady=padY) fr.expSegEndLimit_E.grid(row=8,column=1,padx=10,sticky="E") fr.expSegCoefficent_L.grid(row=9,column=0,sticky="W",padx=padX,pady=padY) fr.expSegCoefficent_E.grid(row=9,column=1,padx=10,sticky="E") fr.expSegExponent_L.grid(row=10,column=0,sticky="W",padx=padX,pady=padY) fr.expSegExponent_E.grid(row=10,column=1,padx=10,sticky="E") # Recalculate buttons fr.calculate_B.grid(row=11,column=0,padx=padX,pady=padY,sticky="W") fr.reset_B.grid(row=11,column=1,padx=10,sticky="E") self.graphNotebook.addFrame(self.regressionGraphFrame, text="Regression") def _displayPow(self): fr = self.statsFrame padX = self.padX padY = self.padY fr.equation_L.grid(row=2,column=0,sticky="W",padx=10,pady=padY) fr.equation_E.grid(row=2,column=1,padx=10,sticky="E") fr.equation_L.configure(text="Equation:") fr.parameters_L.grid(row=3,column=0,padx=10,pady=padY,sticky="W") fr.powCoefficient_L.grid(row=4,column=0,sticky="W",padx=padX,pady=padY) fr.powCoefficient_E.grid(row=4,column=1,padx=10,sticky="E") fr.powExponent_L.grid(row=5,column=0,sticky="W",padx=padX,pady=padY) fr.powExponent_E.grid(row=5,column=1,padx=10,sticky="E") fr.powProximalLimit_L.grid(row=6,column=0,sticky="W",padx=padX,pady=padY) fr.powProximalLimit_E.grid(row=6,column=1,padx=10,sticky="E") fr.powDistalLimit_L.grid(row=7,column=0,sticky="W",padx=padX,pady=padY) fr.powDistalLimit_E.grid(row=7,column=1,padx=10,sticky="E") # Recalculate buttons fr.calculate_B.grid(row=8,column=0,padx=padX,pady=padY,sticky="W") fr.reset_B.grid(row=8,column=1,padx=10,sticky="E") fr.powSuggestedProximalLimit_L.grid(row=9,column=0,sticky="W",padx=10,pady=padY) fr.powSuggestedProximalLimit_E.grid(row=9,column=1,padx=10,sticky="E") self.graphNotebook.addFrame(self.regressionGraphFrame, text="Regression") self.errorSurfaceFrame.update("c", "m", 0.0, 5.0, 0.0, 5.0) def _displayWei(self): fr = self.statsFrame padX = self.padX padY = self.padY fr.equation_L.grid(row=2,column=0,sticky="W",padx=10,pady=padY) fr.equation_E.grid(row=2,column=1,padx=10,sticky="E") fr.equation_L.configure(text="Equation:") fr.parameters_L.grid(row=3,column=0,padx=10,pady=padY,sticky="W") fr.weiLambdaL.grid(row=4,column=0,padx=padX,pady=padY,sticky="W") fr.weiLambdaE.grid(row=4,column=1,padx=10,sticky="E") fr.weiKL.grid(row=5,column=0,padx=padX,pady=padY,sticky="W") fr.weiKE.grid(row=5,column=1,padx=10,sticky="E") fr.weiThetaL.grid(row=6,column=0,padx=padX,pady=padY,sticky="W") fr.weiThetaE.grid(row=6,column=1,padx=10,sticky="E") # Recalculate buttons fr.calculate_B.grid(row=7,column=0,padx=padX,pady=padY,sticky="W") fr.reset_B.grid(row=7,column=1,padx=10,sticky="E") parameterLimits = self.currentParameters["limits"] lambdaLower, lambdaUpper = parameterLimits[0] kLower, kUpper = parameterLimits[1] self.errorSurfaceFrame.update("\u03BB", "k", lambdaLower, lambdaUpper, kLower, kUpper) def _updateExp(self, comboboxUpdate): n = self.currentParameters["numberOfSegments"] coefficients = self.currentParameters["segmentCoefficients"] exponents = self.currentParameters["segmentExponents"] limits = self.currentParameters["segmentLimits"] ########### ## Stats ## ########### fr = self.statsFrame # Segment start start = limits[self.currentSegment] startStr = helper_functions.roundToSF(start, NUMBER_OF_SF) fr.expSegStartLimit_E.insertNew(start) fr.expSegStartLimit_E.setUserEditable(self.currentSegment != 0) # Segment end end = limits[self.currentSegment+1] endStr = helper_functions.roundToSF(end, NUMBER_OF_SF) fr.expSegEndLimit_E.insertNew(end) fr.expSegEndLimit_E.setUserEditable(self.currentSegment != n-1) # Segment coefficient coefficient = coefficients [self.currentSegment] coefficientStr = helper_functions.roundToSF(coefficient, NUMBER_OF_SF) fr.expSegCoefficent_E.insertNew(coefficient) # Segment exponent exponent = exponents[self.currentSegment] exponentStr = helper_functions.roundToSF(exponent, NUMBER_OF_SF) fr.expSegExponent_E.insertNew(exponent) # Segment volume segmentVolumes = [calculateExponentialSegmentVolume(coefficients[i], exponents[i], limits[i], limits[i+1]) for i in range(n)] segmentVolumeStr = helper_functions.roundToSF(segmentVolumes[self.currentSegment], NUMBER_OF_SF) fr.expSegVolume_E.insertNew(segmentVolumeStr) # Total volume totalVolume = sum(segmentVolumes) estimatedTotalVolumeStr = helper_functions.roundToSF(totalVolume, NUMBER_OF_SF) fr.totalEstimatedVolume_E.insertNew(estimatedTotalVolumeStr) # Error def thicknessFunction(x): for i in range(n): if limits[i] <= x < limits[i+1]: return coefficients[i]*math.exp(-exponents[i]*x) error = regression_methods.meanRelativeSquaredError(self.sqrtAreaKM, self.thicknessM, thicknessFunction) errorStr = helper_functions.roundToSF(error, NUMBER_OF_SF) fr.relativeSquaredError_E.insertNew(errorStr) # Equation equationStr = "T = " + coefficientStr if exponent > 0: equationStr += "exp(-" + exponentStr + "x)" elif exponent < 0: equationStr += "exp(" + exponentStr[1:] + "x)" fr.equation_E.insertNew(equationStr) ############ ## Graphs ## ############ if not comboboxUpdate: # Model endXs = limits[1:-1] + [1.5*max(self.sqrtAreaKM)-0.5*min(self.sqrtAreaKM)] for i in range(n): xs = helper_functions.getStaggeredPoints(limits[i], endXs[i], MODEL_PLOTTING_PRECISION) ys = [coefficients[i]*math.exp(-exponents[i]*x) for x in xs] self.modelGraphFrame.plotFilledLine(xs, ys, color=colours[i]) # Regression logThicknessM = [np.log(t) for t in self.thicknessM] self.regressionGraphFrame.plotScatter(self.sqrtAreaKM, logThicknessM, False) self.regressionGraphFrame.axes.set_xlabel(r"$\sqrt{Area}$") for i in range(n): xs = [limits[i], endXs[i]] ys = [np.log(thicknessFunction(x)) for x in xs] self.regressionGraphFrame.plotLine(xs,ys, color=colours[i]) def _updatePow(self): ########### ## Stats ## ########### fr = self.statsFrame # Coefficient c = self.currentParameters["coefficient"] coefficientStr = helper_functions.roundToSF(c, NUMBER_OF_SF) fr.powCoefficient_E.insertNew(c) # Exponent m = self.currentParameters["exponent"] exponentStr = helper_functions.roundToSF(m, NUMBER_OF_SF) fr.powExponent_E.insertNew(m) # Proximal limit proximalLimitKM = self.currentParameters["proximalLimitKM"] proximalLimitStr = helper_functions.roundToSF(proximalLimitKM, NUMBER_OF_SF) fr.powProximalLimit_E.insertNew(proximalLimitKM) # Distal limit distalLimitKM = self.currentParameters["distalLimitKM"] distalLimitStr = helper_functions.roundToSF(distalLimitKM, NUMBER_OF_SF) fr.powDistalLimit_E.insertNew(distalLimitKM) # Volume volume = calculatePowerLawVolume(c, m, proximalLimitKM, distalLimitKM) volumeStr = helper_functions.roundToSF(volume, NUMBER_OF_SF) fr.totalEstimatedVolume_E.insertNew(volumeStr) # Error thicknessFunction = lambda x : c*(x**(-m)) error = regression_methods.meanRelativeSquaredError(self.sqrtAreaKM, self.thicknessM, thicknessFunction) errorStr = helper_functions.roundToSF(error, NUMBER_OF_SF) fr.relativeSquaredError_E.insertNew(errorStr) # Equation equationStr = "T = " + coefficientStr if m > 0: equationStr += "x^-" + exponentStr elif m < 0: equationStr += "x^" + exponentStr[1:] fr.equation_E.insertNew(equationStr) # Suggested proximal limit suggestedProximalLimit = self.currentParameters["suggestedProximalLimit"] suggestedProximalLimitStr = helper_functions.roundToSF(suggestedProximalLimit, NUMBER_OF_SF) fr.powSuggestedProximalLimit_E.insertNew(suggestedProximalLimitStr) ############ ## Graphs ## ############ startX = proximalLimitKM*SQRT_PI endX = distalLimitKM*SQRT_PI # Model xs = helper_functions.getStaggeredPoints(startX, endX, MODEL_PLOTTING_PRECISION) ys = [thicknessFunction(x) for x in xs] self.modelGraphFrame.plotFilledLine(xs, ys, color=colours[0]) # Regression logXs = [np.log(a) for a in self.sqrtAreaKM] logYs = [np.log(t) for t in self.thicknessM] self.regressionGraphFrame.plotScatter(logXs, logYs, False) self.regressionGraphFrame.axes.set_xlabel(r"$\log{\sqrt{Area}}$") lineXs = [np.sqrt(startX), np.sqrt(endX)] lineYs = [np.log(c) - m*x for x in lineXs] self.regressionGraphFrame.plotLine(lineXs, lineYs, colours[0]) def _updateWei(self): ########### ## Stats ## ########### fr = self.statsFrame # lambda lamb = self.currentParameters["lambda"] lambdaStr = helper_functions.roundToSF(lamb, NUMBER_OF_SF) fr.weiLambdaE.insertNew(lamb) # k k = self.currentParameters["k"] kStr = helper_functions.roundToSF(k, NUMBER_OF_SF) fr.weiKE.insertNew(k) # theta theta = self.currentParameters["theta"] thetaStr = helper_functions.roundToSF(theta, NUMBER_OF_SF) fr.weiThetaE.insertNew(theta) # Volume volume = calculateWeibullVolume(lamb, k, theta) volumeStr = helper_functions.roundToSF(volume, NUMBER_OF_SF) fr.totalEstimatedVolume_E.insertNew(volumeStr) # Error thicknessFunction = lambda x : theta*((x/lamb)**(k-2))*math.exp(-((x/lamb)**k)) error = regression_methods.meanRelativeSquaredError(self.sqrtAreaKM, self.thicknessM, thicknessFunction) errorStr = helper_functions.roundToSF(error, NUMBER_OF_SF) fr.relativeSquaredError_E.insertNew(errorStr) # Equation invLambdaStr = helper_functions.roundToSF(1/lamb, NUMBER_OF_SF) kminus2Str = helper_functions.roundToSF(k-2, NUMBER_OF_SF) equationStr = "T = " + thetaStr + "((" + invLambdaStr + "x)^" +kminus2Str + ")exp(-(" + invLambdaStr + "x)^" + kStr + ")" fr.equation_E.insertNew(equationStr) ############ ## Graphs ## ############ # Model startX = 0 endX = (self.isopachs[-1].distanceFromVentKM()+50)*SQRT_PI xs = helper_functions.getStaggeredPoints(startX,endX,MODEL_PLOTTING_PRECISION)[1:] ys = [theta*((x/lamb)**(k-2))*math.exp(-((x/lamb)**k)) for x in xs] self.modelGraphFrame.plotFilledLine(xs, ys, colours[0]) def _displayErrorSurface(self,event): try: xLL, xUL, yLL, yUL, resolution = self.errorSurfaceFrame.getSurfaceParameters() except ValueError as ve: messagebox.showerror("Calculation error", ve.args[0]) return self.graphNotebook.addFrame(self.errorSurfaceGraphFrame, text="Error surface") if self.errorSurfaceFrame.xSymbol == "\u03BB": self.errorSurfaceGraphFrame.axes.set_xlabel("$\lambda$") else: self.errorSurfaceGraphFrame.axes.set_xlabel(self.errorSurfaceFrame.xSymbol) xs = [isopach.sqrtAreaKM for isopach in self.isopachs] ys = [isopach.thicknessM for isopach in self.isopachs] if self.modelType == Model.POW: def errorFunction(c,m): thicknessFunction = lambda x : c*(x**(-m)) return math.log(regression_methods.meanRelativeSquaredError(xs, ys, thicknessFunction)) elif self.modelType == Model.WEI: def errorFunction(lamb,k): theta = calculateTheta(xs,ys,lamb,k) def thicknessFunction(x): try: return np.exp(np.log(theta)+(k-2)*np.log(x/lamb)-(x/lamb)**k) except FloatingPointError: return 0 mrse = regression_methods.meanRelativeSquaredError(xs, ys, thicknessFunction) return math.log(mrse) self.errorSurfaceGraphFrame.axes.set_ylabel(self.errorSurfaceFrame.ySymbol) self.errorSurfaceGraphFrame.clear() self.errorSurfaceGraphFrame.plotSurface(errorFunction, xLL, xUL, yLL, yUL, resolution) self.graphNotebook.select(self.errorSurfaceGraphFrame) def _parametersReset(self,event): self.currentParameters = deepcopy(self.defaultParameters) self._updateDisplay(False) def _parametersChanged(self,event): try: newValues = self.statsFrame.getParameters(self.modelType) except ValueError as ve: messagebox.showerror("Calculation error", ve.args[0]) return if self.modelType == Model.EXP: self.currentParameters["segmentCoefficients"][self.currentSegment] = newValues["c"] self.currentParameters["segmentExponents"][self.currentSegment] = newValues["m"] self.currentParameters["segmentLimits"][self.currentSegment] = newValues["segStart"] self.currentParameters["segmentLimits"][self.currentSegment+1] = newValues["segEnd"] elif self.modelType == Model.POW: self.currentParameters["coefficient"] = newValues["c"] self.currentParameters["exponent"] = newValues["m"] elif self.modelType == Model.WEI: self.currentParameters["lambda"] = newValues["lambda"] self.currentParameters["k"] = newValues["k"] self.currentParameters["theta"] = newValues["theta"] self._updateDisplay(False) def clear(self): if self.modelType is not None: for component in self.statsFrame.components[self.modelType]: component.grid_remove() self.statsFrame.grid_remove() self.graphNotebook.grid_remove() self.errorSurfaceFrame.grid_remove() self.errorSurfaceSeperator.grid_remove() self.config(text="Results") self.modelGraphFrame.clear() self.regressionGraphFrame.clear() self.errorSurfaceGraphFrame.clear() self.graphNotebook.removeFrame(self.regressionGraphFrame) self.graphNotebook.removeFrame(self.errorSurfaceGraphFrame) self.modelType = None
class ResultsFrame(LabelFrame): padY = 5 padX = 30 def __init__(self,parent): LabelFrame.__init__(self, parent,text="Results", width=825, height=485) # Terrible kludgy hack to force the app to stay the right size # Need to work out how to remove self.grid_propagate(False) self.resultsDict = None self.modelType = None self.currentSegment = 0 # Stats frame self.statsFrame = StatsFrame(self, self.padX, self.padY) self.statsFrame.calculate_B.bind("<Button-1>", self._parametersChanged) self.statsFrame.reset_B.bind("<Button-1>", self._parametersReset) def onComboBoxSelect(e): self.currentSegment = e.widget.current() self._updateDisplay(True) self.statsFrame.expSeg_CB.bind("<<ComboboxSelected>>", onComboBoxSelect) # Error frame self.errorSurfaceFrame = ErrorSurfaceFrame(self) self.errorSurfaceFrame.errorSurfaceB.bind("<Button-1>", self._displayErrorSurface) # Graph notebook self.errorSurfaceSeperator = Separator(self,orient=tkinter.HORIZONTAL) self.graphNotebook = ImprovedNotebook(self) self.modelGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.modelGraphFrame.axes.set_ylabel(r'$thickness(m)$') self.regressionGraphFrame = GraphFrame(self.graphNotebook, dim=2) self.regressionGraphFrame.axes.set_ylabel(r'$\ln{(thickness(m))}$') self.errorSurfaceGraphFrame = GraphFrame(self.graphNotebook, dim=3) self.errorSurfaceGraphFrame.axes.set_zlabel(r'$error$') self.graphNotebook.addFrame(self.modelGraphFrame, text="Model") def displayNewModel(self, modelType, resultsDict): self.modelType = modelType self.isopachs = resultsDict["isopachs"] self.sqrtAreaKM = [isopach.sqrtAreaKM for isopach in self.isopachs] self.thicknessM = [isopach.thicknessM for isopach in self.isopachs] self.currentParameters = resultsDict self.defaultParameters = deepcopy(self.currentParameters) self.statsFrame.grid(row=0,column=0,padx=10,pady=5,sticky="NESW") self.graphNotebook.grid(row=0,column=1,padx=10, pady=5,sticky="NEW") if self.modelType == Model.EXP: self._displayExp() self.config(text="Results (Exponential)") else: self.errorSurfaceSeperator.grid(row=1, column=0, columnspan=2, padx=20, pady=(20,0), sticky="EW") self.errorSurfaceFrame.grid(row=2, column=0, columnspan=2, padx=10, pady=0, sticky="EW") if self.modelType == Model.POW: self._displayPow() self.config(text="Results (Power law)") elif self.modelType == Model.WEI: self._displayWei() self.config(text="Results (Weibull)") self._updateDisplay(False) def _updateDisplay(self, comboboxUpdate): if not comboboxUpdate: self.modelGraphFrame.clear() self.regressionGraphFrame.clear() thicknessM = [isopach.thicknessM for isopach in self.isopachs] sqrtArea = [isopach.sqrtAreaKM for isopach in self.isopachs] self.modelGraphFrame.plotScatter(sqrtArea,thicknessM,True) self.modelGraphFrame.axes.set_xlabel(r"$\sqrt{Area}$") if self.modelType == Model.EXP: self._updateExp(comboboxUpdate) elif self.modelType == Model.POW: self._updatePow() elif self.modelType == Model.WEI: self._updateWei() def _displayExp(self): fr = self.statsFrame padX = self.padX padY = self.padY fr.expSeg_CB.grid(row=3,column=0,sticky="W",padx=10,pady=padY) vals = ["Segment " + str(i) for i in range(1,self.currentParameters["numberOfSegments"]+1)] fr.expSeg_CB.configure(values=vals) fr.expSeg_CB.current(0) fr.expSegVolume_L.grid(row=4,column=0,padx=10,sticky="W",pady=padY) fr.expSegVolume_E.grid(row=4,column=1,padx=10,sticky="E") fr.equation_L.grid(row=5,column=0,sticky="W",padx=10,pady=padY) fr.equation_E.grid(row=5,column=1,padx=10,sticky="E") fr.equation_L.configure(text="Segment equation:") fr.parameters_L.grid(row=6,column=0,padx=10,pady=padY,sticky="W") fr.expSegStartLimit_L.grid(row=7,column=0,sticky="W",padx=padX,pady=padY) fr.expSegStartLimit_E.grid(row=7,column=1,padx=10,sticky="E") fr.expSegEndLimit_L.grid(row=8,column=0,sticky="W",padx=padX,pady=padY) fr.expSegEndLimit_E.grid(row=8,column=1,padx=10,sticky="E") fr.expSegCoefficent_L.grid(row=9,column=0,sticky="W",padx=padX,pady=padY) fr.expSegCoefficent_E.grid(row=9,column=1,padx=10,sticky="E") fr.expSegExponent_L.grid(row=10,column=0,sticky="W",padx=padX,pady=padY) fr.expSegExponent_E.grid(row=10,column=1,padx=10,sticky="E") # Recalculate buttons fr.calculate_B.grid(row=11,column=0,padx=padX,pady=padY,sticky="W") fr.reset_B.grid(row=11,column=1,padx=10,sticky="E") self.graphNotebook.addFrame(self.regressionGraphFrame, text="Regression") def _displayPow(self): fr = self.statsFrame padX = self.padX padY = self.padY fr.equation_L.grid(row=2,column=0,sticky="W",padx=10,pady=padY) fr.equation_E.grid(row=2,column=1,padx=10,sticky="E") fr.equation_L.configure(text="Equation:") fr.parameters_L.grid(row=3,column=0,padx=10,pady=padY,sticky="W") fr.powCoefficient_L.grid(row=4,column=0,sticky="W",padx=padX,pady=padY) fr.powCoefficient_E.grid(row=4,column=1,padx=10,sticky="E") fr.powExponent_L.grid(row=5,column=0,sticky="W",padx=padX,pady=padY) fr.powExponent_E.grid(row=5,column=1,padx=10,sticky="E") fr.powProximalLimit_L.grid(row=6,column=0,sticky="W",padx=padX,pady=padY) fr.powProximalLimit_E.grid(row=6,column=1,padx=10,sticky="E") fr.powDistalLimit_L.grid(row=7,column=0,sticky="W",padx=padX,pady=padY) fr.powDistalLimit_E.grid(row=7,column=1,padx=10,sticky="E") # Recalculate buttons fr.calculate_B.grid(row=8,column=0,padx=padX,pady=padY,sticky="W") fr.reset_B.grid(row=8,column=1,padx=10,sticky="E") fr.powSuggestedProximalLimit_L.grid(row=9,column=0,sticky="W",padx=10,pady=padY) fr.powSuggestedProximalLimit_E.grid(row=9,column=1,padx=10,sticky="E") self.graphNotebook.addFrame(self.regressionGraphFrame, text="Regression") self.errorSurfaceFrame.update("c", "m", 0.0, 5.0, 0.0, 5.0) def _displayWei(self): fr = self.statsFrame padX = self.padX padY = self.padY fr.equation_L.grid(row=2,column=0,sticky="W",padx=10,pady=padY) fr.equation_E.grid(row=2,column=1,padx=10,sticky="E") fr.equation_L.configure(text="Equation:") fr.parameters_L.grid(row=3,column=0,padx=10,pady=padY,sticky="W") fr.weiLambdaL.grid(row=4,column=0,padx=padX,pady=padY,sticky="W") fr.weiLambdaE.grid(row=4,column=1,padx=10,sticky="E") fr.weiKL.grid(row=5,column=0,padx=padX,pady=padY,sticky="W") fr.weiKE.grid(row=5,column=1,padx=10,sticky="E") fr.weiThetaL.grid(row=6,column=0,padx=padX,pady=padY,sticky="W") fr.weiThetaE.grid(row=6,column=1,padx=10,sticky="E") # Recalculate buttons fr.calculate_B.grid(row=7,column=0,padx=padX,pady=padY,sticky="W") fr.reset_B.grid(row=7,column=1,padx=10,sticky="E") parameterLimits = self.currentParameters["limits"] lambdaLower, lambdaUpper = parameterLimits[0] kLower, kUpper = parameterLimits[1] self.errorSurfaceFrame.update("\u03BB", "k", lambdaLower, lambdaUpper, kLower, kUpper) def _updateExp(self, comboboxUpdate): n = self.currentParameters["numberOfSegments"] coefficients = self.currentParameters["segmentCoefficients"] exponents = self.currentParameters["segmentExponents"] limits = self.currentParameters["segmentLimits"] ########### ## Stats ## ########### fr = self.statsFrame # Segment start start = limits[self.currentSegment] startStr = helper_functions.roundToSF(start, NUMBER_OF_SF) fr.expSegStartLimit_E.insertNew(start) fr.expSegStartLimit_E.setUserEditable(self.currentSegment != 0) # Segment end end = limits[self.currentSegment+1] endStr = helper_functions.roundToSF(end, NUMBER_OF_SF) fr.expSegEndLimit_E.insertNew(end) fr.expSegEndLimit_E.setUserEditable(self.currentSegment != n-1) # Segment coefficient coefficient = coefficients [self.currentSegment] coefficientStr = helper_functions.roundToSF(coefficient, NUMBER_OF_SF) fr.expSegCoefficent_E.insertNew(coefficient) # Segment exponent exponent = exponents[self.currentSegment] exponentStr = helper_functions.roundToSF(exponent, NUMBER_OF_SF) fr.expSegExponent_E.insertNew(exponent) # Segment volume segmentVolumes = [calculateExponentialSegmentVolume(coefficients[i], exponents[i], limits[i], limits[i+1]) for i in range(n)] segmentVolumeStr = helper_functions.roundToSF(segmentVolumes[self.currentSegment], NUMBER_OF_SF) fr.expSegVolume_E.insertNew(segmentVolumeStr) # Total volume totalVolume = sum(segmentVolumes) estimatedTotalVolumeStr = helper_functions.roundToSF(totalVolume, NUMBER_OF_SF) fr.totalEstimatedVolume_E.insertNew(estimatedTotalVolumeStr) # Error def thicknessFunction(x): for i in range(n): if limits[i] <= x < limits[i+1]: return coefficients[i]*math.exp(-exponents[i]*x) error = regression_methods.meanRelativeSquaredError(self.sqrtAreaKM, self.thicknessM, thicknessFunction) errorStr = helper_functions.roundToSF(error, NUMBER_OF_SF) fr.relativeSquaredError_E.insertNew(errorStr) # Equation equationStr = "T = " + coefficientStr if exponent > 0: equationStr += "exp(-" + exponentStr + "x)" elif exponent < 0: equationStr += "exp(" + exponentStr[1:] + "x)" fr.equation_E.insertNew(equationStr) ############ ## Graphs ## ############ if not comboboxUpdate: # Model endXs = limits[1:-1] + [1.5*max(self.sqrtAreaKM)-0.5*min(self.sqrtAreaKM)] for i in range(n): xs = helper_functions.getStaggeredPoints(limits[i], endXs[i], MODEL_PLOTTING_PRECISION) ys = [coefficients[i]*math.exp(-exponents[i]*x) for x in xs] self.modelGraphFrame.plotFilledLine(xs, ys, color=colours[i]) # Regression logThicknessM = [np.log(t) for t in self.thicknessM] self.regressionGraphFrame.plotScatter(self.sqrtAreaKM, logThicknessM, False) self.regressionGraphFrame.axes.set_xlabel(r"$\sqrt{Area}$") for i in range(n): xs = [limits[i], endXs[i]] ys = [np.log(thicknessFunction(x)) for x in xs] self.regressionGraphFrame.plotLine(xs,ys, color=colours[i]) def _updatePow(self): ########### ## Stats ## ########### fr = self.statsFrame # Coefficient c = self.currentParameters["coefficient"] coefficientStr = helper_functions.roundToSF(c, NUMBER_OF_SF) fr.powCoefficient_E.insertNew(c) # Exponent m = self.currentParameters["exponent"] exponentStr = helper_functions.roundToSF(m, NUMBER_OF_SF) fr.powExponent_E.insertNew(m) # Proximal limit proximalLimitKM = self.currentParameters["proximalLimitKM"] proximalLimitStr = helper_functions.roundToSF(proximalLimitKM, NUMBER_OF_SF) fr.powProximalLimit_E.insertNew(proximalLimitKM) # Distal limit distalLimitKM = self.currentParameters["distalLimitKM"] distalLimitStr = helper_functions.roundToSF(distalLimitKM, NUMBER_OF_SF) fr.powDistalLimit_E.insertNew(distalLimitKM) # Volume volume = calculatePowerLawVolume(c, m, proximalLimitKM, distalLimitKM) volumeStr = helper_functions.roundToSF(volume, NUMBER_OF_SF) fr.totalEstimatedVolume_E.insertNew(volumeStr) # Error thicknessFunction = lambda x : c*(x**(-m)) error = regression_methods.meanRelativeSquaredError(self.sqrtAreaKM, self.thicknessM, thicknessFunction) errorStr = helper_functions.roundToSF(error, NUMBER_OF_SF) fr.relativeSquaredError_E.insertNew(errorStr) # Equation equationStr = "T = " + coefficientStr if m > 0: equationStr += "x^-" + exponentStr elif m < 0: equationStr += "x^" + exponentStr[1:] fr.equation_E.insertNew(equationStr) # Suggested proximal limit suggestedProximalLimit = self.currentParameters["suggestedProximalLimit"] suggestedProximalLimitStr = helper_functions.roundToSF(suggestedProximalLimit, NUMBER_OF_SF) fr.powSuggestedProximalLimit_E.insertNew(suggestedProximalLimitStr) ############ ## Graphs ## ############ startX = proximalLimitKM*SQRT_PI endX = distalLimitKM*SQRT_PI # Model xs = helper_functions.getStaggeredPoints(startX, endX, MODEL_PLOTTING_PRECISION) ys = [thicknessFunction(x) for x in xs] self.modelGraphFrame.plotFilledLine(xs, ys, color=colours[0]) # Regression logXs = [np.log(a) for a in self.sqrtAreaKM] logYs = [np.log(t) for t in self.thicknessM] self.regressionGraphFrame.plotScatter(logXs, logYs, False) self.regressionGraphFrame.axes.set_xlabel(r"$\log{\sqrt{Area}}$") lineXs = [np.sqrt(startX), np.sqrt(endX)] lineYs = [np.log(c) - m*x for x in lineXs] self.regressionGraphFrame.plotLine(lineXs, lineYs, colours[0]) def _updateWei(self): ########### ## Stats ## ########### fr = self.statsFrame # lambda lamb = self.currentParameters["lambda"] lambdaStr = helper_functions.roundToSF(lamb, NUMBER_OF_SF) fr.weiLambdaE.insertNew(lamb) # k k = self.currentParameters["k"] kStr = helper_functions.roundToSF(k, NUMBER_OF_SF) fr.weiKE.insertNew(k) # theta theta = self.currentParameters["theta"] thetaStr = helper_functions.roundToSF(theta, NUMBER_OF_SF) fr.weiThetaE.insertNew(theta) # Volume volume = calculateWeibullVolume(lamb, k, theta) volumeStr = helper_functions.roundToSF(volume, NUMBER_OF_SF) fr.totalEstimatedVolume_E.insertNew(volumeStr) # Error thicknessFunction = lambda x : theta*((x/lamb)**(k-2))*math.exp(-((x/lamb)**k)) error = regression_methods.meanRelativeSquaredError(self.sqrtAreaKM, self.thicknessM, thicknessFunction) errorStr = helper_functions.roundToSF(error, NUMBER_OF_SF) fr.relativeSquaredError_E.insertNew(errorStr) # Equation invLambdaStr = helper_functions.roundToSF(1/lamb, NUMBER_OF_SF) kminus2Str = helper_functions.roundToSF(k-2, NUMBER_OF_SF) equationStr = "T = " + thetaStr + "((" + invLambdaStr + "x)^" +kminus2Str + ")exp(-(" + invLambdaStr + "x)^" + kStr + ")" fr.equation_E.insertNew(equationStr) ############ ## Graphs ## ############ # Model startX = 0 endX = (self.isopachs[-1].distanceFromVentKM()+50)*SQRT_PI xs = helper_functions.getStaggeredPoints(startX,endX,MODEL_PLOTTING_PRECISION)[1:] ys = [theta*((x/lamb)**(k-2))*math.exp(-((x/lamb)**k)) for x in xs] self.modelGraphFrame.plotFilledLine(xs, ys, colours[0]) def _displayErrorSurface(self,event): try: xLL, xUL, yLL, yUL, resolution = self.errorSurfaceFrame.getSurfaceParameters() except ValueError as ve: messagebox.showerror("Calculation error", ve.args[0]) return self.graphNotebook.addFrame(self.errorSurfaceGraphFrame, text="Error surface") if self.errorSurfaceFrame.xSymbol == "\u03BB": self.errorSurfaceGraphFrame.axes.set_xlabel("$\lambda$") else: self.errorSurfaceGraphFrame.axes.set_xlabel(self.errorSurfaceFrame.xSymbol) xs = [isopach.sqrtAreaKM for isopach in self.isopachs] ys = [isopach.thicknessM for isopach in self.isopachs] if self.modelType == Model.POW: def errorFunction(c,m): thicknessFunction = lambda x : c*(x**(-m)) return math.log(regression_methods.meanRelativeSquaredError(xs, ys, thicknessFunction)) elif self.modelType == Model.WEI: def errorFunction(lamb,k): theta = calculateTheta(xs,ys,lamb,k) def thicknessFunction(x): try: return np.exp(np.log(theta)+(k-2)*np.log(x/lamb)-(x/lamb)**k) except FloatingPointError: return 0 mrse = regression_methods.meanRelativeSquaredError(xs, ys, thicknessFunction) return math.log(mrse) self.errorSurfaceGraphFrame.axes.set_ylabel(self.errorSurfaceFrame.ySymbol) self.errorSurfaceGraphFrame.clear() self.errorSurfaceGraphFrame.plotSurface(errorFunction, xLL, xUL, yLL, yUL, resolution) self.graphNotebook.select(self.errorSurfaceGraphFrame) def _parametersReset(self,event): self.currentParameters = deepcopy(self.defaultParameters) self._updateDisplay(False) def _parametersChanged(self,event): try: newValues = self.statsFrame.getParameters(self.modelType) except ValueError as ve: messagebox.showerror("Calculation error", ve.args[0]) return if self.modelType == Model.EXP: self.currentParameters["segmentCoefficients"][self.currentSegment] = newValues["c"] self.currentParameters["segmentExponents"][self.currentSegment] = newValues["m"] self.currentParameters["segmentLimits"][self.currentSegment] = newValues["segStart"] self.currentParameters["segmentLimits"][self.currentSegment+1] = newValues["segEnd"] elif self.modelType == Model.POW: self.currentParameters["coefficient"] = newValues["c"] self.currentParameters["exponent"] = newValues["m"] elif self.modelType == Model.WEI: self.currentParameters["lambda"] = newValues["lambda"] self.currentParameters["k"] = newValues["k"] self.currentParameters["theta"] = newValues["theta"] self._updateDisplay(False) def clear(self): if self.modelType is not None: for component in self.statsFrame.components[self.modelType]: component.grid_remove() self.statsFrame.grid_remove() self.graphNotebook.grid_remove() self.errorSurfaceFrame.grid_remove() self.errorSurfaceSeperator.grid_remove() self.config(text="Results") self.modelGraphFrame.clear() self.regressionGraphFrame.clear() self.errorSurfaceGraphFrame.clear() self.graphNotebook.removeFrame(self.regressionGraphFrame) self.graphNotebook.removeFrame(self.errorSurfaceGraphFrame) self.modelType = None