import Tkinter as tk from View_MyFileOpen import filename from View_Scatterplot import drawScatterplot from View_Histogram import drawHistogram from Controller import * from Model import * class myOptionMenu(tk.OptionMenu): # Allows options to be added or removed. def __init__(self, *args, **kw): self._command = kw.get("command") tk.OptionMenu.__init__(self, *args, **kw) def addOption(self, label, variable): self["menu"].add_command(label=label, command=tk._setit(variable, label, self._command)) def delvar(self, label): self["menu"].delete(self["menu"].index(label)) class Application(Frame): def createLabels(self, r, c): #(0, 1) self.nLabel = Label(self, text="Number of Numeric Val's: ") self.maxLabel = Label(self, text="Max: ") self.minLabel = Label(self, text="Min: ") self.rangeLabel = Label(self, text="Range: ") self.meanLabel = Label(self, text="Mean: ") self.medianLabel = Label(self, text="Median: ") self.modeLabel = Label(self, text="Mode: ") self.stdDevLabel = Label(self, text="Std. Dev.: ") self.varianceLabel = Label(self, text="Variance: ") self.nDispA = Label(self, textvariable= self.A.nVal) self.minDispA = Label(self, textvariable= self.A.minVal) self.maxDispA = Label(self, textvariable= self.A.maxVal) self.rangeDispA = Label(self, textvariable= self.A.rangeVal) self.meanDispA = Label(self, textvariable= self.A.meanVal) self.medianDispA = Label(self, textvariable= self.A.medianVal) self.modeDispA = Label(self, textvariable= self.A.modeVal) self.varianceDispA = Label(self, textvariable= self.A.varianceVal) self.stdDevDispA = Label(self, textvariable= self.A.stdDevVal) self.nDispB = Label(self, textvariable= self.B.nVal) self.minDispB = Label(self, textvariable= self.B.minVal) self.maxDispB = Label(self, textvariable= self.B.maxVal) self.rangeDispB = Label(self, textvariable= self.B.rangeVal) self.meanDispB = Label(self, textvariable= self.B.meanVal) self.medianDispB = Label(self, textvariable= self.B.medianVal) self.modeDispB = Label(self, textvariable= self.B.modeVal) self.varianceDispB = Label(self, textvariable= self.B.varianceVal) self.stdDevDispB = Label(self, textvariable= self.B.stdDevVal) self.Albl = Label(self, text="A") self.Blbl = Label(self, text="B") self.Albl.grid(row=r, column=c) self.Blbl.grid(row=r, column=c+1) self.AlblName = Label(self, textvariable=self.A.name) self.AlblName.grid(row=r+29, column=c) self.AlblName.bind("", lambda x: self.helpDispVar.set("This column contains data about the variable selected in pulldown A.")) self.BlblName = Label(self, textvariable=self.B.name) self.BlblName.grid(row=r+29, column=c+1) self.BlblName.bind("", lambda x: self.helpDispVar.set("This column contains data about the variable selected in pulldown B.")) self.nDispA.grid(row=r+30, column=c) self.minDispA.grid(row=r+40, column=c) self.maxDispA.grid(row=r+50, column=c) self.rangeDispA.grid(row=r+60, column=c) self.meanDispA.grid(row=r+70, column=c) self.medianDispA.grid(row=r+80, column=c) self.modeDispA.grid(row=r+90, column=c) self.stdDevDispA.grid(row=r+100, column=c) self.varianceDispA.grid(row=r+110, column=c) self.nDispB.grid(row=r+30, column=c+1) self.minDispB.grid(row=r+40, column=c+1) self.maxDispB.grid(row=r+50, column=c+1) self.rangeDispB.grid(row=r+60, column=c+1) self.meanDispB.grid(row=r+70, column=c+1) self.medianDispB.grid(row=r+80, column=c+1) self.modeDispB.grid(row=r+90, column=c+1) self.stdDevDispB.grid(row=r+100, column=c+1) self.varianceDispB.grid(row=r+110, column=c+1) self.nLabel.grid(row=r+30) self.nLabel.bind("", lambda x: self.helpDispVar.set("The number of numeric entries in the selected variable.")) self.minLabel.grid(row=r+40) self.minLabel.bind("", lambda x: self.helpDispVar.set("The smallest number in the selected variable.")) self.maxLabel.grid(row=r+50) self.maxLabel.bind("", lambda x: self.helpDispVar.set("The largest number in the selected variable.")) self.rangeLabel.grid(row=r+60) self.rangeLabel.bind("", lambda x: self.helpDispVar.set("Max - Min; The spread of the variable.")) self.meanLabel.grid(row=r+70) self.meanLabel.bind("", lambda x: self.helpDispVar.set("The average value of the variable.")) self.medianLabel.grid(row=r+80) self.medianLabel.bind("", lambda x: self.helpDispVar.set("The centre element if you sort all the values in the variable.")) self.modeLabel.grid(row=r+90) self.modeLabel.bind("", lambda x: self.helpDispVar.set("The number that appears the largest number of times in this variable.")) self.stdDevLabel.grid(row=r+100) self.stdDevLabel.bind("", lambda x: self.helpDispVar.set("The standard deviation is a measure of how spread out the data is.")) self.varianceLabel.grid(row=r+110) self.varianceLabel.bind("", lambda x: self.helpDispVar.set("The variance is a measure of how spread out the data is.")) def createHelpDisplay(self, depth): self.helpDispVar = StringVar() self.helpDisp = Label(self, textvariable=self.helpDispVar) self.helpDisp.grid(row=depth, columnspan=10) self.helpDisp.bind("", lambda x: self.helpDispVar.set("Move the mouse over a screen element to see an explanation of its function.")) def createVarEditors(self, r, c): self.VarEditFrame = Frame(self) self.VarEditFrame["bd"] = 2 self.VarEditFrame["relief"] = GROOVE self.newName = StringVar() self.newName.set("New Name") self.newNameEntry = Entry(self.VarEditFrame, textvariable=self.newName) self.copyButton = Button(self.VarEditFrame, text="Copy " + self.aStringVar.get(), command=lambda: self.copy(self.aStringVar.get(), self.newName.get())) self.deleteA = Button(self.VarEditFrame, text="Delete " + self.aStringVar.get(), command=lambda: self.deleteVar(self.aStringVar.get()) + self.pullDownAcb(self.bStringVar.get() ) ) self.renameA = Button(self.VarEditFrame, text="Rename " + self.aStringVar.get(), command=lambda: self.copy(self.aStringVar.get(), self.newName.get()) + self.deleteVar(self.aStringVar.get()) + self.pullDownAcb(self.newName.get())) self.renameA.grid(row=5, column=1) self.renameA.bind("", lambda x: self.helpDispVar.set("Gives the current variable a new name.")) self.copyButton.grid(row=4, column=1) self.copyButton.bind("", lambda x: self.helpDispVar.set("Copies the current variable to a new name.")) self.newNameEntry.grid(row=6, column=1) self.newNameEntry.bind("", lambda x: self.helpDispVar.set("Use this entry box to type a new name for variables.")) self.deleteA.grid(row=7, column=1) self.deleteA.bind("", lambda x: self.helpDispVar.set("Delete the selected variable.")) self.VarEditFrame.grid(row=r, column=c, rowspan=4, sticky="NSEW") def drawScatterControls(self, r, c): #(3, 0) self.ScatterFrame = Frame(self) self.ScatterFrame["bd"] = 2 self.ScatterFrame["relief"] = GROOVE self.ScatterRadioVar = StringVar() self.selectNullMethodPairwise = Radiobutton(self.ScatterFrame, text="Pairwise Delete", variable=self.ScatterRadioVar, value="Pairwise") self.selectNullMethodZeroSubst = Radiobutton(self.ScatterFrame, text="Zero Substitution", variable=self.ScatterRadioVar, value="Zero") self.selectNullMethodMeanSubst = Radiobutton(self.ScatterFrame, text="Mean Substitution", variable=self.ScatterRadioVar, value="Mean") self.selectNullMethodPairwise.grid(row=2) self.selectNullMethodPairwise.bind("", lambda x: self.helpDispVar.set("Ignore any record where either entry contains non-numeric data.")) self.selectNullMethodZeroSubst.grid(row=3) self.selectNullMethodZeroSubst.bind("", lambda x: self.helpDispVar.set("Zero any record where either entry contains non-numeric data.")) self.selectNullMethodMeanSubst.grid(row=4) self.selectNullMethodMeanSubst.bind("", lambda x: self.helpDispVar.set("Set any record where either entry contains non-numeric data to the mean of the numeric data.")) self.ScatterRadioVar.set("Pairwise") self.scatterButton = Button(self.ScatterFrame, text="Scatterplot (A:B)", command=lambda: drawScatterplot(self.A.list, self.B.list, self.A.name.get(), self.B.name.get(), self.ScatterRadioVar.get())) self.scatterButton.grid(row=1, column=0, columnspan=1) self.scatterButton.bind("", lambda x: self.helpDispVar.set("Display a scatterplot comparing the currently selected variables using gnuplot.")) self.ScatterFrame.grid(row=r, column=c, rowspan=4, sticky="NSEW") def drawCorrelationFrame(self, r, c): #(1, 0) self.pearsonsFrame = Frame(self) self.pearsonsLBL = Label(self.pearsonsFrame, text="Correlation (A:B)") self.pearsonsDisp = Label(self.pearsonsFrame, text="Correlation") self.pearsonsLBL.grid(row=2, column=3) self.pearsonsLBL.bind("", lambda x: self.helpDispVar.set("Pearsons Coefficient measures how strongly related two variables are.\nPositive values indicate direct correlation while negative values indicate inverse correlation.\nValues with a magnitude above 0.5 are quite significant.")) self.pearsonsDisp.grid(row=3, column=3) self.pearsonsDisp.bind("", lambda x: self.helpDispVar.set("Pearsons Coefficient measures how strongly related two variables are.\nPositive values indicate direct correlation while negative values indicate inverse correlation.\nValues with a magnitude above 0.5 are quite significant.")) self.pearsonsDisp["text"] = PearsonCorrelation(zeroSubst(self.A.list), zeroSubst(self.B.list)) self.pearsonsFrame["bd"] = 2 self.pearsonsFrame["relief"] = GROOVE self.pearsonsFrame.grid(row=r, column=c, rowspan=2, sticky="NSEW") self.pearsonsFrame.bind("", lambda x: self.helpDispVar.set("Pearsons Coefficient measures how strongly related two variables are.\nPositive values indicate direct correlation while negative values indicate inverse correlation.\nValues with a magnitude above 0.5 are quite significant.")) def createSumFrame(self, r, c): # (8, 3) def sumVariables(): L = [] L2 = [] L3 = [] items = self.lb.curselection() for i in items: L.append(self.vars[self.lb.get(i)]) if (self.SumRadioVar.get() == "Pairwise"): L2 = pairwiseDelete(L) elif (self.SumRadioVar.get() == "Zero"): for item in L: L2.append(zeroSubst(item)) else: # "Mean" for item in L: L2.append(meanSubst(item)) L3 = L2[0][:] for i in range(1, len(L2)): for j in range(0, len(L2[i])): L3[j] = L3[j] + L2[i][j] self.vars[self.SumVar.get()] = L3[:] self.pullDownA.addOption(self.SumVar.get(), self.aStringVar) self.pullDownB.addOption(self.SumVar.get(), self.bStringVar) self.lb.insert(END, self.SumVar.get()) self.lb["height"] = self.lb["height"] + 1 self.SumFrame = Frame(self) self.SumFrame["bd"] = 2 self.SumFrame["relief"] = GROOVE self.SumRadioVar = StringVar() #self.selectSumNullMethodPairwise = Radiobutton(self.SumFrame, text="Pairwise Delete", # variable=self.SumRadioVar, value="Pairwise") # Pairwise delete makes little sense in this case, and it makes the new variable un-usable with some other options because it isn't the same length # However, uncommenting the previous two lines enables it. Use at own risk. self.selectSumNullMethodZeroSubst = Radiobutton(self.SumFrame, text="Zero Substitution", variable=self.SumRadioVar, value="Zero") self.selectSumNullMethodMeanSubst = Radiobutton(self.SumFrame, text="Mean Substitution", variable=self.SumRadioVar, value="Mean") #self.selectSumNullMethodPairwise.grid(row=1) #self.selectSumNullMethodPairwise.bind("", lambda x: self.helpDispVar.set("Ignore any record where either entry contains non-numeric data.")) self.selectSumNullMethodZeroSubst.grid(row=2) self.selectSumNullMethodZeroSubst.bind("", lambda x: self.helpDispVar.set("Zero any record where either entry contains non-numeric data.")) self.selectSumNullMethodMeanSubst.grid(row=3) self.selectSumNullMethodMeanSubst.bind("", lambda x: self.helpDispVar.set("Set any record where either entry contains non-numeric data to the mean of the numeric data.")) self.SumRadioVar.set("Mean") self.sumButton = Button(self.SumFrame, text="Sum Variables (Use Listbox)", command=sumVariables) self.SumVar = StringVar() self.sumNewName = Entry(self.SumFrame, textvariable=self.SumVar) self.SumVar.set("New Variable Name") self.sumNewName.grid(row=4, pady=3) self.sumNewName.bind("", lambda x: self.helpDispVar.set("The name entered here will be used for variables created by the 'sum' button.")) self.sumButton.grid(row=0) self.sumButton.bind("", lambda x: self.helpDispVar.set("Create a new variable by summing the values of the variables selected in the listbox.")) self.SumFrame.grid(row=r, column=c, sticky="NSEW", rowspan=200) def createReplaceFrame(self, r, c): # (3, 2) self.replFrame = Frame(self) self.replFrame["bd"] = 2 self.replFrame["relief"] = GROOVE self.replaceLBL = Label(self.replFrame, text="Replace:") self.replaceLBL.grid(row=8) self.replaceLBL.bind("", lambda x: self.helpDispVar.set("Enter text or number to find")) self.withLBL = Label(self.replFrame, text="With:") self.withLBL.grid(row=9) self.withLBL.bind("", lambda x: self.helpDispVar.set("Enter text or number to insert, or insert the mean")) self.replaceVar = StringVar() self.replaceEntry = Entry(self.replFrame, textvariable=self.replaceVar) self.replaceEntry.grid(row=8, column=2) self.replaceEntry.bind("", lambda x: self.helpDispVar.set("Enter text or number to find")) self.withTextVar = StringVar() self.withEntry = Entry(self.replFrame, textvariable=self.withTextVar) self.withEntry.grid(row=9, column=2) self.withEntry.bind("", lambda x: self.helpDispVar.set("Enter text or number to insert, or insert the mean")) self.withRadioVar = StringVar() self.withStrRadio = Radiobutton(self.replFrame, text="--->", variable=self.withRadioVar, value="String") self.withStrRadio.grid(row=9, column=1) self.withStrRadio.bind("", lambda x: self.helpDispVar.set("Enter text or number to find")) self.withMeanRadio = Radiobutton(self.replFrame, text="Mean", variable=self.withRadioVar, value="Mean") self.withMeanRadio.grid(row=10, column=1) self.withMeanRadio.bind("", lambda x: self.helpDispVar.set("Replace values with the mean")) self.withRadioVar.set("String") self.inA = Button(self.replFrame, text="In A", command = lambda:self.repl(self.replaceVar.get(), self.withTextVar.get(), self.aStringVar.get(), "A")) self.inA.grid(row=11) self.inA.bind("", lambda x: self.helpDispVar.set("Perform replacement in variable A")) self.inB = Button(self.replFrame, text="In B", command = lambda:self.repl(self.replaceVar.get(), self.withTextVar.get(), self.bStringVar.get(), "B")) self.inB.grid(row=11, column=1) self.inB.bind("", lambda x: self.helpDispVar.set("Perform replacement in variable B")) self.inMany = Button(self.replFrame, text="In Many (Use Listbox)", command=lambda:self.replMany(self.replaceVar.get(), self.withTextVar.get() ) ) self.inMany.grid(row=11, column=2) self.inMany.bind("", lambda x: self.helpDispVar.set("Perform replacement in all variables selected in the listbox")) self.replFrame.grid(row=r, column=c, rowspan=4, columnspan = 4, sticky="NSEW") def drawQuantHist(self, r, c): # (1, 3) self.quantHistFrame = Frame(self) self.quantHistFrame["bd"] = 2 self.quantHistFrame["relief"] = GROOVE self.quantHistCheck = BooleanVar() self.quantHistQ = Checkbutton(self.quantHistFrame, text="Quantize Histograms?", variable=self.quantHistCheck) self.quantHistLbl = Label(self.quantHistFrame, text="Step Size:") self.quantHistStepVal = IntVar() self.quantHistStep = Entry(self.quantHistFrame, textvariable=self.quantHistStepVal, width=5) self.quantHistStepVal.set(1) self.quantHistQ.grid(row=2, column=1, columnspan=2) self.quantHistQ.bind("", lambda x: self.helpDispVar.set("Quantize any histograms displayed?")) self.quantHistLbl.grid(row=3, column=1) self.quantHistLbl.bind("", lambda x: self.helpDispVar.set("Quantize any histograms displayed?")) self.quantHistStep.grid(row=3, column=2) self.quantHistStep.bind("", lambda x: self.helpDispVar.set("The size of the step to quantize the histogram into.")) self.quantHistFrame.grid(row=r, column=c, rowspan=2) def copy(self, x, y): if (y != ""): if (self.vars.has_key(y)): print("Var to copy to already exists; cancelling operation.") #FIXME: This should inform the user of failure better self.helpDispVar.set("Var to copy to already exists; cancelling operation.") else: if (self.vars.has_key(x)): self.vars[y] = self.vars[x][:] self.pullDownA.addOption(y, self.aStringVar) self.pullDownB.addOption(y, self.bStringVar) self.lb.insert(END, y) self.lb["height"] = self.lb["height"] + 1 else: print("Var to copy from not found") # FIXME: Do something to inform the user properly return 1 def deleteVar(self, x): del self.vars[x] if (self.A.name.get() == x): tmp = self.vars.keys() tmp.sort() self.A.set(tmp[0], self.vars[tmp[0]]) self.aStringVar.set(tmp[0]) if (self.B.name.get() == x): tmp = self.vars.keys() tmp.sort() self.B.set(tmp[0], self.vars[tmp[0]]) self.bStringVar.set(tmp[0]) self.pullDownA.delvar(x) self.pullDownB.delvar(x) for i in range(0, self.lb.size()): if (self.lb.get(i) == x): self.lb.delete(i) self.lb["height"] = self.lb["height"] - 1 return 1 def replMany(self, string, value2): items = map(int, self.lb.curselection()) for item in items: self.repl(string, value2, self.lb.get(item), "Listbox") self.pullDownAcb(self.aStringVar.get()) self.pullDownBcb(self.bStringVar.get()) def repl(self, string, value2, varname, which): value = value2 if (self.withRadioVar.get() == "Mean"): value = mean(self.vars[varname]) if isNumeric(value2): value = float(value2) if isNumeric(string): self.vars[varname] = oneStrSubst(self.vars[varname], float(string), value) self.vars[varname] = oneStrSubst(self.vars[varname], string, value) if (which == "A"): self.pullDownAcb(varname) elif (which == "B"): self.pullDownBcb(varname) return 1 def pullDownAcb(self, x): self.A.set(self.aStringVar.get(), self.vars[self.aStringVar.get()]) self.pearsonsDisp["text"] = PearsonCorrelation(zeroSubst(self.A.list), zeroSubst(self.B.list)) self.deleteA["text"] = "Delete " + self.aStringVar.get() self.copyButton["text"] = "Copy " + self.aStringVar.get() self.renameA["text"] = "Rename " + self.aStringVar.get() return 1 def pullDownBcb(self, x): self.B.set(self.bStringVar.get(), self.vars[self.bStringVar.get()]) self.pearsonsDisp["text"] = PearsonCorrelation(zeroSubst(self.A.list), zeroSubst(self.B.list)) return 1 def createWidgets(self, L=[]): self.createHelpDisplay(1080) self.vars = {} self.aStringVar = StringVar() self.aStringVar.set(L[0][0]) self.pullDownA = myOptionMenu(self, self.aStringVar, L[0][0], command=self.pullDownAcb) self.bStringVar = StringVar() self.bStringVar.set(L[0][0]) self.pullDownB = myOptionMenu(self, self.bStringVar, L[0][0], command=self.pullDownBcb) self.A = FloatVar(L[0][0], L[0][1:]) self.B = FloatVar(L[0][0], L[0][1:]) self.createLabels(0, 1) self.createReplaceFrame(3, 2) self.createVarEditors(3, 1) self.drawScatterControls(3, 0) self.drawCorrelationFrame(1, 0) self.createSumFrame(8, 3) self.drawQuantHist(1, 3) self.lb = Listbox(self.SumFrame) self.lb["selectmode"] = EXTENDED self.lb["height"] = len(L) self.histButtonA = Button(self, text="Histogram (A)", command=lambda: drawHistogram(self.A.list, self.A.name.get(), self.quantHistCheck.get(), self.quantHistStepVal.get())) self.histButtonB = Button(self, text="Histogram (B)", command=lambda: drawHistogram(self.B.list, self.B.name.get(), self.quantHistCheck.get(), self.quantHistStepVal.get())) self.histButtonA.grid(row=2, column=1, columnspan=1) self.histButtonA.bind("", lambda x: self.helpDispVar.set("Draw a histogram of the variable selected in A using Gnuplot")) self.histButtonB.grid(row=2, column=2, columnspan=1) self.histButtonB.bind("", lambda x: self.helpDispVar.set("Draw a histogram of the variable selected in B using Gnuplot")) self.lb.insert(END, str(L[0][0])) self.vars[L[0][0]] = L[0][1:] for i in range(1, len(L)): variable = L[i] self.lb.insert(END, str(variable[0])) self.pullDownA.addOption(str(variable[0]), self.aStringVar) self.pullDownB.addOption(str(variable[0]), self.bStringVar) self.vars[variable[0]] = variable[1:] # Build a dictionary of variables - remember that the list retains its order. # At this point, stop using L! It's no longer relevant since we have self.vars instead. self.pullDownA.grid(row=1, column=1, sticky="EW") self.pullDownA.bind("", lambda x: self.helpDispVar.set("Select Variable A")) self.pullDownB.grid(row=1, column=2, sticky="EW") self.pullDownB.bind("", lambda x: self.helpDispVar.set("Select Variable B")) self.lb.grid(row=7, column=0, sticky="NSEW") def __init__(self, lists, master=None): Frame.__init__(self, master) self.grid() self.createWidgets(lists)