def send_to_mi(self): #TODO: get left and right selectors try: left = float(self.spinboxLeftVal.get()) right = float(self.spinboxRightVal.get()) except ValueError: messagebox.showinfo("Bad Input","Please enter in-range floating point numbers for the bounds.") if left < self.energies[0] or right > self.energies[-1]: messagebox.showinfo("Bad Input","Please enter in-range floating point numbers for the bounds.") return None r = binary_search_find_nearest(self.energies, right) l = binary_search_find_nearest(self.energies, left) self.controller.show_frame(ManualIntegrationPage) self.controller.frames[ManualIntegrationPage].populate_values(self.energies[l:r], self.cps[l:r]) self.controller.frames[ManualIntegrationPage].add_peak_selector(self.get_possibilites(False))
def reanalyze(self): try: lowIndex = np.where(self.energies==self.spinboxLeftVal.get())[0][0] highIndex = np.where(self.energies==self.spinboxRightVal.get())[0][0] + 1 except IndexError: lowIndex = binary_search_find_nearest(self.energies, self.spinboxLeftVal.get()) highIndex = binary_search_find_nearest(self.energies, self.spinboxRightVal.get()) guesses = [[float(j) for j in i.cget("text").split(", ")] for i in self.peakGUIList] guesses = list(chain.from_iterable(guesses)) guesses = [self.slope, self.intercept] + guesses try: popt, pcov = curve_fit(self.controller.multiple_gaussian_and_secant, xdata = self.energies[lowIndex:highIndex], ydata = self.cps[lowIndex:highIndex], p0 = np.array(guesses)) self.populate_values(self.startInd - 20 + lowIndex, self.startInd - 20 + highIndex, popt, np.diag(pcov)[2:]) except RuntimeError: messagebox.showwarning("No fit found", "No good peak fit could be determined. Try entering fewer centroids.")
def update_right(self): temp = self.spinboxRightVal.get() try: newRange = self.energies[np.where( self.energies == self.spinboxLeftVal.get())[0][0] + 1:] except IndexError: newRange = self.energies[binary_search_find_nearest( self.energies, self.spinboxLeftVal.get())] self.spinboxRight.configure(values=newRange) self.spinboxRightVal.set(temp)
def update_right(self): temp = self.spinboxRightVal.get() if self.spinboxLeftVal.get() < self.energies[0]: messagebox.showinfo("Out of Bounds","Please enter an X value within the currently plotted points") self.spinboxLeftVal.set(self.energies[20]) return None try: newRange = self.energies[np.where(self.energies==self.spinboxLeftVal.get())[0][0]+1:] except IndexError: newRange = self.energies[binary_search_find_nearest(self.energies, self.spinboxLeftVal.get()):] self.spinboxRight.configure(values=newRange) self.spinboxRightVal.set(temp)
def edit_ROIs(self): """Edit ROIs for the program when submitted from ROI edit window""" self.ROIEditWindow.withdraw() self.isotopes = self.elements fitRanges = self.get_fitting_ranges(self.elements) self.fitRanges = fitRanges if len(self.graphEnergies) > 0: l = lambda x:binary_search_find_nearest(self.graphEnergies, x) fitIndices = [[l(p[1]), l(p[2])] for p in fitRanges] fitIndices = list(chain.from_iterable(fitIndices)) self.fitIndices = fitIndices for i in self.polyFills: i.remove() self.polyFills = [] for i in range(0, len(fitIndices), 2): self.polyFills.append(self.plotAxes.fill_between(self.graphEnergies[fitIndices[i]:fitIndices[i+1]],self.graphCPS[fitIndices[i]:fitIndices[i+1]])) self.canvas.draw()
def do_peak_fitting(self, energies, cps, ROIs): """This function takes a lot of guesses at initial parameters, then uses a curve fitter to find the best-fitting peak equation""" peaks_to_return = [] variances = [] for region in ROIs: i = 0 while energies[i] < region[0]: i += 1 lowerBound = energies[i - 1] lowerIndex = i - 1 while energies[i] < region[1]: i += 1 upperBound = energies[i] upperIndex = i peaksInRange = [] i = 0 while float(self.all_peaks_sens[i][1]) < lowerBound: i += 1 while i < len(self.all_peaks_sens) and float( self.all_peaks_sens[i][1]) < upperBound: peaksInRange.append(self.all_peaks_sens[i]) i += 1 #Background line guessing algorthm (finds flat areas on each side of peak) thresh = 5000 searchLeft = (lowerIndex + upperIndex) // 2 searchRight = (lowerIndex + upperIndex) // 2 + 1 if lowerBound < thresh: v1 = 25 v2 = 10 v3 = .05 else: v1 = 100 v2 = 50 v3 = .015 while not ( (abs( sum(cps[searchLeft - 4:searchLeft]) / 4 - cps[searchLeft]) < cps[searchLeft] / v1 and abs(cps[searchLeft - 4] - cps[searchLeft]) < cps[searchLeft] / v2 and abs(cps[searchLeft - 3] - cps[searchLeft]) < cps[searchLeft] / v2 and abs(cps[searchLeft - 2] - cps[searchLeft]) < cps[searchLeft] / v2 and abs(cps[searchLeft - 1] - cps[searchLeft]) < cps[searchLeft] / v2) or (sum(cps[searchLeft - 4:searchLeft + 1]) < v3)): searchLeft -= 1 if lowerBound < thresh: while not ((abs( sum(cps[searchRight + 1:searchRight + 5]) / 4 - cps[searchRight]) < cps[searchRight] / v1 and abs(cps[searchRight + 1] - cps[searchRight]) < cps[searchRight] / v2 and abs(cps[searchRight + 2] - cps[searchRight]) < cps[searchRight] / v2 and abs(cps[searchRight + 3] - cps[searchRight]) < cps[searchRight] / v2 and abs(cps[searchRight + 4] - cps[searchRight]) < cps[searchRight] / v2) or (sum(cps[searchRight + 1:searchRight + 5]) < v3)): searchRight += 1 else: while cps[searchRight] > cps[searchLeft]: searchRight += 1 while searchRight - searchLeft > 50: #If our ROI is too wide v1 /= 2 v2 /= 2 v3 *= 2 searchLeft = (lowerIndex + upperIndex) // 2 searchRight = (lowerIndex + upperIndex) // 2 + 1 while not ((abs( sum(cps[searchLeft - 4:searchLeft]) / 4 - cps[searchLeft]) < cps[searchLeft] / v1 and abs(cps[searchLeft - 4] - cps[searchLeft]) < cps[searchLeft] / v2 and abs(cps[searchLeft - 3] - cps[searchLeft]) < cps[searchLeft] / v2 and abs(cps[searchLeft - 2] - cps[searchLeft]) < cps[searchLeft] / v2 and abs(cps[searchLeft - 1] - cps[searchLeft]) < cps[searchLeft] / v2) or (sum(cps[searchLeft - 4:searchLeft + 1]) < v3)): searchLeft -= 1 if lowerBound < thresh: while not ( (abs( sum(cps[searchRight + 1:searchRight + 5]) / 4 - cps[searchRight]) < cps[searchRight] / v1 and abs(cps[searchRight + 1] - cps[searchRight]) < cps[searchRight] / v2 and abs(cps[searchRight + 2] - cps[searchRight]) < cps[searchRight] / v2 and abs(cps[searchRight + 3] - cps[searchRight]) < cps[searchRight] / v2 and abs(cps[searchRight + 4] - cps[searchRight]) < cps[searchRight] / v2) or (sum(cps[searchRight + 1:searchRight + 5]) < v3)): searchRight += 1 else: while cps[searchRight] > cps[searchLeft]: searchRight += 1 while searchRight - searchLeft < 15: #If our ROI is too narrow, just widen it a bit searchLeft -= 1 searchRight += 1 enerToFit = energies[searchLeft:searchRight + 1] cpsToFit = cps[searchLeft:searchRight + 1] start = cpsToFit[0] end = cpsToFit[-1] tempData = copy.deepcopy(cpsToFit) slope = (end - start) / (enerToFit[-1] - enerToFit[0]) intercept = start - enerToFit[0] * slope tempData = tempData - (slope * enerToFit + np.full_like(tempData, intercept)) newMin = min(tempData) tempData = tempData - np.full_like(tempData, newMin) #Peak finding maxima = peakdet(cpsToFit, max(cpsToFit) / 50, enerToFit) guessedParams = [slope, intercept] for i, j in maxima: if j < max(cpsToFit) / 25: maxima.remove((i, j)) maxima = sorted(maxima, key=lambda x: -x[1]) while len(maxima) * 3 + 2 > searchRight - searchLeft: del maxima[-1] #TODO: get width estimation from FWHM input for m, _ in maxima: guessedParams += [ m, cpsToFit[binary_search_find_nearest(enerToFit, m)], 1.00 ] #Actual curve fitting if len(guessedParams) >= 5: try: popt, pcov = curve_fit(self.multiple_gaussian_and_secant, enerToFit, cpsToFit, p0=guessedParams) peaks_to_return.append([searchLeft, searchRight] + list(popt)) pvar = list(np.diag(pcov))[2:] if len(pvar) == 0: pvar = [.1, .1, .1] #maybe change variances.append(pvar) except RuntimeError: try: #fallack, use our guess for background line and give the algorithm less params to work with popt, pcov = curve_fit(self.multiple_gaussian, enerToFit, tempData, p0=guessedParams[2:]) peaks_to_return.append([searchLeft, searchRight] + [slope, intercept] + list(popt)) pvar = list(np.diag(pcov)) if len(pvar) == 0: pvar = [.1, .1, .1] #maybe change variances.append(pvar) except RuntimeError: peaks_to_return.append([searchLeft, searchRight]) variances.append([]) #TODO: as a catch-all for special cases, just integrate under the data. Present the graph of the data(with maybe even more context) to the researcher and let them choose the bounds """self.show_frame(ManualIntegrationPage) self.frames[ManualIntegrationPage].populate_values(enerToFit,cpsToFit)""" #TODO: wait until we get a callback #TODO: figure out variance for this case #TODO: figure out how to differentiate integral data from fit data in find_elements pass else: peaks_to_return.append([searchLeft, searchRight]) variances.append([]) """peaks_to_return = [[left bound, right bound, slope, intercept, ctr1, amp1, wid1...,ctrn,ampn,widn]]""" return peaks_to_return, variances
def show_side_to_side(self, fname1, fname2, area, xlim, stacked, win, f): """Side-by-side Graph Creator""" if fname1 == "" or fname2 == "" or fname1 == fname2: tk.messagebox.showinfo("Bad Input","Please add 2 distinct files for comaprison") return None fig = Figure(figsize=(10,5), dpi=100) f1Ind = self.files.index(fname1) f1Ener = self.fileInfo[f1Ind][2] f1CPS = self.fileInfo[f1Ind][3] f2Ind = self.files.index(fname2) f2Ener = self.fileInfo[f2Ind][2] f2CPS = self.fileInfo[f2Ind][3] if area == "Current Bounds": left = xlim[0] right = xlim[1] f1Left = max(binary_search_find_nearest(f1Ener, left), 5) f1Right = min(binary_search_find_nearest(f1Ener, right), len(f1Ener)-5) f2Left = max(binary_search_find_nearest(f2Ener, left), 5) f2Right = min(binary_search_find_nearest(f2Ener, right), len(f1Ener)-5) if stacked: a = fig.add_subplot(111) a.plot(f1Ener[f1Left-5:f1Right+5],f1CPS[f1Left-5:f1Right+5], label=fname1) a.plot(f2Ener[f2Left-5:f2Right+5],f2CPS[f2Left-5:f2Right+5], label=fname2) a.set_xlim(*xlim) else: a = fig.add_subplot(121) a.plot(f1Ener[f1Left-5:f1Right+5],f1CPS[f1Left-5:f1Right+5]) b = fig.add_subplot(122) b.plot(f2Ener[f2Left-5:f2Right+5],f2CPS[f2Left-5:f2Right+5]) a.set_xlim(*xlim) b.set_xlim(*xlim) elif area == "All Data": if stacked: a = fig.add_subplot(111) a.plot(f1Ener, f1CPS) a.plot(f2Ener, f2CPS) else: a = fig.add_subplot(121) a.plot(f1Ener, f1CPS, label=fname1) b = fig.add_subplot(122) b.plot(f2Ener, f2CPS, label=fname2) else: bounds = area.split(": ")[1].split("-") left = float(bounds[0]) right = float(bounds[1]) f1Left = max(binary_search_find_nearest(f1Ener, left), 5) f1Right = min(binary_search_find_nearest(f1Ener, right), len(f1Ener)-5) f2Left = max(binary_search_find_nearest(f2Ener, left), 5) f2Right = min(binary_search_find_nearest(f2Ener, right), len(f1Ener)-5) if stacked: a = fig.add_subplot(111) a.plot(f1Ener[f1Left-5:f1Right+5],f1CPS[f1Left-5:f1Right+5], label=fname1) a.plot(f2Ener[f2Left-5:f2Right+5],f2CPS[f2Left-5:f2Right+5], label=fname2) a.set_xlim(left, right) else: a = fig.add_subplot(121) a.plot(f1Ener[f1Left-5:f1Right+5],f1CPS[f1Left-5:f1Right+5]) b = fig.add_subplot(122) b.plot(f2Ener[f2Left-5:f2Right+5],f2CPS[f2Left-5:f2Right+5]) a.set_xlim(left, right) b.set_xlim(left, right) if stacked: fig.set_size_inches(5,5) a.set_title("Side-by-Side", size=14) a.legend(fontsize=8) a.set_xlabel("Energy (kEv)") a.set_ylabel("Counts per Second") else: a.set_title(fname1, fontsize=10) a.set_xlabel("Energy (kEv)") a.set_ylabel("Counts per Second") b.set_title(fname2, fontsize = 10) b.set_xlabel("Energy (kEv)") b.set_ylabel("Counts per Second") f.destroy() c = FigureCanvasTkAgg(fig, win) c.draw() c.get_tk_widget().grid(row=0,column=0,columnspan=6, rowspan=6)
def edit_ROIs(self): """Edit ROIs for the program when submitted from ROI edit window""" self.ROIEditWindow.withdraw() elementMap = { 'Hydrogen': 'H', 'Helium': 'He', 'Lithium': 'Li', 'Beryllium': 'Be', 'Boron': 'B', 'Carbon': 'C', 'Nitrogen': 'N', 'Oxygen': 'O', 'Fluorine': 'F', 'Neon': 'Ne', 'Sodium': 'Na', 'Magnesium': 'Mg', 'Aluminum': 'Al', 'Silicon': 'Si', 'Phosphorus': 'P', 'Sulfur': 'S', 'Chlorine': 'Cl', 'Argon': 'Ar', 'Potassium': 'K', 'Calcium': 'Ca', 'Scandium': 'Sc', 'Titanium': 'Ti', 'Vanadium': 'V', 'Chromium': 'Cr', 'Manganese': 'Mn', 'Iron': 'Fe', 'Cobalt': 'Co', 'Nickel': 'Ni', 'Copper': 'Cu', 'Zinc': 'Zn', 'Gallium': 'Ga', 'Germanium': 'Ge', 'Arsenic': 'As', 'Selenium': 'Se', 'Bromine': 'Br', 'Krypton': 'Kr', 'Rubidium': 'Rb', 'Strontium': 'Sr', 'Yttrium': 'Y', 'Zirconium': 'Zr', 'Niobium': 'Nb', 'Molybdenum': 'Mo', 'Technetium': 'Tc', 'Ruthenium': 'Ru', 'Rhodium': 'Rh', 'Palladium': 'Pd', 'Silver': 'Ag', 'Cadmium': 'Cd', 'Indium': 'In', 'Tin': 'Sn', 'Antimony': 'Sb', 'Tellurium': 'Te', 'Iodine': 'I', 'Xenon': 'Xe', 'Caesium': 'Cs', 'Barium': 'Ba', 'Lanthanum': 'La', 'Cerium': 'Ce', 'Praseodymium': 'Pr', 'Neodymium': 'Nd', 'Promethium': 'Pm', 'Samarium': 'Sm', 'Europium': 'Eu', 'Gadolinium': 'Gd', 'Terbium': 'Tb', 'Dysprosium': 'Dy', 'Holmium': 'Ho', 'Erbium': 'Er', 'Thulium': 'Tm', 'Ytterbium': 'Yb', 'Lutetium': 'Lu', 'Hafnium': 'Hf', 'Tantalum': 'Ta', 'Tungsten': 'W', 'Rhenium': 'Re', 'Osmium': 'Os', 'Iridium': 'Ir', 'Platinum': 'Pt', 'Gold': 'Au', 'Mercury': 'Hg', 'Thallium': 'Tl', 'Lead': 'Pb', 'Bismuth': 'Bi', 'Polonium': 'Po', 'Astatine': 'At', 'Radon': 'Rn', 'Francium': 'Fr', 'Radium': 'Ra', 'Actinium': 'Ac', 'Thorium': 'Th', 'Protactinium': 'Pa', 'Uranium': 'U', 'Neptunium': 'Np', 'Plutonium': 'Pu', 'Americium': 'Am', 'Curium': 'Cm', 'Berkelium': 'Bk', 'Californium': 'Cf', 'Einsteinium': 'Es', 'Fermium': 'Fm', 'Mendelevium': 'Md', 'Nobelium': 'No', 'Lawrencium': 'Lr', 'Rutherfordium': 'Rf', 'Dubnium': 'Db', 'Seaborgium': 'Sg', 'Bohrium': 'Bh', 'Hassium': 'Hs', 'Meitnerium': 'Mt', 'Darmstadtium': 'Ds', 'Roentgenium': 'Rg', 'Copernicium': 'Cn', 'Ununtrium': 'Uut', 'Flerovium': 'Fl', 'Ununpentium': 'Uup', 'Livermorium': 'Lv', 'Ununseptium': 'Uus', 'Ununoctium': 'Uuo' } self.elementSymbols = [elementMap[e] for e in self.elements] fitRanges = self.get_fitting_ranges(self.elementSymbols) self.fitRanges = fitRanges if len(self.graphEnergies) > 0: l = lambda x: binary_search_find_nearest(self.graphEnergies, x) fitIndices = list(map(l, fitRanges)) self.fitIndices = fitIndices for i in self.polyFills: i.remove() self.polyFills = [] for i in range(0, len(fitIndices), 2): self.polyFills.append( self.plotAxes.fill_between( self.graphEnergies[fitIndices[i]:fitIndices[i + 1]], self.graphCPS[fitIndices[i]:fitIndices[i + 1]])) self.canvas.draw()