def quantify_chromatogram(self): time, _ = zip(*self.chrom_data) self.peaks = [] # Iterate over peaks for i in self.master.reference: self.peak_name = i[0] self.peak_time = i[1] self.peak_window = i[2] self.peak = Peak(self) # Ignore peaks outside the Trace RT window if self.peak_time < self.settings.start+self.settings.background_window \ or self.peak_time > self.settings.end-self.settings.background_window: continue # Background correct self.peak.determine_background_and_noise() if self.peak.background < 0.: self.peak.background_correct() self.peak.determine_background_and_noise() # Determine Areas, background and noise self.peak.determine_peak_area() self.peak.determine_background_area() self.peak.determine_peak_noise() self.peak.determine_signal_noise() self.peak.determine_total_area() # Data Subset (based on second derivative) self.peak.determine_spline_and_derivative() self.peak.determine_breakpoints() self.peak.subset_data() # Gaussian fit try: self.peak.determine_gaussian_coefficients() if self.peak.coeff.size > 0: self.peak.determine_gaussian_area() self.peak.determine_gaussian_parameters() self.peak.determine_height() self.peak.determine_actual_time() self.peak.determine_residual() except AttributeError: self.logger.warning('Unable to determine Gaussian fit for' + f'{self.peak_name}') pass # Results self.peaks.append(self.peak)
def determine_peak_parameters(self): x_data, _ = zip(*self.peak_buffer.peak_maximum_data) self.peak_name = None self.peak_window = (x_data[-1] - x_data[0]) / 2 self.peak_time = self.peak_window + x_data[0] peak = Peak(self) peak.determine_spline_and_derivative() peak.determine_breakpoints() peak.subset_data() peak.determine_gaussian_coefficients() self.peak = peak
def explore_chromatogram(self): self.peak_name = None self.peak_window = (self.settings.end - self.settings.start) / 2 self.peak_time = self.peak_window + self.settings.start peak_buffer = Peak(self) peak_buffer.determine_spline_and_derivative() peak_buffer.determine_breakpoints() peak_buffer.subset_data() self.peak_buffer = peak_buffer
def determine_calibration_timepairs(self): self.calibration_time_pairs = [] for i in self.master.reference: self.peak_name = i[0] self.peak_time = i[1] self.peak_window = i[2] self.peak = Peak(self) self.peak.determine_background_and_noise() self.peak.determine_signal_noise() time, intensity = zip( *self.peak.peak_data[self.peak.low:self.peak.high]) max_value = max(intensity) max_index = intensity.index(max_value) if self.peak.signal_noise >= self.settings.min_peak_SN: self.calibration_time_pairs.append((i[1], time[max_index]))
class Chromatogram(object): def __init__(self, master): self.filename = master.filename self.settings = master.settings self.master = master self.logger = master.logger self.axes = master.axes self.chrom_data = None self.peaks = [] def baseline_correction(self): # Background determination background = [] chunks = [ self.chrom_data[x:x + self.settings.points] for x in range(0, len(self.chrom_data), self.settings.points) ] for j in chunks: buff1, buff2 = zip(*j) min_index, _ = min(enumerate(buff2), key=operator.itemgetter(1)) if buff1[0] > self.settings.start and buff1[-1] < self.settings.end: background.append((buff1[min_index], buff2[min_index])) # Baseline function time, intensity = zip(*background) func = polyfit(time, intensity, self.settings.baseline_order) p = poly1d(func) # Transform time = [a for a, b in self.chrom_data] new_chrom_intensity = [b - p(a) for a, b in self.chrom_data] # Uplift low = bisect_left(time, self.settings.start) high = bisect_right(time, self.settings.end) offset = abs(min(min(new_chrom_intensity[low:high]), 0)) self.chrom_data = list( zip(time, [x + offset for x in new_chrom_intensity])) def calibrate_chromatogram(self): time, intensity = zip(*self.chrom_data) time = self.calibration_function(time) self.chrom_data = list(zip(time, intensity)) def determine_calibration_timepairs(self): self.calibration_time_pairs = [] for i in self.master.reference: self.peak_name = i[0] self.peak_time = i[1] self.peak_window = i[2] self.peak = Peak(self) self.peak.determine_background_and_noise() self.peak.determine_signal_noise() time, intensity = zip( *self.peak.peak_data[self.peak.low:self.peak.high]) max_value = max(intensity) max_index = intensity.index(max_value) if self.peak.signal_noise >= self.settings.min_peak_SN: self.calibration_time_pairs.append((i[1], time[max_index])) def determine_calibration_function(self): expected, observed = zip(*self.calibration_time_pairs) z = polyfit(observed, expected, 2) self.calibration_function = poly1d(z) def generate_pdf_report(self): pdf = Pdf(self) pdf.plot_overview() for self.peak in self.peaks: pdf.plot_individual() pdf.close() def normalize_chromatogram(self): time, intensity = zip(*self.chrom_data) # Normalize to maximum intensity maximum = max( intensity[bisect_left(time, self.settings.start ):bisect_right(time, self.settings.end)]) normalized_intensity = [b / maximum for a, b, in self.chrom_data] self.chrom_data = list(zip(time, normalized_intensity)) def open_chromatogram(self): file_parser(self) def plot_chromatogram(self): label = PurePath(self.filename).stem time, intensity = zip(*self.chrom_data) self.axes.plot(time, intensity, label=str(label)) def quantify_chromatogram(self): time, _ = zip(*self.chrom_data) self.peaks = [] # Iterate over peaks for i in self.master.reference: self.peak_name = i[0] self.peak_time = i[1] self.peak_window = i[2] self.peak = Peak(self) # Ignore peaks outside the Trace RT window if self.peak_time < self.settings.start+self.settings.background_window \ or self.peak_time > self.settings.end-self.settings.background_window: continue # Background correct self.peak.determine_background_and_noise() if self.peak.background < 0.: self.peak.background_correct() self.peak.determine_background_and_noise() # Determine Areas, background and noise self.peak.determine_peak_area() self.peak.determine_background_area() self.peak.determine_peak_noise() self.peak.determine_signal_noise() self.peak.determine_total_area() # Data Subset (based on second derivative) self.peak.determine_spline_and_derivative() self.peak.determine_breakpoints() self.peak.subset_data() # Gaussian fit try: self.peak.determine_gaussian_coefficients() if self.peak.coeff.size > 0: self.peak.determine_gaussian_area() self.peak.determine_gaussian_parameters() self.peak.determine_height() self.peak.determine_actual_time() self.peak.determine_residual() except AttributeError: self.logger.warning('Unable to determine Gaussian fit for' + f'{self.peak_name}') pass # Results self.peaks.append(self.peak) def smooth_chromatogram(self): # Apply Savitzky-Golay filter # TODO: Allow user to specify Smoothing method time, intensity = zip(*self.chrom_data) new = savgol_filter(intensity, 21, 3) self.chrom_data = list(zip(time, new)) def save_chromatogram(self): with open(self.filename, 'w') as fw: for data_point in self.trace.chrom_data: fw.write( str( format(data_point[0], '0.' + str(self.settings.decimal_numbers) + 'f')) + '\t' + str( format(data_point[1], '0.' + str(self.settings.decimal_numbers) + 'f')) + '\n')
def detect_peaks(self, master): orig_time, orig_intensity = zip(*self.chrom.trace.chrom_data) curr_intensity = orig_intensity time_start = bisect_left(orig_time, self.settings.start) time_end = bisect_right(orig_time, self.settings.end) # Loop till intensity falls below specified threshold while (max(curr_intensity[time_start:time_end]) > self.settings.peak_detection_min * max(orig_intensity[time_start:time_end])): self.window = (self.settings.end - self.settings.start) / 2 self.time = self.window + self.settings.start # Determine breaks and get subset of data self.breaks = self.functions.determine_breakpoints(self) self.data_subset = self.functions.subset_data(self) # Get time and intensity lists x_data, _ = zip(*self.data_subset) # Create Peak() object self.peak = None self.window = (x_data[-1] - x_data[0]) / 2 self.time = self.window + x_data[0] self.peak = Peak(self) # Gaussian fit self.peak.determine_gaussian_coefficients(self) if self.peak.coeff.any(): new_intensity = [] for index, i in enumerate(curr_intensity): new_intensity.append(i - Fitting().gauss_function( orig_time[index], *self.peak.coeff)) curr_intensity = new_intensity # Subtract Gaussian intensity from the current intensity self.chrom.trace.chrom_data = list(zip(orig_time, curr_intensity)) # Create Gaussian data at 3 sigma width gauss_start = self.time - 3 * self.peak.coeff[2] gauss_end = self.time + 3 * self.peak.coeff[2] gauss_time = linspace(gauss_start, gauss_end, (gauss_end - gauss_start) * 1000) gauss_intensity = Fitting().gauss_function(gauss_time, *self.peak.coeff) # Store detected peak self.detected_peaks.append({ 'data': list(zip(gauss_time, gauss_intensity)), 'coeff': self.peak.coeff, 'central_time': self.time }) # Sort by retention time self.detected_peaks = sorted(self.detected_peaks, key=lambda x: x['central_time']) # Restore original data self.chrom.trace.chrom_data = list(zip(orig_time, orig_intensity))
class PeakDetection(object): def __init__(self, master): self.settings = master.settings self.logger = logging.getLogger(__name__) self.functions = master.functions self.chrom = master.chrom self.detected_peaks = [] def detect_peaks(self, master): orig_time, orig_intensity = zip(*self.chrom.trace.chrom_data) curr_intensity = orig_intensity time_start = bisect_left(orig_time, self.settings.start) time_end = bisect_right(orig_time, self.settings.end) # Loop till intensity falls below specified threshold while (max(curr_intensity[time_start:time_end]) > self.settings.peak_detection_min * max(orig_intensity[time_start:time_end])): self.window = (self.settings.end - self.settings.start) / 2 self.time = self.window + self.settings.start # Determine breaks and get subset of data self.breaks = self.functions.determine_breakpoints(self) self.data_subset = self.functions.subset_data(self) # Get time and intensity lists x_data, _ = zip(*self.data_subset) # Create Peak() object self.peak = None self.window = (x_data[-1] - x_data[0]) / 2 self.time = self.window + x_data[0] self.peak = Peak(self) # Gaussian fit self.peak.determine_gaussian_coefficients(self) if self.peak.coeff.any(): new_intensity = [] for index, i in enumerate(curr_intensity): new_intensity.append(i - Fitting().gauss_function( orig_time[index], *self.peak.coeff)) curr_intensity = new_intensity # Subtract Gaussian intensity from the current intensity self.chrom.trace.chrom_data = list(zip(orig_time, curr_intensity)) # Create Gaussian data at 3 sigma width gauss_start = self.time - 3 * self.peak.coeff[2] gauss_end = self.time + 3 * self.peak.coeff[2] gauss_time = linspace(gauss_start, gauss_end, (gauss_end - gauss_start) * 1000) gauss_intensity = Fitting().gauss_function(gauss_time, *self.peak.coeff) # Store detected peak self.detected_peaks.append({ 'data': list(zip(gauss_time, gauss_intensity)), 'coeff': self.peak.coeff, 'central_time': self.time }) # Sort by retention time self.detected_peaks = sorted(self.detected_peaks, key=lambda x: x['central_time']) # Restore original data self.chrom.trace.chrom_data = list(zip(orig_time, orig_intensity)) def plot_peaks(self, master): for index, peak in enumerate(self.detected_peaks): x_array, y_array = zip(*peak['data']) master.axes.fill_between(x_array, 0, y_array, alpha=0.5, label='Peak ' + str(index + 1)) def write_peaks(self, master): save_file = filedialog.asksaveasfilename(title='Save Annotation File') with Path(save_file).open('w') as fw: fw.write('Index\tTime\tWindow\n') for index, peak in enumerate(self.detected_peaks): time, intensity = zip(*peak['data']) max_intensity_index = intensity.index(max(intensity)) peak_maximum = time[max_intensity_index] if self.settings.peak_detection_edge == 'Sigma': window = (self.settings.peak_detection_edge_value * peak['coeff'][2]) elif self.settings.peak_detection_edge == 'FWHM': window = abs(2 * peak['coeff'][2] * sqrt(2 * log(2))) else: window = None fw.write( str(index + 1) + '\t' + str( format(peak_maximum, '0.' + str(self.settings.decimal_numbers) + 'f')) + '\t' + str( format(window, '0.' + str(self.settings.decimal_numbers) + 'f')) + '\n')