Exemple #1
0
    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")
Exemple #2
0
	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")
Exemple #3
0
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
Exemple #4
0
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