From 2b393926a666228c9ba2d9bc3268f6e177fa0ce2 Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 26 Feb 2020 20:53:03 -0800 Subject: [PATCH 01/14] Progress with angular corridor. --- SearchStrategyAnalysis/Pathfinder.py | 67 +++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index a27b79e..9b380d0 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -547,6 +547,7 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window mazeX, mazeY = mazeCentreStringVar.get().split(",") mazeCentre = [float(mazeX), float(mazeY)] + startX, startY = 200, 200+scale*radius goalX, goalY = goalPosStringVar.get().split(",") goalCentre = [200 + (float(goalX)) - mazeCentre[0], 200 - (float(goalY)) + mazeCentre[1]] goalLBorder = goalCentre[0] - scale * (float(goalDiamStringVar.get()) / 2) @@ -572,11 +573,42 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) + aArcTangent = math.degrees(math.atan((goalCentre[0] - startY) / (goalCentre[1]+0.000000001 - startX))) + if (aArcTangent < 0): aArcTangent += 360 + upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 + lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 + + p, q = goalCentre[0] , goalCentre[1] + r = radius*scale + + m1 = math.tan(math.radians(upperCorridor)) + c1 = startY - m1 * startX + A1 = m1 ** 2 + 1 + B1 = 2 * (m1 * c1 - m1 * q - p) + C1 = q ** 2 - r ** 2 + p ** 2 - 2 * c1 * q + c1 ** 2 + det = B1 ** 2 - 4 * A1 * C1 + + endX1 = (-B1 + math.sqrt(det)) / 2 * A1 + endY1 = m1 * endX1 + c1 + + m2 = math.tan(math.radians(lowerCorridor)) + c2 = startY - m2 * startX + A2 = m2 ** 2 + 1 + B2 = 2 * (m2 * c2 - m2 * q - p) + C2 = q ** 2 - r ** 2 + p ** 2 - 2 * c2 * q + c2 ** 2 + det = B2 ** 2 - 4 * A2 * C2 + + endX2 = (-B2 + math.sqrt(det)) / 2 * A2 + endY2 = m2 * endX2 + c2 + + self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) + self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, endY2, fill="blue", width=2) + self.centerLine = canvas.create_line(200, 200 + scale * radius, 200, 200 - scale * radius, dash=(1, 1)) self.centerLine = canvas.create_line(200 - scale * radius, 200, 200 + scale * radius, 200, dash=(1, 1)) + self.centerToGoalLine = canvas.create_line(200, 200 + scale * radius, goalCentre[0], goalCentre[1], fill="red") self.start = canvas.create_oval(195, 195 + scale * radius, 205, 205 + scale * radius, fill="green", width=1) self.goal = canvas.create_oval(goalLBorder, goalTopBorder, goalRBorder, goalBottomBorder, fill="red", width=1) - self.centerToGoalLine = canvas.create_line(200, 200 + scale * radius, goalCentre[0], goalCentre[1], fill="red") # draw all rois for aTuple in rois: @@ -623,11 +655,42 @@ def redraw(*args): self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) + aArcTangent = math.degrees(math.atan((goalCentre[0] - startY) / (goalCentre[1] + 0.000000001 - startX))) + if (aArcTangent < 0): aArcTangent += 360 + upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 + lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 + + p, q = goalCentre[0], goalCentre[1] + r = radius * scale + + m1 = math.tan(math.radians(upperCorridor)) + c1 = startY - m1 * startX + A1 = m1 ** 2 + 1 + B1 = 2 * (m1 * c1 - m1 * q - p) + C1 = q ** 2 - r ** 2 + p ** 2 - 2 * c1 * q + c1 ** 2 + det = B1 ** 2 - 4 * A1 * C1 + + endX1 = (-B1 + math.sqrt(det)) / 2 * A1 + endY1 = m1 * endX1 + c1 + + m2 = math.tan(math.radians(lowerCorridor)) + c2 = startY - m2 * startX + A2 = m2 ** 2 + 1 + B2 = 2 * (m2 * c2 - m2 * q - p) + C2 = q ** 2 - r ** 2 + p ** 2 - 2 * c2 * q + c2 ** 2 + det = B2 ** 2 - 4 * A2 * C2 + + endX2 = (-B2 + math.sqrt(det)) / 2 * A2 + endY2 = m2 * endX2 + c2 + + self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) + self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, endY2, fill="blue", width=2) + self.centerLine = canvas.create_line(200, 200 + scale*radius, 200, 200 - scale*radius, dash=(1, 1)) self.centerLine = canvas.create_line(200 - scale*radius, 200, 200 + scale*radius, 200, dash=(1, 1)) + self.centerToGoalLine = canvas.create_line(200, 200 + scale*radius, goalCentre[0], goalCentre[1], fill="red") self.start = canvas.create_oval(195, 195 + scale*radius, 205, 205 + scale*radius, fill="green", width=1) self.goal = canvas.create_oval(goalLBorder, goalTopBorder, goalRBorder, goalBottomBorder, fill="red", width=1) - self.centerToGoalLine = canvas.create_line(200, 200 + scale*radius, goalCentre[0], goalCentre[1], fill="red") # draw all rois for aTuple in rois: From b56c8137edf81e32cf6fe8abb3b8769956b5c944 Mon Sep 17 00:00:00 2001 From: rickyma Date: Sun, 1 Mar 2020 16:11:02 -0800 Subject: [PATCH 02/14] Angular corridor working with goal at (0,0) --- SearchStrategyAnalysis/Pathfinder.py | 44 +++++++++------------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 9b380d0..66c7018 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -573,33 +573,25 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - aArcTangent = math.degrees(math.atan((goalCentre[0] - startY) / (goalCentre[1]+0.000000001 - startX))) + aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX - goalCentre[1]+0.000000001))) if (aArcTangent < 0): aArcTangent += 360 upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 + if (upperCorridor < 0): upperCorridor += 360 lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 + if (lowerCorridor < 0): lowerCorridor += 360 p, q = goalCentre[0] , goalCentre[1] r = radius*scale m1 = math.tan(math.radians(upperCorridor)) c1 = startY - m1 * startX - A1 = m1 ** 2 + 1 - B1 = 2 * (m1 * c1 - m1 * q - p) - C1 = q ** 2 - r ** 2 + p ** 2 - 2 * c1 * q + c1 ** 2 - det = B1 ** 2 - 4 * A1 * C1 - - endX1 = (-B1 + math.sqrt(det)) / 2 * A1 - endY1 = m1 * endX1 + c1 + endX1 = -c1/m1 + endY1 = 0 m2 = math.tan(math.radians(lowerCorridor)) c2 = startY - m2 * startX - A2 = m2 ** 2 + 1 - B2 = 2 * (m2 * c2 - m2 * q - p) - C2 = q ** 2 - r ** 2 + p ** 2 - 2 * c2 * q + c2 ** 2 - det = B2 ** 2 - 4 * A2 * C2 - - endX2 = (-B2 + math.sqrt(det)) / 2 * A2 - endY2 = m2 * endX2 + c2 + endX2 = -c2/m2 + endY2 = 0 self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, endY2, fill="blue", width=2) @@ -655,33 +647,25 @@ def redraw(*args): self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - aArcTangent = math.degrees(math.atan((goalCentre[0] - startY) / (goalCentre[1] + 0.000000001 - startX))) + aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX - goalCentre[1] + 0.000000001))) if (aArcTangent < 0): aArcTangent += 360 upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 + if (upperCorridor < 0): upperCorridor += 360 lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 + if (lowerCorridor < 0): lowerCorridor += 360 p, q = goalCentre[0], goalCentre[1] r = radius * scale m1 = math.tan(math.radians(upperCorridor)) c1 = startY - m1 * startX - A1 = m1 ** 2 + 1 - B1 = 2 * (m1 * c1 - m1 * q - p) - C1 = q ** 2 - r ** 2 + p ** 2 - 2 * c1 * q + c1 ** 2 - det = B1 ** 2 - 4 * A1 * C1 - - endX1 = (-B1 + math.sqrt(det)) / 2 * A1 - endY1 = m1 * endX1 + c1 + endX1 = -c1 / m1 + endY1 = 0 m2 = math.tan(math.radians(lowerCorridor)) c2 = startY - m2 * startX - A2 = m2 ** 2 + 1 - B2 = 2 * (m2 * c2 - m2 * q - p) - C2 = q ** 2 - r ** 2 + p ** 2 - 2 * c2 * q + c2 ** 2 - det = B2 ** 2 - 4 * A2 * C2 - - endX2 = (-B2 + math.sqrt(det)) / 2 * A2 - endY2 = m2 * endX2 + c2 + endX2 = -c2 / m2 + endY2 = 0 self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, endY2, fill="blue", width=2) From 32b57b05a30191966c16e22c4aafdba912ab6b6e Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 4 Mar 2020 17:36:30 -0800 Subject: [PATCH 03/14] Added semi-colon support, calculate for custom filetypes --- SearchStrategyAnalysis/Pathfinder.py | 56 ++++++++++--------- SearchStrategyAnalysis/appTrial.py | 82 ++++++++++++++++++++++------ 2 files changed, 94 insertions(+), 44 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 2fd18f9..d7cf267 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -159,6 +159,8 @@ chainingRadiusStringVar.set(chainingRadiusVar) thigmotaxisZoneSizeStringVar = StringVar() thigmotaxisZoneSizeStringVar.set(thigmotaxisZoneSizeVar) +softwareStringVar = StringVar() +softwareStringVar.set("") softwareScalingFactorStringVar = StringVar() softwareScalingFactorStringVar.set("1.0") outputFileStringVar = StringVar() @@ -332,7 +334,7 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window value="eztrack", indicatoron=1, width=15, bg="white") self.eztrackRadio.grid(row=rowCount, column=4, padx=5, sticky='NW') - self.defineRadio = Radiobutton(self.softwareBar, text="Define", variable=softwareStringVar, value="define", + self.defineRadio = Radiobutton(self.softwareBar, text="Define", variable=softwareStringVar, value="custom", indicatoron=0, width=15, bg="white", command=self.callDefineOwnSoftware) self.defineRadio.grid(row=rowCount, column=5, padx=5, sticky='NW') self.softwareBar.pack(side=TOP, fill=X, pady=5) @@ -573,24 +575,23 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX - goalCentre[1]+0.000000001))) - if (aArcTangent < 0): aArcTangent += 360 + if (startX - goalCentre[1] == 0): + aArcTangent = 270 + else: + aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) + # aArcTangent = math.degrees(math.atan2(startY - goalCentre[0], startX - goalCentre[1])) + upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 - if (upperCorridor < 0): upperCorridor += 360 lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 - if (lowerCorridor < 0): lowerCorridor += 360 - - p, q = goalCentre[0] , goalCentre[1] - r = radius*scale m1 = math.tan(math.radians(upperCorridor)) c1 = startY - m1 * startX - endX1 = -c1/m1 + endX1 = -c1 / m1 endY1 = 0 m2 = math.tan(math.radians(lowerCorridor)) c2 = startY - m2 * startX - endX2 = -c2/m2 + endX2 = -c2 / m2 endY2 = 0 self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) @@ -647,15 +648,18 @@ def redraw(*args): self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX - goalCentre[1] + 0.000000001))) - if (aArcTangent < 0): aArcTangent += 360 + if (startX - goalCentre[0] == 0): + aArcTangent = 270 + else: + aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) + # if (goalCentre[0] > 200 and goalCentre[1] < 200): + # aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX + goalCentre[1]))) + # else: + # aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX - goalCentre[1]))) + # aArcTangent = math.degrees(math.atan2(-(startY - goalCentre[0]), startX - goalCentre[1])) + upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 - if (upperCorridor < 0): upperCorridor += 360 lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 - if (lowerCorridor < 0): lowerCorridor += 360 - - p, q = goalCentre[0], goalCentre[1] - r = radius * scale m1 = math.tan(math.radians(upperCorridor)) c1 = startY - m1 * startX @@ -753,7 +757,6 @@ def generateHeatmap(self, root): global fileDirectory global theFile software = softwareStringVar.get() - experiment = saveFileAsExperiment(software, theFile, fileDirectory) self.guiHeatmap(experiment) @@ -1416,8 +1419,8 @@ def find_files(self, directory, pattern): # searches for our files in the direc yield filename def callDefineOwnSoftware(self): - messagebox.showinfo(None, "Please select a sample input file") defineOwnSoftware(root) + softwareStringVar.set("custom") self.defineRadio['state'] = 'active' self.calculateButton['state'] = 'normal' @@ -2266,7 +2269,7 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): skipFlag = False software = softwareStringVar.get() if (software == "auto"): - detectSoftwareType(self) + self.detectSoftwareType() software = softwareStringVar.get() try: @@ -2524,19 +2527,18 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): focalSearchCount, "| Indirect Search: ", indirectSearchCount, "| Semi-focal Search: ", semifocalSearchCount, "| Chaining: ", chainingCount, "| Scanning: ", scanningCount, "| Random Search: ", randomCount, "| Thigmotaxis: ", thigmotaxisCount, "| Not Recognized: ", notRecognizedCount) - if sys.platform.startswith('darwin'): - subprocess.call(('open', currentOutputFile)) - elif os.name == 'nt': # For Windows - os.startfile(currentOutputFile) - elif os.name == 'posix': # For Linux, Mac, etc. - subprocess.call(('xdg-open', currentOutputFile)) + # if sys.platform.startswith('darwin'): + # subprocess.call(('open', currentOutputFile)) + # elif os.name == 'nt': # For Windows + # os.startfile(currentOutputFile) + # elif os.name == 'posix': # For Linux, Mac, etc. + # subprocess.call(('xdg-open', currentOutputFile)) self.updateTasks() theStatus.set('') self.updateTasks() csvfilename = "output/results/results " + str(strftime("%Y_%m_%d %I_%M_%S_%p", localtime())) # update the csv file name for the next run outputFileStringVar.set(csvfilename) - return diff --git a/SearchStrategyAnalysis/appTrial.py b/SearchStrategyAnalysis/appTrial.py index 7232fab..e8a808c 100644 --- a/SearchStrategyAnalysis/appTrial.py +++ b/SearchStrategyAnalysis/appTrial.py @@ -173,8 +173,8 @@ def openFile(): # opens a dialog to get a single file return theFile -global xyt -xyt = [] +global customxyt +customxyt = [] def defineOwnSoftware(root): @@ -208,14 +208,15 @@ def defineOwnSoftware(root): status = Label(frame, textvariable=theStatus, width=50, height=2, relief=SUNKEN, anchor=W, bg="white") status.grid(row=0, column=0, columnspan=4) - global xyt + global customxyt def okButton(): - if (len(xyt) == 3): + if (len(customxyt) == 3): top.attributes('-topmost', False) - messagebox.showinfo(None, "First X value: " + str(xyt[0]) - + "\nFirst Y value: " + str(xyt[1]) - + "\nFirst time value: " + str(xyt[2])) + messagebox.showinfo(None, "First X value: " + str(customxyt[0]) + + "\nFirst Y value: " + str(customxyt[1]) + + "\nFirst time value: " + str(customxyt[2])) + top.quit() top.destroy() else: @@ -224,8 +225,8 @@ def okButton(): top.attributes('-topmost', True) def resetButton(): - global xyt - xyt = [] + global customxyt + customxyt = [] theStatus.set("[First X, Y, time values]: ") def displayTable(data): @@ -245,13 +246,15 @@ def displayTable(data): def getXYT(event): info = event.widget.grid_info() coord = (info["column"], info["row"]-1) - xyt.append(coord) - theStatus.set("[First X, Y, time values]: " + str(xyt)) + customxyt.append(coord) + theStatus.set("[First X, Y, time values]: " + str(customxyt)) + # display table if (file_extension == '.csv'): - # display csv as table with open(filename, newline="") as file: - data = csv.reader(file) + dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") + file.seek(0) + data = csv.reader(file, dialect) displayTable(data) elif (file_extension == '.xlsx'): data = pd.read_excel(filename) @@ -272,6 +275,7 @@ def saveFileAsExperiment(software, filename, filedirectory): trialList = [] filenameList = [] experiment = Experiment(filename) + dialect = "" if filename == "": if filedirectory == "": logging.error("No files selected") @@ -288,7 +292,11 @@ def saveFileAsExperiment(software, filename, filedirectory): filenameList.append(filename) for filename in filenameList: - + file_extension = os.path.splitext(filename)[1] + if software != "ethovision" and file_extension == '.csv': + with open(filename, newline="") as file: + dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") + file.seek(0) if software == "ethovision": logging.info("Reading file ethovision") experiment.setHasAnimalNames(True) @@ -354,7 +362,7 @@ def saveFileAsExperiment(software, filename, filedirectory): traceback.print_exc() logging.info("Could not open " + filename) return - reader = csv.reader(f, delimiter=",") + reader = csv.reader(f, dialect) next(reader) for row in reader: for (i, v) in enumerate(row): @@ -392,7 +400,7 @@ def saveFileAsExperiment(software, filename, filedirectory): logging.info("Could not open " + filename) return - reader = csv.reader(f, delimiter=",") + reader = csv.reader(f, dialect) for row in reader: for (i, v) in enumerate(row): columns[i].append(v) @@ -440,7 +448,7 @@ def saveFileAsExperiment(software, filename, filedirectory): logging.info("Could not open " + filename) return - reader = csv.reader(f, delimiter=",") + reader = csv.reader(f, dialect) listReader = list(reader) aTrial = Trial() aTrial.setname(filename.split("/")[-1]) @@ -472,6 +480,46 @@ def saveFileAsExperiment(software, filename, filedirectory): trialList.append(aTrial) + elif software == "custom": + logging.info("Reading file custom") + experiment.setHasAnimalNames(False) + experiment.setHasDateInfo(False) + experiment.setHasTrialNames(False) + try: + f = open(filename) + except: + logging.info("Could not open " + filename) + return + + file_extension = os.path.splitext(filename)[1] + if (file_extension == '.csv'): + reader = csv.reader(f, dialect) + elif (file_extension == '.xlsx'): + reader = pd.read_excel(filename) + + listReader = list(reader) + aTrial = Trial() + aTrial.setname(filename.split("/")[-1]) + columns = defaultdict(list) # each value in each column is appended to a list + aIndex = 0 + firstX = list(customxyt[0]) + firstY = list(customxyt[1]) + firstT = list(customxyt[2]) + + for x, y, t in zip(listReader[firstX[1]:][firstX[0]], listReader[firstY[1]:][firstY[0]], listReader[firstT[1]:][firstT[0]]): + try: + hours = float(t.split(':')[0]) + minutes = float(t.split(':')[1]) + seconds = float(t.split(':')[2]) + time = seconds + minutes * 60 + hours * 3600 + x = float(x) + y = float(y) + print(time,x,y) + aTrial.append(Datapoint(time, x, y)) + except: + aTrial.markDataAsCorrupted() + trialList.append(aTrial) + else: logging.critical("Could not determine trial, saveFileAsTrial") return From d7c74d033e835a2f72b7482cf73a7d1136d10718 Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 4 Mar 2020 17:50:06 -0800 Subject: [PATCH 04/14] Fixed scaling for corridor --- SearchStrategyAnalysis/Pathfinder.py | 36 +++++++--------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index d7cf267..0337c23 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -575,27 +575,20 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - if (startX - goalCentre[1] == 0): - aArcTangent = 270 - else: - aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) - # aArcTangent = math.degrees(math.atan2(startY - goalCentre[0], startX - goalCentre[1])) - + if (startX - goalCentre[1] == 0): aArcTangent = 270 + else: aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 m1 = math.tan(math.radians(upperCorridor)) c1 = startY - m1 * startX endX1 = -c1 / m1 - endY1 = 0 - m2 = math.tan(math.radians(lowerCorridor)) c2 = startY - m2 * startX endX2 = -c2 / m2 - endY2 = 0 - self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) - self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, endY2, fill="blue", width=2) + self.upperCorridorLine = canvas.create_line(startX, startY, endX1, 0, fill="blue", width=2) + self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, 0, fill="blue", width=2) self.centerLine = canvas.create_line(200, 200 + scale * radius, 200, 200 - scale * radius, dash=(1, 1)) self.centerLine = canvas.create_line(200 - scale * radius, 200, 200 + scale * radius, 200, dash=(1, 1)) @@ -624,7 +617,7 @@ def redraw(*args): mazeX, mazeY = mazeCentreStringVar.get().split(",") mazeCentre = [float(mazeX), float(mazeY)] - + startX, startY = 200, 200 + scale * radius goalX, goalY = goalPosStringVar.get().split(",") goalCentre = [200 + (float(goalX)) - mazeCentre[0], 200 - (float(goalY)) + mazeCentre[1]] goalLBorder = goalCentre[0] - scale * (float(goalDiamStringVar.get()) / 2) @@ -648,31 +641,20 @@ def redraw(*args): self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - if (startX - goalCentre[0] == 0): - aArcTangent = 270 - else: - aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) - # if (goalCentre[0] > 200 and goalCentre[1] < 200): - # aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX + goalCentre[1]))) - # else: - # aArcTangent = math.degrees(math.atan((startY - goalCentre[0]) / (startX - goalCentre[1]))) - # aArcTangent = math.degrees(math.atan2(-(startY - goalCentre[0]), startX - goalCentre[1])) - + if (startX - goalCentre[1] == 0): aArcTangent = 270 + else: aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 m1 = math.tan(math.radians(upperCorridor)) c1 = startY - m1 * startX endX1 = -c1 / m1 - endY1 = 0 - m2 = math.tan(math.radians(lowerCorridor)) c2 = startY - m2 * startX endX2 = -c2 / m2 - endY2 = 0 - self.upperCorridorLine = canvas.create_line(startX, startY, endX1, endY1, fill="blue", width=2) - self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, endY2, fill="blue", width=2) + self.upperCorridorLine = canvas.create_line(startX, startY, endX1, 0, fill="blue", width=2) + self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, 0, fill="blue", width=2) self.centerLine = canvas.create_line(200, 200 + scale*radius, 200, 200 - scale*radius, dash=(1, 1)) self.centerLine = canvas.create_line(200 - scale*radius, 200, 200 + scale*radius, 200, dash=(1, 1)) From 458661a7cdd3b526606fe72bc4b1cfd3f6172161 Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 4 Mar 2020 18:28:23 -0800 Subject: [PATCH 05/14] Simplified define function to also load file --- SearchStrategyAnalysis/Pathfinder.py | 22 ++-- SearchStrategyAnalysis/appTrial.py | 170 +++++++++++++-------------- 2 files changed, 95 insertions(+), 97 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 0337c23..319286f 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -672,7 +672,6 @@ def redraw(*args): roiBottomBorder = roiCentre[1] + scale * float(aTuple[1]) / 2 self.roi = canvas.create_oval(roiLBorder, roiTopBorder, roiRBorder, roiBottomBorder, fill="red", width=1) except: - #print("INVALID VAR INPUT") pass goalDiamStringVar.trace_variable("w", redraw) @@ -694,8 +693,10 @@ def detectSoftwareType(self): ethovision = ['Number of header lines:'] file_extension = os.path.splitext(theFile)[1] if (file_extension == '.csv'): - with open(theFile, newline="") as file: - data = csv.reader(file) + with open(filename, newline="") as file: + dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") + file.seek(0) + data = csv.reader(file, dialect) twoRows = [row for idx, row in enumerate(data) if idx in (0, 1)] if (set(anymaze).issubset(twoRows[0])): softwareStringVar.set("anymaze") @@ -703,15 +704,16 @@ def detectSoftwareType(self): softwareStringVar.set("watermaze") if (set(eztrack).issubset(twoRows[0])): softwareStringVar.set("eztrack") + else: + softwareStringVar.set("custom") elif (file_extension == '.xlsx'): workbook = open_workbook(theFile) sheet = workbook.sheet_by_index(0) rowNames = sheet.col_values(0) if (set(ethovision).issubset(rowNames)): softwareStringVar.set("ethovision") - else: - self.callDefineOwnSoftware() - + else: + softwareStringVar.set("custom") def openFile(self): # opens a dialog to get a single file logging.debug("Open File...") @@ -722,7 +724,6 @@ def openFile(self): # opens a dialog to get a single file fileDirectory = "" theFile = filedialog.askopenfilename() # look for xlsx and xls files self.calculateButton['state'] = 'normal' - #self.detectSoftwareType() def openDir(self): # open dialog to get multiple files logging.debug("Open Dir...") @@ -1401,7 +1402,11 @@ def find_files(self, directory, pattern): # searches for our files in the direc yield filename def callDefineOwnSoftware(self): - defineOwnSoftware(root) + global theFile + if theFile == "": + logging.debug("Open File...") + theFile = filedialog.askopenfilename() + defineOwnSoftware(root, theFile) softwareStringVar.set("custom") self.defineRadio['state'] = 'active' self.calculateButton['state'] = 'normal' @@ -2509,6 +2514,7 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): focalSearchCount, "| Indirect Search: ", indirectSearchCount, "| Semi-focal Search: ", semifocalSearchCount, "| Chaining: ", chainingCount, "| Scanning: ", scanningCount, "| Random Search: ", randomCount, "| Thigmotaxis: ", thigmotaxisCount, "| Not Recognized: ", notRecognizedCount) + # TODO # if sys.platform.startswith('darwin'): # subprocess.call(('open', currentOutputFile)) # elif os.name == 'nt': # For Windows diff --git a/SearchStrategyAnalysis/appTrial.py b/SearchStrategyAnalysis/appTrial.py index e8a808c..071c564 100644 --- a/SearchStrategyAnalysis/appTrial.py +++ b/SearchStrategyAnalysis/appTrial.py @@ -172,103 +172,95 @@ def openFile(): # opens a dialog to get a single file theFile = filedialog.askopenfilename() return theFile - global customxyt customxyt = [] -def defineOwnSoftware(root): - filename = openFile() +def defineOwnSoftware(root, filename): file_extension = os.path.splitext(filename)[1] - if filename == "": - logging.error("Please select a file") - print("Please select a file") - return - else: - # main loop - top = Toplevel(root) - canvas = Canvas(top, borderwidth=0, width=800, height=600, bg="white") # we create the canvas - frame = Frame(canvas) # we place a frame in the canvas - frame.configure(bg="white") - xscrollbar = Scrollbar(top, orient=HORIZONTAL, command=canvas.xview) # we add a horizontal scroll bar - yscrollbar = Scrollbar(top, orient="vertical", command=canvas.yview) # vertical scroll bar - xscrollbar.pack(side=BOTTOM, fill=X) # we put the horizontal scroll bar on the bottom - yscrollbar.pack(side="right", fill="y") # put on right - - canvas.pack(side="left", fill="both", expand=True) # we pack in the canvas - canvas.create_window((4, 4), window=frame, anchor="nw") # we create the window for the results - canvas.configure(xscrollcommand=xscrollbar.set) - canvas.configure(yscrollcommand=yscrollbar.set) # we set the commands for the scroll bars - frame.bind("", lambda event, canvas=canvas: canvas.configure(scrollregion=canvas.bbox("all"))) - top.attributes('-topmost', True) - - # display selected XYT columns using a status bar - theStatus = StringVar() - theStatus.set("[First X, Y, time values]: ") - status = Label(frame, textvariable=theStatus, width=50, height=2, relief=SUNKEN, anchor=W, bg="white") - status.grid(row=0, column=0, columnspan=4) + top = Toplevel(root) + canvas = Canvas(top, borderwidth=0, width=800, height=600, bg="white") # we create the canvas + frame = Frame(canvas) # we place a frame in the canvas + frame.configure(bg="white") + xscrollbar = Scrollbar(top, orient=HORIZONTAL, command=canvas.xview) # we add a horizontal scroll bar + yscrollbar = Scrollbar(top, orient="vertical", command=canvas.yview) # vertical scroll bar + xscrollbar.pack(side=BOTTOM, fill=X) # we put the horizontal scroll bar on the bottom + yscrollbar.pack(side="right", fill="y") # put on right + + canvas.pack(side="left", fill="both", expand=True) # we pack in the canvas + canvas.create_window((4, 4), window=frame, anchor="nw") # we create the window for the results + canvas.configure(xscrollcommand=xscrollbar.set) + canvas.configure(yscrollcommand=yscrollbar.set) # we set the commands for the scroll bars + frame.bind("", lambda event, canvas=canvas: canvas.configure(scrollregion=canvas.bbox("all"))) + top.attributes('-topmost', True) + + # display selected XYT columns using a status bar + theStatus = StringVar() + theStatus.set("[First X, Y, time values]: ") + status = Label(frame, textvariable=theStatus, width=50, height=2, relief=SUNKEN, anchor=W, bg="white") + status.grid(row=0, column=0, columnspan=4) + + global customxyt + + def okButton(): + if (len(customxyt) == 3): + top.attributes('-topmost', False) + messagebox.showinfo(None, "First X value: " + str(customxyt[0]) + + "\nFirst Y value: " + str(customxyt[1]) + + "\nFirst time value: " + str(customxyt[2])) + + top.quit() + top.destroy() + else: + top.attributes('-topmost', False) + messagebox.showinfo(None, "Please select three columns!") + top.attributes('-topmost', True) + def resetButton(): global customxyt + customxyt = [] + theStatus.set("[First X, Y, time values]: ") - def okButton(): - if (len(customxyt) == 3): - top.attributes('-topmost', False) - messagebox.showinfo(None, "First X value: " + str(customxyt[0]) - + "\nFirst Y value: " + str(customxyt[1]) - + "\nFirst time value: " + str(customxyt[2])) - - top.quit() - top.destroy() - else: - top.attributes('-topmost', False) - messagebox.showinfo(None, "Please select three columns!") - top.attributes('-topmost', True) - - def resetButton(): - global customxyt - customxyt = [] - theStatus.set("[First X, Y, time values]: ") - - def displayTable(data): - r = 0 - for col in data: - c = 0 - for row in col: - coord = (r, c) - if (r < 100): - cell = Label(frame, width=12, height=1, text=row, borderwidth=2, relief="groove") - cell.grid(row=r + 1, column=c) - cell.bind("", lambda event: getXYT(event)) - c += 1 - r += 1 - - # gets column number from clicked column - def getXYT(event): - info = event.widget.grid_info() - coord = (info["column"], info["row"]-1) - customxyt.append(coord) - theStatus.set("[First X, Y, time values]: " + str(customxyt)) - - # display table - if (file_extension == '.csv'): - with open(filename, newline="") as file: - dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") - file.seek(0) - data = csv.reader(file, dialect) - displayTable(data) - elif (file_extension == '.xlsx'): - data = pd.read_excel(filename) - displayTable(data.values) - - okbutton = Button(frame, text="Save", width=12, height=2, command=okButton) - okbutton.grid(row=0, column=4) - resetbutton = Button(frame, text="Reset", width=12, height=2, command=resetButton) - resetbutton.grid(row=0, column=5) - - top.attributes('-topmost', False) - messagebox.showinfo(None, "Please select in order: first X value, first Y value, first time value.") - top.attributes('-topmost', True) - top.mainloop() + def displayTable(data): + r = 0 + for col in data: + c = 0 + for row in col: + coord = (r, c) + if (r < 100): + cell = Label(frame, width=12, height=1, text=row, borderwidth=2, relief="groove") + cell.grid(row=r + 1, column=c) + cell.bind("", lambda event: getXYT(event)) + c += 1 + r += 1 + + # gets column number from clicked column + def getXYT(event): + info = event.widget.grid_info() + coord = (info["column"], info["row"]-1) + customxyt.append(coord) + theStatus.set("[First X, Y, time values]: " + str(customxyt)) + + # display table + if (file_extension == '.csv'): + with open(filename, newline="") as file: + dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") + file.seek(0) + data = csv.reader(file, dialect) + displayTable(data) + elif (file_extension == '.xlsx'): + data = pd.read_excel(filename) + displayTable(data.values) + + okbutton = Button(frame, text="Save", width=12, height=2, command=okButton) + okbutton.grid(row=0, column=4) + resetbutton = Button(frame, text="Reset", width=12, height=2, command=resetButton) + resetbutton.grid(row=0, column=5) + + top.attributes('-topmost', False) + messagebox.showinfo(None, "Please select in order: first X value, first Y value, first time value.") + top.attributes('-topmost', True) + top.mainloop() def saveFileAsExperiment(software, filename, filedirectory): From d46edfbf71737ebb54a524b10870440c3f197ece Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 4 Mar 2020 20:26:24 -0800 Subject: [PATCH 06/14] Fixed calculate for custom software --- SearchStrategyAnalysis/Pathfinder.py | 9 +++------ SearchStrategyAnalysis/appTrial.py | 18 ++++++++---------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 319286f..9baae36 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -2087,9 +2087,6 @@ def calculateValues(self, theTrial, goalX, goalY, mazeCentreX, mazeCentreY, corr initialHeadingError = 0.0 initialHeadingErrorCount = 0 for aDatapoint in theTrial: # go back through all values and calculate distance to the centroid - # if dayNum == 9 or dayNum == 14: - # if aDatapoint.gettime() > probeCutVar: - # continue currentDistanceFromGoal = math.sqrt( (goalX - aDatapoint.getx()) ** 2 + (goalY - aDatapoint.gety()) ** 2) * scalingFactor distanceToSwimPathCentroid = math.sqrt( @@ -2373,11 +2370,11 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): quadrantThree = 0 quadrantFour = 0 quadrantTotal = 0 - # score = 0 # Analyze the data ---------------------------------------------------------------------------------------------- - - corridorAverage, distanceAverage, averageDistanceToSwimPathCentroid, averageDistanceToCentre, averageHeadingError, percentTraversed, quadrantTotal, totalDistance, latency, fullThigmoCounter, smallThigmoCounter, annulusCounter, i, arrayX, arrayY, velocity, ipe, initialHeadingError, entropyResult = self.calculateValues( + corridorAverage, distanceAverage, averageDistanceToSwimPathCentroid, averageDistanceToCentre, averageHeadingError, \ + percentTraversed, quadrantTotal, totalDistance, latency, fullThigmoCounter, smallThigmoCounter, annulusCounter, i, \ + arrayX, arrayY, velocity, ipe, initialHeadingError, entropyResult = self.calculateValues( aTrial, goalX, goalY, mazeCentreX, mazeCentreY, corridorWidth, thigmotaxisZoneSize, chainingRadius, fullThigmoZone, smallThigmoZone, scalingFactor, mazeRadius, dayNum, goalDiamVar) diff --git a/SearchStrategyAnalysis/appTrial.py b/SearchStrategyAnalysis/appTrial.py index 071c564..92c29a1 100644 --- a/SearchStrategyAnalysis/appTrial.py +++ b/SearchStrategyAnalysis/appTrial.py @@ -492,26 +492,24 @@ def saveFileAsExperiment(software, filename, filedirectory): listReader = list(reader) aTrial = Trial() aTrial.setname(filename.split("/")[-1]) - columns = defaultdict(list) # each value in each column is appended to a list aIndex = 0 - firstX = list(customxyt[0]) - firstY = list(customxyt[1]) - firstT = list(customxyt[2]) - - for x, y, t in zip(listReader[firstX[1]:][firstX[0]], listReader[firstY[1]:][firstY[0]], listReader[firstT[1]:][firstT[0]]): + xCol = customxyt[0][0] + yCol = customxyt[1][0] + tCol = customxyt[2][0] + for row in listReader[customxyt[0][0]:]: try: + x = float(row[xCol]) + y = float(row[yCol]) + t = row[tCol] hours = float(t.split(':')[0]) minutes = float(t.split(':')[1]) seconds = float(t.split(':')[2]) time = seconds + minutes * 60 + hours * 3600 - x = float(x) - y = float(y) - print(time,x,y) + print(time, x, y) aTrial.append(Datapoint(time, x, y)) except: aTrial.markDataAsCorrupted() trialList.append(aTrial) - else: logging.critical("Could not determine trial, saveFileAsTrial") return From 065f6bce7a1dbeadebe1cf3f7035d89376b7bffd Mon Sep 17 00:00:00 2001 From: rickyma Date: Thu, 12 Mar 2020 13:17:10 -0700 Subject: [PATCH 07/14] Latest update --- SearchStrategyAnalysis/Pathfinder.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 9baae36..8fcef3f 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -990,8 +990,13 @@ def settings(self): try: with open('customobjs.pickle', 'rb') as f: - ipeMaxVal, headingMaxVal, distanceToSwimMaxVal, distanceToPlatMaxVal, distanceToSwimMaxVal2, distanceToPlatMaxVal2, corridorAverageMinVal, directedSearchMaxDistance, focalMinDistance, focalMaxDistance, focalMinDistance2, focalMaxDistance2, corridoripeMaxVal, annulusCounterMaxVal, quadrantTotalMaxVal, chainingMaxCoverage, percentTraversedMaxVal, percentTraversedMinVal, distanceToCentreMaxVal, thigmoMinDistance, smallThigmoMinVal, fullThigmoMinVal, ipeIndirectMaxVal, percentTraversedRandomMaxVal, headingIndirectMaxVal, useDirectPathV, useFocalSearchV, useDirectedSearchV, useIndirectV, useFocalSearchV2, useScanningV, useChainingV, useRandomV, useThigmoV = pickle.load( - f) + ipeMaxVal, headingMaxVal, distanceToSwimMaxVal, distanceToPlatMaxVal, distanceToSwimMaxVal2, \ + distanceToPlatMaxVal2, corridorAverageMinVal, directedSearchMaxDistance, focalMinDistance, \ + focalMaxDistance, focalMinDistance2, focalMaxDistance2, corridoripeMaxVal, annulusCounterMaxVal, \ + quadrantTotalMaxVal, chainingMaxCoverage, percentTraversedMaxVal, percentTraversedMinVal, \ + distanceToCentreMaxVal, thigmoMinDistance, smallThigmoMinVal, fullThigmoMinVal, ipeIndirectMaxVal, \ + percentTraversedRandomMaxVal, headingIndirectMaxVal, useDirectPathV, useFocalSearchV, useDirectedSearchV, \ + useIndirectV, useFocalSearchV2, useScanningV, useChainingV, useRandomV, useThigmoV = pickle.load(f) params = Parameters(name="Custom", ipeMaxVal=float(ipeMaxVal), headingMaxVal=float(headingMaxVal), distanceToSwimMaxVal=float(distanceToSwimMaxVal), distanceToPlatMaxVal=float(distanceToPlatMaxVal), @@ -2521,8 +2526,7 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): self.updateTasks() theStatus.set('') self.updateTasks() - csvfilename = "output/results/results " + str(strftime("%Y_%m_%d %I_%M_%S_%p", - localtime())) # update the csv file name for the next run + csvfilename = "output/results/results " + str(strftime("%Y_%m_%d %I_%M_%S_%p", localtime())) # update the csv file name for the next run outputFileStringVar.set(csvfilename) return From 487809c9cbdb69c4c6099dfa6753fefd6130f272 Mon Sep 17 00:00:00 2001 From: rickyma Date: Sat, 14 Mar 2020 22:23:23 -0700 Subject: [PATCH 08/14] Added scrollbar to settings --- SearchStrategyAnalysis/Pathfinder.py | 163 ++++++++++++++------------- SearchStrategyAnalysis/appTrial.py | 2 - 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 8fcef3f..cdecdf6 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -1062,260 +1062,271 @@ def settings(self): self.top = Toplevel(root) # we set this to be the top self.top.configure(bg="white") - Label(self.top, text="Settings", bg="white", fg="red").grid(row=0, column=0, columnspan=2) # we title it + + canvas = Canvas(self.top, borderwidth=0, width=400, height=600, bg="white") # we create the canvas + frame = Frame(canvas) # we place a frame in the canvas + frame.configure(bg="white") + yscrollbar = Scrollbar(self.top, orient=VERTICAL, command=canvas.yview) # vertical scroll bar + yscrollbar.grid(row=0, column=2, sticky='ns') + + canvas.grid(row=0, column=0) # we pack in the canvas + canvas.create_window((4, 4), window=frame, anchor="nw") + canvas.configure(yscrollcommand=yscrollbar.set) # we set the commands for the scroll bars + frame.bind("", lambda event, canvas=canvas: canvas.configure(scrollregion=canvas.bbox("all"))) + + + + Label(frame, text="Settings", bg="white", fg="black").grid(row=0, column=0, columnspan=2, padx=100, pady=20) # we title it rowCount = 1 - useDirectPathL = Label(self.top, text="Direct Path: ", bg="white") # we add a direct path label + useDirectPathL = Label(frame, text="Direct Path: ", bg="white") # we add a direct path label useDirectPathL.grid(row=rowCount, column=0, sticky=E) # stick it to row 1 - useDirectPathC = Checkbutton(self.top, variable=self.useDirectPath, bg="white") # we add a direct path checkbox + useDirectPathC = Checkbutton(frame, variable=self.useDirectPath, bg="white") # we add a direct path checkbox useDirectPathC.grid(row=rowCount, column=1) # put it beside the label rowCount += 1 - jslsMaxCustomL = Label(self.top, text="Ideal Path Error [maximum]: ", bg="white") # label for JSLs + jslsMaxCustomL = Label(frame, text="Ideal Path Error [maximum]: ", bg="white") # label for JSLs jslsMaxCustomL.grid(row=rowCount, column=0, sticky=E) # row 2 - jslsMaxCustomE = Entry(self.top, textvariable=self.jslsMaxCustom) # entry field + jslsMaxCustomE = Entry(frame, textvariable=self.jslsMaxCustom) # entry field jslsMaxCustomE.grid(row=rowCount, column=1) # right beside rowCount += 1 - headingErrorCustomL = Label(self.top, text="Heading error [maximum, degrees]: ", bg="white") + headingErrorCustomL = Label(frame, text="Heading error [maximum, degrees]: ", bg="white") headingErrorCustomL.grid(row=rowCount, column=0, sticky=E) - headingErrorCustomE = Entry(self.top, textvariable=self.headingErrorCustom) + headingErrorCustomE = Entry(frame, textvariable=self.headingErrorCustom) headingErrorCustomE.grid(row=rowCount, column=1) rowCount += 1 - useFocalSearchL = Label(self.top, text="Focal Search: ", bg="white") + useFocalSearchL = Label(frame, text="Focal Search: ", bg="white") useFocalSearchL.grid(row=rowCount, column=0, sticky=E) - useFocalSearchC = Checkbutton(self.top, variable=self.useFocalSearch, bg="white") + useFocalSearchC = Checkbutton(frame, variable=self.useFocalSearch, bg="white") useFocalSearchC.grid(row=rowCount, column=1) rowCount += 1 - distanceToSwimCustomL = Label(self.top, text="Distance to swim path centroid [maximum, % of radius]: ", + distanceToSwimCustomL = Label(frame, text="Distance to swim path centroid [maximum, % of radius]: ", bg="white") distanceToSwimCustomL.grid(row=rowCount, column=0, sticky=E) - distanceToSwimCustomE = Entry(self.top, textvariable=self.distanceToSwimCustom) + distanceToSwimCustomE = Entry(frame, textvariable=self.distanceToSwimCustom) distanceToSwimCustomE.grid(row=rowCount, column=1) rowCount += 1 - distanceToPlatCustomL = Label(self.top, text="Distance to goal [maximum, % of radius]: ", bg="white") + distanceToPlatCustomL = Label(frame, text="Distance to goal [maximum, % of radius]: ", bg="white") distanceToPlatCustomL.grid(row=rowCount, column=0, sticky=E) - distanceToPlatCustomE = Entry(self.top, textvariable=self.distanceToPlatCustom) + distanceToPlatCustomE = Entry(frame, textvariable=self.distanceToPlatCustom) distanceToPlatCustomE.grid(row=rowCount, column=1) rowCount += 1 - focalMinDistanceCustomL = Label(self.top, text="Distance covered (minimum, cm): ", bg="white") + focalMinDistanceCustomL = Label(frame, text="Distance covered (minimum, cm): ", bg="white") focalMinDistanceCustomL.grid(row=rowCount, column=0, sticky=E) - focalMinDistanceCustomE = Entry(self.top, textvariable=self.focalMinDistanceCustom) + focalMinDistanceCustomE = Entry(frame, textvariable=self.focalMinDistanceCustom) focalMinDistanceCustomE.grid(row=rowCount, column=1) rowCount += 1 - focalMaxDistanceCustomL = Label(self.top, text="Distance covered (maximum, cm): ", bg="white") + focalMaxDistanceCustomL = Label(frame, text="Distance covered (maximum, cm): ", bg="white") focalMaxDistanceCustomL.grid(row=rowCount, column=0, sticky=E) - focalMaxDistanceCustomE = Entry(self.top, textvariable=self.focalMaxDistanceCustom) + focalMaxDistanceCustomE = Entry(frame, textvariable=self.focalMaxDistanceCustom) focalMaxDistanceCustomE.grid(row=rowCount, column=1) rowCount += 1 - useDirectedSearchL = Label(self.top, text="Directed Search: ", bg="white") + useDirectedSearchL = Label(frame, text="Directed Search: ", bg="white") useDirectedSearchL.grid(row=rowCount, column=0, sticky=E) - useDirectedSearchC = Checkbutton(self.top, variable=self.useDirectedSearch, bg="white", onvalue=1) + useDirectedSearchC = Checkbutton(frame, variable=self.useDirectedSearch, bg="white", onvalue=1) useDirectedSearchC.grid(row=rowCount, column=1) rowCount += 1 - corridorAverageCustomL = Label(self.top, text="Time in angular corridor [minimum, % of trial]: ", bg="white") + corridorAverageCustomL = Label(frame, text="Time in angular corridor [minimum, % of trial]: ", bg="white") corridorAverageCustomL.grid(row=rowCount, column=0, sticky=E) - corridorAverageCustomE = Entry(self.top, textvariable=self.corridorAverageCustom) + corridorAverageCustomE = Entry(frame, textvariable=self.corridorAverageCustom) corridorAverageCustomE.grid(row=rowCount, column=1) rowCount += 1 - directedSearchMaxDistanceCustomL = Label(self.top, text="Distance covered (maximum, cm): ", bg="white") + directedSearchMaxDistanceCustomL = Label(frame, text="Distance covered (maximum, cm): ", bg="white") directedSearchMaxDistanceCustomL.grid(row=rowCount, column=0, sticky=E) - directedSearchMaxDistanceCustomE = Entry(self.top, textvariable=self.directedSearchMaxDistanceCustom) + directedSearchMaxDistanceCustomE = Entry(frame, textvariable=self.directedSearchMaxDistanceCustom) directedSearchMaxDistanceCustomE.grid(row=rowCount, column=1) rowCount += 1 - corridorJslsCustomL = Label(self.top, text="Ideal Path Error [maximum]: ", bg="white") + corridorJslsCustomL = Label(frame, text="Ideal Path Error [maximum]: ", bg="white") corridorJslsCustomL.grid(row=rowCount, column=0, sticky=E) - corridorJslsCustomE = Entry(self.top, textvariable=self.corridorJslsCustom) + corridorJslsCustomE = Entry(frame, textvariable=self.corridorJslsCustom) corridorJslsCustomE.grid(row=rowCount, column=1) rowCount += 1 - useIndirectL = Label(self.top, text="Indirect Search: ", bg="white") + useIndirectL = Label(frame, text="Indirect Search: ", bg="white") useIndirectL.grid(row=rowCount, column=0, sticky=E) - useIndirectC = Checkbutton(self.top, variable=self.useIndirect, bg="white") + useIndirectC = Checkbutton(frame, variable=self.useIndirect, bg="white") useIndirectC.grid(row=rowCount, column=1) rowCount += 1 - jslsIndirectCustomL = Label(self.top, text="Ideal Path Error [maximum]: ", bg="white") + jslsIndirectCustomL = Label(frame, text="Ideal Path Error [maximum]: ", bg="white") jslsIndirectCustomL.grid(row=rowCount, column=0, sticky=E) - jslsIndirectCustomE = Entry(self.top, textvariable=self.jslsIndirectCustom) + jslsIndirectCustomE = Entry(frame, textvariable=self.jslsIndirectCustom) jslsIndirectCustomE.grid(row=rowCount, column=1) rowCount += 1 - headingIndirectCustomL = Label(self.top, text="Average Heading error [maximum]: ", bg="white") + headingIndirectCustomL = Label(frame, text="Average Heading error [maximum]: ", bg="white") headingIndirectCustomL.grid(row=rowCount, column=0, sticky=E) - headingIndirectCustomE = Entry(self.top, textvariable=self.headingIndirectCustom, bg="white") + headingIndirectCustomE = Entry(frame, textvariable=self.headingIndirectCustom, bg="white") headingIndirectCustomE.grid(row=rowCount, column=1) rowCount += 1 - useFocalSearchL2 = Label(self.top, text="Semi-focal Search: ", bg="white") + useFocalSearchL2 = Label(frame, text="Semi-focal Search: ", bg="white") useFocalSearchL2.grid(row=rowCount, column=0, sticky=E) - useFocalSearchC2 = Checkbutton(self.top, variable=self.useFocalSearch2, bg="white") + useFocalSearchC2 = Checkbutton(frame, variable=self.useFocalSearch2, bg="white") useFocalSearchC2.grid(row=rowCount, column=1) rowCount += 1 - distanceToSwimCustomL2 = Label(self.top, text="Distance to swim path centroid [maximum, % of radius]: ", + distanceToSwimCustomL2 = Label(frame, text="Distance to swim path centroid [maximum, % of radius]: ", bg="white") distanceToSwimCustomL2.grid(row=rowCount, column=0, sticky=E) - distanceToSwimCustomE2 = Entry(self.top, textvariable=self.distanceToSwimCustom2) + distanceToSwimCustomE2 = Entry(frame, textvariable=self.distanceToSwimCustom2) distanceToSwimCustomE2.grid(row=rowCount, column=1) rowCount += 1 - distanceToPlatCustomL2 = Label(self.top, text="Distance to goal [maximum, % of radius]: ", bg="white") + distanceToPlatCustomL2 = Label(frame, text="Distance to goal [maximum, % of radius]: ", bg="white") distanceToPlatCustomL2.grid(row=rowCount, column=0, sticky=E) - distanceToPlatCustomE2 = Entry(self.top, textvariable=self.distanceToPlatCustom2) + distanceToPlatCustomE2 = Entry(frame, textvariable=self.distanceToPlatCustom2) distanceToPlatCustomE2.grid(row=rowCount, column=1) rowCount += 1 - focalMinDistanceCustomL2 = Label(self.top, text="Distance covered (minimum, cm): ", bg="white") + focalMinDistanceCustomL2 = Label(frame, text="Distance covered (minimum, cm): ", bg="white") focalMinDistanceCustomL2.grid(row=rowCount, column=0, sticky=E) - focalMinDistanceCustomE2 = Entry(self.top, textvariable=self.focalMinDistanceCustom2) + focalMinDistanceCustomE2 = Entry(frame, textvariable=self.focalMinDistanceCustom2) focalMinDistanceCustomE2.grid(row=rowCount, column=1) rowCount += 1 - focalMaxDistanceCustomL2 = Label(self.top, text="Distance covered (maximum, cm): ", bg="white") + focalMaxDistanceCustomL2 = Label(frame, text="Distance covered (maximum, cm): ", bg="white") focalMaxDistanceCustomL2.grid(row=rowCount, column=0, sticky=E) - focalMaxDistanceCustomE2 = Entry(self.top, textvariable=self.focalMaxDistanceCustom2) + focalMaxDistanceCustomE2 = Entry(frame, textvariable=self.focalMaxDistanceCustom2) focalMaxDistanceCustomE2.grid(row=rowCount, column=1) rowCount += 1 - useChainingL = Label(self.top, text="Chaining: ", bg="white") + useChainingL = Label(frame, text="Chaining: ", bg="white") useChainingL.grid(row=rowCount, column=0, sticky=E) - useChainingC = Checkbutton(self.top, variable=self.useChaining, bg="white") + useChainingC = Checkbutton(frame, variable=self.useChaining, bg="white") useChainingC.grid(row=rowCount, column=1) rowCount += 1 - annulusCustomL = Label(self.top, text="Time in annulus zone [minimum, % of trial]: ", bg="white") + annulusCustomL = Label(frame, text="Time in annulus zone [minimum, % of trial]: ", bg="white") annulusCustomL.grid(row=rowCount, column=0, sticky=E) - annulusCustomE = Entry(self.top, textvariable=self.annulusCustom) + annulusCustomE = Entry(frame, textvariable=self.annulusCustom) annulusCustomE.grid(row=rowCount, column=1) rowCount += 1 - quadrantTotalCustomL = Label(self.top, text="Quadrants visited [minimum]: ", bg="white") + quadrantTotalCustomL = Label(frame, text="Quadrants visited [minimum]: ", bg="white") quadrantTotalCustomL.grid(row=rowCount, column=0, sticky=E) - quadrantTotalCustomE = Entry(self.top, textvariable=self.quadrantTotalCustom) + quadrantTotalCustomE = Entry(frame, textvariable=self.quadrantTotalCustom) quadrantTotalCustomE.grid(row=rowCount, column=1) rowCount += 1 - chainingMaxCoverageCustomL = Label(self.top, text="Area of maze traversed (maximum, % of maze): ", bg="white") + chainingMaxCoverageCustomL = Label(frame, text="Area of maze traversed (maximum, % of maze): ", bg="white") chainingMaxCoverageCustomL.grid(row=rowCount, column=0, sticky=E) - chainingMaxCoverageCustomE = Entry(self.top, textvariable=self.chainingMaxCoverageCustom) + chainingMaxCoverageCustomE = Entry(frame, textvariable=self.chainingMaxCoverageCustom) chainingMaxCoverageCustomE.grid(row=rowCount, column=1) rowCount += 1 - useScanningL = Label(self.top, text="Scanning: ", bg="white") + useScanningL = Label(frame, text="Scanning: ", bg="white") useScanningL.grid(row=rowCount, column=0, sticky=E) - useScanningC = Checkbutton(self.top, variable=self.useScanning, bg="white") + useScanningC = Checkbutton(frame, variable=self.useScanning, bg="white") useScanningC.grid(row=rowCount, column=1) rowCount += 1 - percentTraversedCustomL = Label(self.top, text="Area of maze traversed [maximum, % of maze]: ", bg="white") + percentTraversedCustomL = Label(frame, text="Area of maze traversed [maximum, % of maze]: ", bg="white") percentTraversedCustomL.grid(row=rowCount, column=0, sticky=E) - percentTraversedCustomE = Entry(self.top, textvariable=self.percentTraversedCustom) + percentTraversedCustomE = Entry(frame, textvariable=self.percentTraversedCustom) percentTraversedCustomE.grid(row=rowCount, column=1) rowCount += 1 - percentTraversedMinCustomL = Label(self.top, text="Area of maze traversed [minimum, % of maze]: ", bg="white") + percentTraversedMinCustomL = Label(frame, text="Area of maze traversed [minimum, % of maze]: ", bg="white") percentTraversedMinCustomL.grid(row=rowCount, column=0, sticky=E) - percentTraversedMinCustomE = Entry(self.top, textvariable=self.percentTraversedMinCustom) + percentTraversedMinCustomE = Entry(frame, textvariable=self.percentTraversedMinCustom) percentTraversedMinCustomE.grid(row=rowCount, column=1) rowCount += 1 - distanceToCentreCustomL = Label(self.top, text="Average distance to maze centre [maximum, % of radius]: ", + distanceToCentreCustomL = Label(frame, text="Average distance to maze centre [maximum, % of radius]: ", bg="white") distanceToCentreCustomL.grid(row=rowCount, column=0, sticky=E) - distanceToCentreCustomE = Entry(self.top, textvariable=self.distanceToCentreCustom) + distanceToCentreCustomE = Entry(frame, textvariable=self.distanceToCentreCustom) distanceToCentreCustomE.grid(row=rowCount, column=1) rowCount += 1 - useThigmoL = Label(self.top, text="Thigmotaxis: ", bg="white") + useThigmoL = Label(frame, text="Thigmotaxis: ", bg="white") useThigmoL.grid(row=rowCount, column=0, sticky=E) - useThigmoC = Checkbutton(self.top, variable=self.useThigmo, bg="white") + useThigmoC = Checkbutton(frame, variable=self.useThigmo, bg="white") useThigmoC.grid(row=rowCount, column=1) rowCount += 1 - fullThigmoCustomL = Label(self.top, text="Time in full thigmotaxis zone [minimum, % of trial]: ", bg="white") + fullThigmoCustomL = Label(frame, text="Time in full thigmotaxis zone [minimum, % of trial]: ", bg="white") fullThigmoCustomL.grid(row=rowCount, column=0, sticky=E) - fullThigmoCustomE = Entry(self.top, textvariable=self.fullThigmoCustom, bg="white") + fullThigmoCustomE = Entry(frame, textvariable=self.fullThigmoCustom, bg="white") fullThigmoCustomE.grid(row=rowCount, column=1) rowCount += 1 - smallThigmoCustomL = Label(self.top, text="Time in smaller thigmotaxis zone [minimum, % of trial]: ", - bg="white") + smallThigmoCustomL = Label(frame, text="Time in smaller thigmotaxis zone [minimum, % of trial]: ", bg="white") smallThigmoCustomL.grid(row=rowCount, column=0, sticky=E) - smallThigmoCustomE = Entry(self.top, textvariable=self.smallThigmoCustom) + smallThigmoCustomE = Entry(frame, textvariable=self.smallThigmoCustom) smallThigmoCustomE.grid(row=rowCount, column=1) rowCount += 1 - thigmoMinDistanceCustomL = Label(self.top, text="Total distance covered (minimum, cm): ", bg="white") + thigmoMinDistanceCustomL = Label(frame, text="Total distance covered (minimum, cm): ", bg="white") thigmoMinDistanceCustomL.grid(row=rowCount, column=0, sticky=E) - thigmoMinDistanceCustomE = Entry(self.top, textvariable=self.thigmoMinDistanceCustom, bg="white") + thigmoMinDistanceCustomE = Entry(frame, textvariable=self.thigmoMinDistanceCustom, bg="white") thigmoMinDistanceCustomE.grid(row=rowCount, column=1) rowCount += 1 - useRandomL = Label(self.top, text="Random Search: ", bg="white") + useRandomL = Label(frame, text="Random Search: ", bg="white") useRandomL.grid(row=rowCount, column=0, sticky=E) - useRandomC = Checkbutton(self.top, variable=self.useRandom, bg="white") + useRandomC = Checkbutton(frame, variable=self.useRandom, bg="white") useRandomC.grid(row=rowCount, column=1) rowCount += 1 - percentTraversedRandomCustomL = Label(self.top, text="Area of maze traversed [minimum, % of maze]: ", - bg="white") + percentTraversedRandomCustomL = Label(frame, text="Area of maze traversed [minimum, % of maze]: ", bg="white") percentTraversedRandomCustomL.grid(row=rowCount, column=0, sticky=E) - percentTraversedRandomCustomE = Entry(self.top, textvariable=self.percentTraversedRandomCustom) + percentTraversedRandomCustomE = Entry(frame, textvariable=self.percentTraversedRandomCustom) percentTraversedRandomCustomE.grid(row=rowCount, column=1) # we save the values from the fields and scale them appropriately rowCount += 1 - - Button(self.top, text="Save", command=self.saveCuston).grid(row=rowCount, column=0, - columnspan=2) # button to save + Button(frame, text="Save", command=self.saveCuston).grid(row=rowCount, column=0, columnspan=2) rowCount += 1 - Button(self.top, text="Reset", command=self.resetCustom).grid(row=rowCount, column=0, - columnspan=2) # button to save + Button(frame, text="Reset", command=self.resetCustom).grid(row=rowCount, column=0, columnspan=2) + + def saveCuston(self): # save the custom values logging.debug("Saving custom parameters") diff --git a/SearchStrategyAnalysis/appTrial.py b/SearchStrategyAnalysis/appTrial.py index 92c29a1..cdc69e1 100644 --- a/SearchStrategyAnalysis/appTrial.py +++ b/SearchStrategyAnalysis/appTrial.py @@ -199,7 +199,6 @@ def defineOwnSoftware(root, filename): theStatus.set("[First X, Y, time values]: ") status = Label(frame, textvariable=theStatus, width=50, height=2, relief=SUNKEN, anchor=W, bg="white") status.grid(row=0, column=0, columnspan=4) - global customxyt def okButton(): @@ -208,7 +207,6 @@ def okButton(): messagebox.showinfo(None, "First X value: " + str(customxyt[0]) + "\nFirst Y value: " + str(customxyt[1]) + "\nFirst time value: " + str(customxyt[2])) - top.quit() top.destroy() else: From 5bfb5327589aac51f1f84351afcf60ce3d7be745 Mon Sep 17 00:00:00 2001 From: rickyma Date: Sat, 14 Mar 2020 23:22:04 -0700 Subject: [PATCH 09/14] Cleaned up GUI, start position is plotted --- SearchStrategyAnalysis/Pathfinder.py | 88 +++++++++++++++++----------- SearchStrategyAnalysis/appTrial.py | 2 +- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index cdecdf6..c72052a 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -575,20 +575,31 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - if (startX - goalCentre[1] == 0): aArcTangent = 270 - else: aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) - upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 - lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 - - m1 = math.tan(math.radians(upperCorridor)) - c1 = startY - m1 * startX - endX1 = -c1 / m1 - m2 = math.tan(math.radians(lowerCorridor)) - c2 = startY - m2 * startX - endX2 = -c2 / m2 - - self.upperCorridorLine = canvas.create_line(startX, startY, endX1, 0, fill="blue", width=2) - self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, 0, fill="blue", width=2) + # # goalCentre = 250, 250 + # reflectedGoal = goalCentre + # if (goalCentre[0] > 200 and goalCentre[1] < 200): + # reflectedGoal = goalCentre[0], 400-goalCentre[1] + # elif (goalCentre[0] > 200 and goalCentre[1] > 200): + # reflectedGoal = 400-goalCentre[0], goalCentre[1] + # elif (goalCentre[0] < 200 and goalCentre[1] > 200): + # reflectedGoal = goalCentre[0], 400-goalCentre[1] + # elif (goalCentre[0] < 200 and goalCentre[1] < 200): + # reflectedGoal = goalCentre[0], 400-goalCentre[1] + # + # if (startX - reflectedGoal[1] == 0): aArcTangent = 270 + # else: aArcTangent = math.degrees(math.atan(-(startY - reflectedGoal[0]) / (startX - reflectedGoal[1]))) + # upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 + # lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 + # + # m1 = math.tan(math.radians(upperCorridor)) + # c1 = startY - m1 * startX + # endX1 = -c1 / m1 + # m2 = math.tan(math.radians(lowerCorridor)) + # c2 = startY - m2 * startX + # endX2 = -c2 / m2 + # + # self.upperCorridorLine = canvas.create_line(startX, startY, endX1, 0, fill="blue", width=2) + # self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, 0, fill="blue", width=2) self.centerLine = canvas.create_line(200, 200 + scale * radius, 200, 200 - scale * radius, dash=(1, 1)) self.centerLine = canvas.create_line(200 - scale * radius, 200, 200 + scale * radius, 200, dash=(1, 1)) @@ -641,20 +652,30 @@ def redraw(*args): self.smallThigmo = canvas.create_oval(smallThigmoRadius, smallThigmoRadius, 400 - smallThigmoRadius, 400 - smallThigmoRadius, dash=(2, 1)) - if (startX - goalCentre[1] == 0): aArcTangent = 270 - else: aArcTangent = math.degrees(math.atan(-(startY - goalCentre[0]) / (startX - goalCentre[1]))) - upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 - lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 - - m1 = math.tan(math.radians(upperCorridor)) - c1 = startY - m1 * startX - endX1 = -c1 / m1 - m2 = math.tan(math.radians(lowerCorridor)) - c2 = startY - m2 * startX - endX2 = -c2 / m2 - - self.upperCorridorLine = canvas.create_line(startX, startY, endX1, 0, fill="blue", width=2) - self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, 0, fill="blue", width=2) + # reflectedGoal = goalCentre + # if (goalCentre[0] > 200 and goalCentre[1] < 200): + # reflectedGoal = 400 - goalCentre[0], goalCentre[1] + # elif (goalCentre[0] > 200 and goalCentre[1] > 200): + # reflectedGoal = 400 - goalCentre[0], 400 - goalCentre[1] + # elif (goalCentre[0] < 200 and goalCentre[1] > 200): + # reflectedGoal = goalCentre[0], goalCentre[1] + # elif (goalCentre[0] < 200 and goalCentre[1] < 200): + # reflectedGoal = goalCentre[0], 400 - goalCentre[1] + # + # if (startX - reflectedGoal[1] == 0): aArcTangent = 270 + # else: aArcTangent = math.degrees(math.atan(-(startY - reflectedGoal[0]) / (startX - reflectedGoal[1]))) + # upperCorridor = aArcTangent + float(corridorWidthStringVar.get()) / 2 + # lowerCorridor = aArcTangent - float(corridorWidthStringVar.get()) / 2 + # + # m1 = math.tan(math.radians(upperCorridor)) + # c1 = startY - m1 * startX + # endX1 = -c1 / m1 + # m2 = math.tan(math.radians(lowerCorridor)) + # c2 = startY - m2 * startX + # endX2 = -c2 / m2 + # + # self.upperCorridorLine = canvas.create_line(startX, startY, endX1, 0, fill="blue", width=2) + # self.lowerCorridorLine = canvas.create_line(startX, startY, endX2, 0, fill="blue", width=2) self.centerLine = canvas.create_line(200, 200 + scale*radius, 200, 200 - scale*radius, dash=(1, 1)) self.centerLine = canvas.create_line(200 - scale*radius, 200, 200 + scale*radius, 200, dash=(1, 1)) @@ -870,12 +891,11 @@ def otherROI(self): self.saveButton.config(width=10) self.add_button.config(width=10) self.container = Frame(self.top4) - self.canvas.create_window(0, 0, anchor="nw", window=self.container) - Label(self.top4, text="Settings", bg="white", fg="red").pack(side="top") # we title it - self.add_button.pack(side="top") + self.canvas.create_window(0, 0, anchor="nw", window=self.container) # we title it self.vsb.pack(side="right", fill="y") self.canvas.pack(side="left", fill="both", expand=True) self.saveButton.pack(side="bottom") + self.add_button.pack(side="bottom") def addROI(self): labelText = "ROI #" + str(int((len(self.entries)) / 2 + 2)) @@ -1427,8 +1447,7 @@ def callDefineOwnSoftware(self): self.defineRadio['state'] = 'active' self.calculateButton['state'] = 'normal' - def plotPoints(self, x, y, mazeDiam, centreX, centreY, platX, platY, scalingFactor, name, title, - platEstDiam): # function to graph the data for the not recognized trials + def plotPoints(self, x, y, mazeDiam, centreX, centreY, platX, platY, scalingFactor, name, title, platEstDiam): # function to graph the data for the not recognized trials wallsX = [] wallsY = [] platWallsX = [] @@ -1547,7 +1566,6 @@ def plotPoints(self, x, y, mazeDiam, centreX, centreY, platX, platY, scalingFact def saveStrat(self): # save the manual strategy global searchStrategyV global searchStrategyStringVar - searchStrategyV = searchStrategyStringVar.get() # get the value to be saved try: # try and destroy the window self.top2.destroy() @@ -1558,7 +1576,7 @@ def guiHeatmap(self, aExperiment): self.top3 = Toplevel(root) # create a new toplevel window self.top3.configure(bg="white") - self.top3.geometry('{}x{}'.format(500, 500)) + self.top3.geometry('{}x{}'.format(200, 300)) Label(self.top3, text="Heatmap Parameters", bg="white", fg="black", width=15).pack() # add a title self.gridSizeL = Label(self.top3, text="Grid Size:", bg="white") diff --git a/SearchStrategyAnalysis/appTrial.py b/SearchStrategyAnalysis/appTrial.py index cdc69e1..1da9ad4 100644 --- a/SearchStrategyAnalysis/appTrial.py +++ b/SearchStrategyAnalysis/appTrial.py @@ -494,7 +494,7 @@ def saveFileAsExperiment(software, filename, filedirectory): xCol = customxyt[0][0] yCol = customxyt[1][0] tCol = customxyt[2][0] - for row in listReader[customxyt[0][0]:]: + for row in listReader[customxyt[0][1]:]: try: x = float(row[xCol]) y = float(row[yCol]) From 97650166ec4407925daa96431107562c62f8b4aa Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 1 Apr 2020 16:53:15 -0700 Subject: [PATCH 10/14] Fixed addROI bug --- SearchStrategyAnalysis/Pathfinder.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index c72052a..ab351d2 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -75,12 +75,9 @@ if not os.path.exists("output/heatmaps"): os.makedirs("output/heatmaps") -logfilename = "output/logs/logfile " + str( - strftime("%Y_%m_%d %I_%M_%S_%p", localtime())) + ".log" # name of the log file for the run -logging.basicConfig(filename=logfilename, - level=logging.DEBUG) # set the default log type to INFO, can be set to DEBUG for more detailed information -csvfilename = "output/results/results " + str( - strftime("%Y_%m_%d %I_%M_%S_%p", localtime())) # name of the default results file +logfilename = "output/logs/logfile " + str(strftime("%Y_%m_%d %I_%M_%S_%p", localtime())) + ".log" # name of the log file for the run +logging.basicConfig(filename=logfilename, level=logging.DEBUG) # set the default log type to INFO, can be set to DEBUG for more detailed information +csvfilename = "output/results/results " + str(strftime("%Y_%m_%d %I_%M_%S_%p", localtime())) # name of the default results file theFile = "" fileDirectory = "" goalPosVar = "0,0" @@ -237,6 +234,9 @@ def __init__(self, root): # init is called on runtime logging.debug("GUI is built") def buildGUI(self, root): # Called in the __init__ to build the GUI window + for widget in root.winfo_children(): + widget.destroy() + root.wm_title("Pathfinder") global goalPosVar @@ -270,8 +270,6 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window accelC = "Ctrl+C" accelV = "Ctrl+V" - #root.geometry('{}x{}'.format(1100, 500)) - self.menu = Menu(root) # create a menu root.config(menu=self.menu, bg="white") # set up the config self.fileMenu = Menu(self.menu, tearoff=False) # create file menu @@ -619,6 +617,7 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window def redraw(*args): try: + canvas.delete("all") scale = 1/float(softwareScalingFactorStringVar.get()) radius = float(mazeDiamStringVar.get()) / 2 @@ -966,6 +965,7 @@ def saveROI(self): chainingRadiusVar = chainingRadiusStringVar.get() thigmotaxisZoneSizeVar = thigmotaxisZoneSizeStringVar.get() softwareScalingFactorVar = softwareScalingFactorStringVar.get() + self.buildGUI(root) @@ -2546,12 +2546,12 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): semifocalSearchCount, "| Chaining: ", chainingCount, "| Scanning: ", scanningCount, "| Random Search: ", randomCount, "| Thigmotaxis: ", thigmotaxisCount, "| Not Recognized: ", notRecognizedCount) # TODO - # if sys.platform.startswith('darwin'): - # subprocess.call(('open', currentOutputFile)) - # elif os.name == 'nt': # For Windows - # os.startfile(currentOutputFile) - # elif os.name == 'posix': # For Linux, Mac, etc. - # subprocess.call(('xdg-open', currentOutputFile)) + if sys.platform.startswith('darwin'): + subprocess.call(('open', currentOutputFile)) + elif os.name == 'nt': # For Windows + os.startfile(currentOutputFile) + elif os.name == 'posix': # For Linux, Mac, etc. + subprocess.call(('xdg-open', currentOutputFile)) self.updateTasks() theStatus.set('') self.updateTasks() From a52f06a9e979ecb7b69a2708a9a3964917e80409 Mon Sep 17 00:00:00 2001 From: rickyma Date: Wed, 8 Apr 2020 15:52:44 -0700 Subject: [PATCH 11/14] Fixed and added error recovery for define input, callDefineOwnSoftware --- SearchStrategyAnalysis/Pathfinder.py | 16 +++++++--- SearchStrategyAnalysis/appTrial.py | 48 ++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index ab351d2..7b35174 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -182,7 +182,7 @@ useScaling.set(False) scale = False rois = [] - +destroyedroot = False def show_message(text): # popup box with message text logging.debug("Displaying message") @@ -233,6 +233,12 @@ def __init__(self, root): # init is called on runtime return logging.debug("GUI is built") + ## Helper for callDefineOwnSoftware, tracks if root has been destroyed + def root_tracker(): + destroyedroot = True + root.destroy() + root.protocol("WM_DELETE_WINDOW", root_tracker) + def buildGUI(self, root): # Called in the __init__ to build the GUI window for widget in root.winfo_children(): widget.destroy() @@ -1437,15 +1443,17 @@ def find_files(self, directory, pattern): # searches for our files in the direc filename = os.path.join(root, basename) yield filename + def callDefineOwnSoftware(self): global theFile if theFile == "": logging.debug("Open File...") theFile = filedialog.askopenfilename() defineOwnSoftware(root, theFile) - softwareStringVar.set("custom") - self.defineRadio['state'] = 'active' - self.calculateButton['state'] = 'normal' + if destroyedroot==True: + softwareStringVar.set('custom') + self.defineRadio['state'] = 'active' + self.calculateButton['state'] = 'normal' def plotPoints(self, x, y, mazeDiam, centreX, centreY, platX, platY, scalingFactor, name, title, platEstDiam): # function to graph the data for the not recognized trials wallsX = [] diff --git a/SearchStrategyAnalysis/appTrial.py b/SearchStrategyAnalysis/appTrial.py index 1da9ad4..0de793b 100644 --- a/SearchStrategyAnalysis/appTrial.py +++ b/SearchStrategyAnalysis/appTrial.py @@ -242,23 +242,43 @@ def getXYT(event): # display table if (file_extension == '.csv'): with open(filename, newline="") as file: - dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") - file.seek(0) - data = csv.reader(file, dialect) - displayTable(data) + try: + dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") + file.seek(0) + data = csv.reader(file, dialect) + displayTable(data) + + okbutton = Button(frame, text="Save", width=12, height=2, command=okButton) + okbutton.grid(row=0, column=4) + resetbutton = Button(frame, text="Reset", width=12, height=2, command=resetButton) + resetbutton.grid(row=0, column=5) + + top.attributes('-topmost', False) + messagebox.showinfo(None, "Please select in order: first X value, first Y value, first time value.") + top.attributes('-topmost', True) + top.mainloop() + except: + top.attributes('-topmost', False) + messagebox.showinfo(None, "Invalid CSV format.") + top.destroy() + top.mainloop() elif (file_extension == '.xlsx'): - data = pd.read_excel(filename) - displayTable(data.values) + try: + data = pd.read_excel(filename) + displayTable(data.values) - okbutton = Button(frame, text="Save", width=12, height=2, command=okButton) - okbutton.grid(row=0, column=4) - resetbutton = Button(frame, text="Reset", width=12, height=2, command=resetButton) - resetbutton.grid(row=0, column=5) + okbutton = Button(frame, text="Save", width=12, height=2, command=okButton) + okbutton.grid(row=0, column=4) + resetbutton = Button(frame, text="Reset", width=12, height=2, command=resetButton) + resetbutton.grid(row=0, column=5) - top.attributes('-topmost', False) - messagebox.showinfo(None, "Please select in order: first X value, first Y value, first time value.") - top.attributes('-topmost', True) - top.mainloop() + top.attributes('-topmost', False) + messagebox.showinfo(None, "Please select in order: first X value, first Y value, first time value.") + top.attributes('-topmost', True) + top.mainloop() + except: + top.attributes('-topmost', False) + messagebox.showinfo(None, "Error opening Excel table.") def saveFileAsExperiment(software, filename, filedirectory): From d2ac6bb4669c27134e263e84a106674d1bc8c8fa Mon Sep 17 00:00:00 2001 From: bdungate Date: Wed, 6 May 2020 15:02:09 -0700 Subject: [PATCH 12/14] Notifies user to upload file or directory before generating heatmap. --- SearchStrategyAnalysis/Pathfinder.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 7b35174..e9bb203 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -766,8 +766,11 @@ def generateHeatmap(self, root): global fileDirectory global theFile software = softwareStringVar.get() - experiment = saveFileAsExperiment(software, theFile, fileDirectory) - self.guiHeatmap(experiment) + if theFile == "" and fileDirectory == "": + messagebox.showwarning('No file or directory', 'Please upload a file or directory before attempting to generate heatmap.') + else: + experiment = saveFileAsExperiment(software, theFile, fileDirectory) + self.guiHeatmap(experiment) def on_enter(self, text, event): global oldStatus From 73621975dc74c6748d000ddb7cc22c6ff6824efe Mon Sep 17 00:00:00 2001 From: bdungate Date: Wed, 6 May 2020 17:09:49 -0700 Subject: [PATCH 13/14] Updates output file name to user defined name for current calculations --- SearchStrategyAnalysis/Pathfinder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index e9bb203..2a26b57 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -2326,7 +2326,7 @@ def mainCalculate(self, goalPosVar=goalPosVar, goalDiamVar=goalDiamVar): theStatus.set('Calculating Search Strategies...') # update status bar self.updateTasks() - currentOutputFile = outputFile + str(goalPosVar) + ".csv" + currentOutputFile = outputFileStringVar.get() + str(goalPosVar) + ".csv" logging.debug("Calculating search strategies") try: # try to open a csv file for output f = open(currentOutputFile, 'wt') From 86014069ecee7a316fb304ebf721823c66cc438a Mon Sep 17 00:00:00 2001 From: bdungate Date: Fri, 5 Jun 2020 14:31:05 -0700 Subject: [PATCH 14/14] Calculation of angular cooridor which updates to user input and renders representation on maze graphicimplemented. --- SearchStrategyAnalysis/Pathfinder.py | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/SearchStrategyAnalysis/Pathfinder.py b/SearchStrategyAnalysis/Pathfinder.py index 2a26b57..c82dbcb 100755 --- a/SearchStrategyAnalysis/Pathfinder.py +++ b/SearchStrategyAnalysis/Pathfinder.py @@ -611,6 +611,29 @@ def buildGUI(self, root): # Called in the __init__ to build the GUI window self.start = canvas.create_oval(195, 195 + scale * radius, 205, 205 + scale * radius, fill="green", width=1) self.goal = canvas.create_oval(goalLBorder, goalTopBorder, goalRBorder, goalBottomBorder, fill="red", width=1) + + # calculation of angular cooridor, updates to user input and renders blue lines on user interface + # to represent outer bounds of cooridor + rightCorridorSideAngle = math.radians(float(corridorWidthStringVar.get())/2 + math.degrees(math.atan((float(goalX))/(float(goalY) + radius)))) + rightCorridorLeftDiameterChordSection = radius + radius* math.tan(rightCorridorSideAngle) + rightCorridorRightDiameterChordSection = radius - radius* math.tan(rightCorridorSideAngle) + rightCorridorBottomChordSection = radius / math.cos(rightCorridorSideAngle) + rightCorridorTopChordSection = (rightCorridorLeftDiameterChordSection*rightCorridorRightDiameterChordSection)/rightCorridorBottomChordSection + rightCorridorOnCircleX = radius*math.tan(rightCorridorSideAngle) + rightCorridorTopChordSection*math.sin(rightCorridorSideAngle) + rightCorridorOnCircleY = rightCorridorTopChordSection * math.cos(rightCorridorSideAngle) + self.rightAngularCooridorLine = canvas.create_line(200, 200 + scale * radius, 200 + scale*(rightCorridorOnCircleX), 200 - (scale * rightCorridorOnCircleY), fill = "blue", width = 2) + + leftCorridorSideAngle = rightCorridorSideAngle - math.radians(float(corridorWidthStringVar.get())) + leftCorridorLeftDiameterChordSection = radius + radius* math.tan(leftCorridorSideAngle) + leftCorridorRightDiameterChordSection = radius - radius* math.tan(leftCorridorSideAngle) + leftCorridorBottomChordSection = radius / math.cos(leftCorridorSideAngle) + leftCorridorTopChordSection = (leftCorridorLeftDiameterChordSection*leftCorridorRightDiameterChordSection)/leftCorridorBottomChordSection + leftCorridorOnCircleX = radius*math.tan(leftCorridorSideAngle) + leftCorridorTopChordSection*math.sin(leftCorridorSideAngle) + leftCorridorOnCircleY = leftCorridorTopChordSection * math.cos(leftCorridorSideAngle) + self.leftAngularCooridorLine = canvas.create_line(200, 200 + scale * radius, 200 + scale*(leftCorridorOnCircleX), 200 - (scale * leftCorridorOnCircleY),fill = "blue", width = 2) + + + # draw all rois for aTuple in rois: roiX, roiY = aTuple[0].split(",") @@ -688,6 +711,30 @@ def redraw(*args): self.start = canvas.create_oval(195, 195 + scale*radius, 205, 205 + scale*radius, fill="green", width=1) self.goal = canvas.create_oval(goalLBorder, goalTopBorder, goalRBorder, goalBottomBorder, fill="red", width=1) + + # calculation of angular cooridor, updates to user input and renders blue lines on user interface + # to represent outer bounds of cooridor + rightCorridorSideAngle = math.radians(float(corridorWidthStringVar.get())/2 + math.degrees(math.atan((float(goalX))/(float(goalY) + radius)))) + rightCorridorLeftDiameterChordSection = radius + radius* math.tan(rightCorridorSideAngle) + rightCorridorRightDiameterChordSection = radius - radius* math.tan(rightCorridorSideAngle) + rightCorridorBottomChordSection = radius / math.cos(rightCorridorSideAngle) + rightCorridorTopChordSection = (rightCorridorLeftDiameterChordSection*rightCorridorRightDiameterChordSection)/rightCorridorBottomChordSection + rightCorridorOnCircleX = radius*math.tan(rightCorridorSideAngle) + rightCorridorTopChordSection*math.sin(rightCorridorSideAngle) + rightCorridorOnCircleY = rightCorridorTopChordSection * math.cos(rightCorridorSideAngle) + self.rightAngularCooridorLine = canvas.create_line(200, 200 + scale * radius, 200 + scale*(rightCorridorOnCircleX), 200 - (scale * rightCorridorOnCircleY), fill = "blue", width = 2) + + + leftCorridorSideAngle = rightCorridorSideAngle - math.radians(float(corridorWidthStringVar.get())) + leftCorridorLeftDiameterChordSection = radius + radius* math.tan(leftCorridorSideAngle) + leftCorridorRightDiameterChordSection = radius - radius* math.tan(leftCorridorSideAngle) + leftCorridorBottomChordSection = radius / math.cos(leftCorridorSideAngle) + leftCorridorTopChordSection = (leftCorridorLeftDiameterChordSection*leftCorridorRightDiameterChordSection)/leftCorridorBottomChordSection + leftCorridorOnCircleX = radius*math.tan(leftCorridorSideAngle) + leftCorridorTopChordSection*math.sin(leftCorridorSideAngle) + leftCorridorOnCircleY = leftCorridorTopChordSection * math.cos(leftCorridorSideAngle) + self.leftAngularCooridorLine = canvas.create_line(200, 200 + scale * radius, 200 + scale*(leftCorridorOnCircleX), 200 - (scale * leftCorridorOnCircleY), fill = "blue", width = 2) + + + # draw all rois for aTuple in rois: roiX, roiY = aTuple[0].split(",")