def compute(self, qlplate, plate_metric): wells = qlplate.analyzed_wells.values() fam_hi = [w for w in wells if w.sample_name in ('FAM HI', 'FAM 350nM')] fam_lo = [w for w in wells if w.sample_name in ('FAM LO', 'FAM 40nM')] vic_hi = [w for w in wells if w.sample_name in ('VIC HI', 'VIC 350nM')] vic_lo = [w for w in wells if w.sample_name in ('VIC LO', 'VIC 70nM')] if fam_hi and vic_hi: fam_hi_peaks = accepted_peaks(fam_hi[0]) vic_hi_peaks = accepted_peaks(vic_hi[0]) # get tight rain boundaries (3.25% CV*3) -- below fam_hi, below vic_hi nil, nil, nil, nil, nil, nil, fam_low = rain_pvalues_thresholds(fam_hi_peaks, channel_num=0, threshold=None, pct_boundary=.0975) nil, nil, nil, nil, nil, nil, vic_low = rain_pvalues_thresholds(vic_hi_peaks, channel_num=1, threshold=None, pct_boundary=.135) all_peaks = np.hstack([fam_hi_peaks, vic_hi_peaks]) # find total % of all peaks dontcare, dontcare, dontcare, rain = cluster_2d(all_peaks, fam_low, vic_low) plate_metric.hi_cluster_rain = float(len(rain))/len(all_peaks) if fam_lo and vic_lo: fam_lo_peaks = accepted_peaks(fam_lo[0]) vic_lo_peaks = accepted_peaks(vic_lo[0]) # get tight rain boundaries (4.5% CV*3) -- below fam_hi, below vic_hi nil, nil, nil, nil, nil, nil, fam_low = rain_pvalues_thresholds(fam_lo_peaks, channel_num=0, threshold=None, pct_boundary=.0975) nil, nil, nil, nil, nil, nil, vic_low = rain_pvalues_thresholds(vic_lo_peaks, channel_num=1, threshold=None, pct_boundary=.135) all_peaks = np.hstack([fam_lo_peaks, vic_lo_peaks]) # find total % of all peaks dontcare, dontcare, dontcare, rain = cluster_2d(all_peaks, fam_low, vic_low) plate_metric.lo_cluster_rain = float(len(rain))/len(all_peaks) return plate_metric
def fpfn_by_bin(plate_objects, vic_channels, sample_names, bin_func): bins = set([bin_func(c) for c in vic_channels]) bin_plots = dict([(bin, []) for bin in bins]) bin_wells = defaultdict(list) # divide into plates for bin, group in groupinto(vic_channels, bin_func): # this is a wacky grouping, but for reuse in plate_objects (why did I not pick plate ids again?) plate_groups = groupinto(group, lambda c: (c.well.plate.file.dirname, c.well.plate.file.basename)) for plate_id, channels in plate_groups: qplate = plate_objects[plate_id] positives = [c for c in channels if c.well.well_name in fpfn_positive_well_names] negatives = [c for c in channels if c.well.well_name in fpfn_negative_well_names] # compute a threshold which is 1/4 between the positive and negative means for the plate positive_means = [] negative_means = [] for p in positives: amps = vic_amplitudes(accepted_peaks(qplate.wells[p.well.well_name])) positive_means.append((len(amps), np.mean(amps)*len(amps))) if positive_means: positive_mean = sum([pm[1] for pm in positive_means])/sum([pm[0] for pm in positive_means]) else: positive_mean = 32767 for n in negatives: amps = vic_amplitudes(accepted_peaks(qplate.wells[n.well.well_name])) negative_means.append((len(amps), np.mean(amps)*len(amps))) if negative_means: negative_mean = sum([nm[1] for nm in negative_means])/sum([nm[0] for nm in negative_means]) else: negative_mean = 0 threshold = ((3*negative_mean)+positive_mean)/4 fps = [c for c in channels if c.well.well_name in fpfn_fp_well_names] fns = [c for c in channels if c.well.well_name in fpfn_fn_well_names] fp_counts = [] fn_counts = [] for f in fps: pos, neg = cluster_1d(accepted_peaks(qplate.wells[f.well.well_name]), 1, threshold) fp_counts.append((f.well.id, len(pos), 10000*(float(len(pos))/(float(len(pos))+float(len(neg)))), qplate.wells[f.well.well_name])) for f in fns: pos, neg = cluster_1d(accepted_peaks(qplate.wells[f.well.well_name]), 1, threshold) fn_counts.append((f.well.id, len(neg), 10000*(float(len(neg))/(float(len(pos))+float(len(neg)))))) bin_wells[bin].append((fp_counts, fn_counts, threshold)) return bin_wells
def compute(self, qlplate, plate_metric): wells = qlplate.analyzed_wells.values() fam_hi = [w for w in wells if w.sample_name in ('FAM HI', 'FAM 350nM')] fam_lo = [w for w in wells if w.sample_name in ('FAM LO', 'FAM 40nM')] vic_hi = [w for w in wells if w.sample_name in ('VIC HI', 'VIC 350nM')] vic_lo = [w for w in wells if w.sample_name in ('VIC LO', 'VIC 70nM')] if fam_hi and fam_lo and vic_hi and vic_lo: fam_hi_peaks = accepted_peaks(fam_hi[0]) fam_lo_peaks = accepted_peaks(fam_lo[0]) vic_hi_peaks = accepted_peaks(vic_hi[0]) vic_lo_peaks = accepted_peaks(vic_lo[0]) fam_hi_f = np.mean(fam_amplitudes(fam_hi_peaks)) fam_hi_v = np.mean(vic_amplitudes(fam_hi_peaks)) fam_lo_f = np.mean(fam_amplitudes(fam_lo_peaks)) fam_lo_v = np.mean(vic_amplitudes(fam_lo_peaks)) vic_hi_f = np.mean(fam_amplitudes(vic_hi_peaks)) vic_hi_v = np.mean(vic_amplitudes(vic_hi_peaks)) vic_lo_f = np.mean(fam_amplitudes(vic_lo_peaks)) vic_lo_v = np.mean(vic_amplitudes(vic_lo_peaks)) fam_vec = [fam_hi_v-fam_lo_v, fam_hi_f-fam_lo_f] vic_vec = [vic_hi_v-vic_lo_v, vic_hi_f-vic_lo_f] dot = np.dot(fam_vec, vic_vec) norm_diff = abs(90-np.rad2deg(math.acos(dot/(math.hypot(*fam_vec)*math.hypot(*vic_vec))))) fam_diff = np.rad2deg(math.atan(fam_vec[0]/fam_vec[1])) vic_diff = np.rad2deg(math.atan(vic_vec[1]/vic_vec[0])) # maybe there is an easier way to do this, but this is how my brain works # y = mx + b forever mf = fam_vec[1]/fam_vec[0] mv = vic_vec[1]/vic_vec[0] bf = fam_hi_f - mf*fam_hi_v bv = vic_hi_f - mv*vic_hi_v xv = (bv-bf)/(mf-mv) xf = mf*xv + bf origin_diff = math.sqrt(xv**2+xf**2) plate_metric.fam_normal_offset = fam_diff plate_metric.vic_normal_offset = vic_diff plate_metric.famvic_normal_offset = norm_diff plate_metric.famvic_origin_offset = origin_diff else: plate_metric.fam_normal_offset = None plate_metric.vic_normal_offset = None plate_metric.famvic_normal_offset = None plate_metric.famvic_origin_offset = None return plate_metric
def air_hist(self, id=None, channel_num=0, *args, **kwargs): from qtools.lib.nstats.peaks import gap_air from pyqlb.nstats.well import accepted_peaks from pyqlb.nstats.peaks import color_uncorrected_peaks, channel_amplitudes, peak_times from qtools.lib.mplot import air_hist, cleanup, render as plt_render qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) c.channel_num = int(channel_num) threshold = c.vic_threshold if c.channel_num == 1 else c.fam_threshold cutoff = request.params.get('cutoff', 500) # can detect air on either channel (especially if VICs super low) # but always report VIC amplitude air_drops = gap_air(qlwell, c.channel_num, threshold=threshold) uncorrected_air = color_uncorrected_peaks(air_drops, qlwell.color_compensation_matrix) # count number of accepted peak times air_drop_times = peak_times(air_drops) accepted_times = peak_times(accepted_peaks(qlwell)) num_air_accepted = len([t for t in air_drop_times if t in accepted_times]) # always gate on VIC air_amps = channel_amplitudes(uncorrected_air, 1) title = 'Air Droplet Histogram - %s, %s (%s)' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if c.channel_num == 1 else 'FAM') fig = air_hist(title, air_amps, cutoff=cutoff, num_accepted=num_air_accepted) response.content_type = 'image/png' imgdata = plt_render(fig, dpi=72) cleanup(fig) return imgdata
def svilen(self, id=None, *args, **kwargs): from pyqlb.nstats.well import accepted_peaks from pyqlb.nstats.peaks import cluster_2d, peak_times, fam_widths from pyqlb.factory import QLNumpyObjectFactory from qtools.lib.mplot import svilen, cleanup, render as plt_render qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) well_path = self.__well_path() # oh shit factory = QLNumpyObjectFactory() raw_well = factory.parse_well(well_path) crap, crap, gold, crap = cluster_2d(accepted_peaks(qlwell), c.fam_threshold, c.vic_threshold) times = peak_times(gold) widths = fam_widths(gold) title = "VIC+/FAM- droplet traces (accepted events)" ranges = [(int(t-(w*2)), int(t+(w*2))) for t, w in zip(times, widths)] if c.fam_threshold == 0 or c.vic_threshold == 0: ranges = [] title = "%s (no events in quadrant)" % title elif len(ranges) > 100: ranges = ranges[:100] title = "%s (truncated at first 100)" % title fig = svilen(title, raw_well.samples, ranges, widths) response.content_type = 'image/png' imgdata = plt_render(fig, dpi=72) cleanup(fig) return imgdata
def cluster_csv(self, id=None, show_only_gated=True, *args, **kwargs): from pyqlb.nstats.well import accepted_peaks qlwell = self.__qlwell_from_threshold_form(id) if show_only_gated != 'False': peaks = accepted_peaks(qlwell) else: peaks = qlwell.peaks from pyqlb.nstats.peaks import fam_amplitudes, fam_widths, vic_amplitudes, vic_widths, peak_times from pyqlb.nstats.well import well_observed_cluster_assignments response.headers['Content-Type'] = 'text/csv' h.set_download_response_header(request, response, "%s_%s%s.csv" % \ (str(c.well.plate.plate.name), str(c.well.well_name), '' if show_only_gated != 'False' else '_all')) out = StringIO.StringIO() csvwriter = csv_pkg.writer(out) csvwriter.writerow(['Plate',c.well.plate.plate.name]) csvwriter.writerow(['Well',c.well.well_name]) csvwriter.writerow([]) csvwriter.writerow(['Time','FAMAmplitude','FAMWidth','VICAmplitude','VICWidth','Cluster']) csvwriter.writerow([]) pts = peak_times(peaks) fas = fam_amplitudes(peaks) fws = fam_widths(peaks) vas = vic_amplitudes(peaks) vws = vic_widths(peaks) cls = well_observed_cluster_assignments(qlwell, peaks) for row in zip(pts, fas, fws, vas, vws, cls): csvwriter.writerow(row) csv = out.getvalue() out.close() return csv
def dnr_by_bin(plate_objects, fam_channels, sample_names, bin_func): """ @deprecated - use metrics """ bins = set([bin_func(c) for c in fam_channels]) # TODO: do sample names here bin_plots = dict([(bin, [[0.001,None],[0.01,None],[0.1,None],[1,None],[5,None]]) for bin in bins]) groups = [] groups.extend([(sample_name, groupinto(sample_name_channel_filter(fam_channels, sample_name), bin_func)) for sample_name in sample_names]) for i, (sample, group) in enumerate(groups): for bin, channels in group: conc_array = [] for c in channels: qplate = plate_objects[(c.well.plate.file.dirname, c.well.plate.file.basename)] well = qplate.wells[c.well.well_name] # TODO: use dynamic threshold or keep 4000? pos, neg = cluster_1d(accepted_peaks(well), 0, 4000) conc, clow, chigh = concentration_interval(len(pos), len(neg), droplet_vol=well.droplet_volume) conc_array.append((max(conc,0.0001), max(clow,0.0001), max(chigh,0.0001))) if len(conc_array) > 0: conc_mean = np.mean([ca[0] for ca in conc_array]) bin_plots[bin][i][1] = (conc_mean, conc_array) return bin_plots
def compute(self, qlwell, well_metric): target_channel = qlwell.channels[self.target_channel_num] reference_channel = qlwell.channels[self.reference_channel_num] cnv, cnv_low, cnv_high = well_observed_cnv_interval(qlwell, self.target_channel_num, self.reference_channel_num) inverse_cnv, inverse_cnv_low, inverse_cnv_high = well_observed_cnv_interval(qlwell, self.reference_channel_num, self.target_channel_num) well_metric.cnv = cnv well_metric.cnv_lower_bound = cnv_low well_metric.cnv_upper_bound = cnv_high well_metric.inverse_cnv = inverse_cnv well_metric.inverse_cnv_lower_bound = inverse_cnv_low well_metric.inverse_cnv_upper_bound = inverse_cnv_high # cnv calc mode is only used for display at the moment, should rename and take out of CNVCalculator. if qlwell.clusters_defined: well_metric.cnv_calc_mode = QLWellChannelStatistics.CONC_CALC_MODE_CLUSTER else: well_metric.cnv_calc_mode = QLWellChannelStatistics.CONC_CALC_MODE_THRESHOLD if not target_channel.statistics.threshold or not reference_channel.statistics.threshold: # cannot compute CNV rise ratio if cannot compute threshold -- pos/neg unknown convert_nan_to_none(well_metric) return well_metric ok_peaks = accepted_peaks(qlwell) qsize = len(ok_peaks)/4 # CLUSTER-TODO: fix if(qsize >= 1000): fq = ok_peaks[:qsize] lq = ok_peaks[(len(ok_peaks)-qsize):] fq_target_pos, fq_target_neg = cluster_1d(fq, self.target_channel_num, qlwell.channels[self.target_channel_num].statistics.threshold) lq_target_pos, lq_target_neg = cluster_1d(lq, self.target_channel_num, qlwell.channels[self.target_channel_num].statistics.threshold) fq_reference_pos, fq_reference_neg = cluster_1d(fq, self.reference_channel_num, qlwell.channels[self.reference_channel_num].statistics.threshold) lq_reference_pos, lq_reference_neg = cluster_1d(lq, self.reference_channel_num, qlwell.channels[self.reference_channel_num].statistics.threshold) fq_cnv = get_cnv(len(fq_target_pos), len(fq_target_neg), len(fq_reference_pos), len(fq_reference_neg), reference_copies=qlwell.ref_copy_num) lq_cnv = get_cnv(len(lq_target_pos), len(lq_target_neg), len(lq_reference_pos), len(lq_reference_neg), reference_copies=qlwell.ref_copy_num) if not fq_cnv: well_metric.cnv_rise_ratio = None else: well_metric.cnv_rise_ratio = lq_cnv/fq_cnv # TODO: probably best done elsewhere convert_nan_to_none(well_metric) return well_metric
def compute(self, qlwell, qlwell_channel, well_channel_metric): if qlwell.sample_name and 'NTC' in qlwell.sample_name: ap = accepted_peaks(qlwell) if qlwell_channel.channel_num == 0: threshold = self.fam_threshold else: threshold = self.vic_threshold ntc_pos, ntc_neg = cluster_1d(ap, qlwell_channel.channel_num, threshold) well_channel_metric.ntc_positives = len(ntc_pos) return well_channel_metric
def temporal2d(self, id=None, *args, **kwargs): from qtools.lib.nstats.peaks import accepted_peaks from pyqlb.nstats.peaks import peak_times, fam_amplitudes, vic_amplitudes qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) ok_peaks = accepted_peaks(qlwell) c.tvf = zip(peak_times(ok_peaks), vic_amplitudes(ok_peaks), fam_amplitudes(ok_peaks)) return render('/well/temporal2d.html')
def count_positives_in_well(well, channel): # return count of positives and total events from pyqlb.nstats.peaks import cluster_1d, width_gated, quality_gated chn_stats = well.channels[channel].statistics threshold = chn_stats.threshold min_width_gate = chn_stats.min_width_gate max_width_gate = chn_stats.max_width_gate min_quality_gate = chn_stats.min_quality_gate accepted_events = accepted_peaks(well) positives, negatives = cluster_1d(accepted_events, channel, threshold) return len(positives), len(positives)+len(negatives)
def compute(self, qlwell, well_metric): if qlwell.sample_name not in self.test_well_names: return well_metric air_drops = gap_air(qlwell, self.channel_num, max_amp=self.air_max_threshold, threshold=qlwell.channels[self.channel_num].statistics.threshold or None) # Rev A: droplets would not be there if below min amplitude # Rev B: droplets will have min amplitude flag if they were below 500 # in the VIC channel accepted_times = peak_times(accepted_peaks(qlwell)) air_times = peak_times(air_drops) well_metric.air_droplets = len([t for t in air_times if t in accepted_times]) well_metric.air_droplets_threshold = qlwell.channels[1].statistics.trigger_min_amplitude
def compute(self, qlplate, plate_metric): wmd = plate_metric.well_metric_name_dict twm = [wmd.get(name, None) for name in self.threshold_well_names] twm = [t for t in twm if t] thresholds = self._compute_thresholds(twm) for name in self.measurement_well_names: wm = wmd.get(name, None) if not wm: continue for num in self.channel_nums: pos, neg = cluster_1d(accepted_peaks(qlplate.analyzed_wells[name]), num, thresholds[num]) wm.well_channel_metrics[num].false_positive_peaks = len(pos) wm.well_channel_metrics[num].manual_threshold = thresholds[num] return plate_metric
def amphist(self, id=None, channel_num=0, *args, **kwargs): from qtools.lib.mplot import plot_amp_hist, cleanup, render as plt_render from pyqlb.nstats.well import accepted_peaks response.content_type = 'image/png' c.channel_num = int(channel_num) qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) peaks = accepted_peaks(qlwell) fig = plot_amp_hist(peaks, title='%s - %s' % (c.well.plate.plate.name, c.well.well_name), channel_num=c.channel_num, threshold=(c.vic_threshold if c.channel_num == 1 else c.fam_threshold)) imgdata = plt_render(fig, dpi=72) cleanup(fig) return imgdata
def compute(self, qlwell, well_metric): # do not compute a metric if neither well has a threshold set channels = qlwell.channels if not channels or len(channels) != 2: return None for c in channels: if c.statistics.threshold == 0 or not c.statistics.threshold: return None # get clusters peaks = accepted_peaks(qlwell) fampos_vicpos, fampos_vicneg, famneg_vicpos, famneg_vicneg = \ cluster_2d(peaks, channels[0].statistics.threshold, channels[1].statistics.threshold) well_metric.null_linkage = linkage_2d(len(fampos_vicpos), len(fampos_vicneg), len(famneg_vicpos), len(famneg_vicneg)) return well_metric
def compute(self, qlplate, plate_metric): wmd = plate_metric.well_metric_name_dict pwm = [wmd.get(name, None) for name in self.positive_well_names] nwm = [wmd.get(name, None) for name in self.negative_well_names] pwm = [p for p in pwm if p] nwm = [n for n in nwm if n] thresholds = self._compute_thresholds(pwm, nwm) for name in self.measurement_well_names: wm = wmd.get(name, None) if not wm: continue for num in self.channel_nums: pos, neg = cluster_1d(accepted_peaks(qlplate.analyzed_wells[name]), num, thresholds[num]) wm.well_channel_metrics[num].false_negative_peaks = len(neg) wm.well_channel_metrics[num].manual_threshold = thresholds[num] return plate_metric
def _compute_well_metrics(qlwell, well_metric): """ Populate the well_metric object with statistics derived from the QLWell object. This computes well-specific metrics, which are channel-agnostic, such as width, number of accepted peaks, and B-score. :param qlwell: QLWell record read from QLP. :param well_metric: WellMetric object meant to be stored. :return: The WellMetric object, though it gets side-effected. """ # assume that width, events are same in both channels; so the width # and quality gates should be OK accepted_events = accepted_peaks(qlwell) wm = well_metric # for convenience wm.accepted_event_count = len(accepted_events) wm.total_event_count = len(qlwell.peaks) # TODO: double check on desired values for these (width of accepted, or overall width?) # current hunch is to use the width of all events width_peaks = above_min_amplitude_peaks(qlwell) wm.width_mean = np.mean(fam_widths(width_peaks)) wm.width_variance = np.std(fam_widths(width_peaks)) wm.accepted_width_mean = np.mean(fam_widths(accepted_events)) wm.accepted_width_stdev = np.std(fam_widths(accepted_events)) wm.rejected_peaks = qlwell.statistics.rejected_peaks wm.min_amplitude_peaks = len(min_amplitude_peaks(qlwell)) wm.vertical_streak_events = qlwell.statistics.vertical_streak_peaks wm.sum_baseline_mean = qlwell.statistics.sum_baseline_mean wm.sum_baseline_stdev = qlwell.statistics.sum_baseline_stdev wm.short_interval_count = narrow_droplet_spacing_count(qlwell, threshold=NARROW_NORMALIZED_DROPLET_SPACING) wm.short_interval_threshold = NARROW_NORMALIZED_DROPLET_SPACING wm.balance_score = well_balance_score_2d(qlwell)[0] wm.fragmentation_probability = well_fragmentation_probability(qlwell)[0] #new droplet metrics -> Diagonal scatter.... NEW_DROPLET_CLUSTER_WELL_METRICS_CALCULATOR.compute(qlwell, wm) global DEFAULT_CNV_CALC DEFAULT_CNV_CALC.compute(qlwell, wm) global DEFAULT_NULL_LINKAGE_CALC DEFAULT_NULL_LINKAGE_CALC.compute(qlwell, wm) return wm
def cluster(self, id=None, *args, **kwargs): from qtools.lib.mplot import plot_threshold_2d, cleanup, render as plt_render from qtools.lib.nstats.peaks import accepted_peaks response.content_type = 'image/png' qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']] boundaries = (-2000,-2000,max_amplitudes[1],max_amplitudes[0]) # to emulate current behavior -- include gated events peaks = accepted_peaks(qlwell) fig = plot_threshold_2d(peaks, thresholds=(c.fam_threshold, c.vic_threshold), boundaries=boundaries) response.content_type = 'image/png' imgdata = plt_render(fig, dpi=72) cleanup(fig) return imgdata
def peak_csv(self, id=None, show_only_gated=True, *args, **kwargs): from qtools.lib.nstats.peaks import accepted_peaks qlwell = self.__qlwell_from_threshold_form(id) if show_only_gated != 'False': peaks = accepted_peaks(qlwell) else: peaks = qlwell.peaks from pyqlb.nstats.peaks import fam_amplitudes, fam_widths, fam_quality, vic_amplitudes, vic_widths, vic_quality, peak_times response.headers['Content-Type'] = 'text/csv' h.set_download_response_header(request, response, "%s_%s%s.csv" % \ (str(c.well.plate.plate.name), str(c.well.well_name), '' if show_only_gated != 'False' else '_all')) out = StringIO.StringIO() csvwriter = csv_pkg.writer(out) csvwriter.writerow(['Plate',c.well.plate.plate.name]) csvwriter.writerow(['Well',c.well.well_name]) csvwriter.writerow([]) csvwriter.writerow(['FAMThreshold',qlwell.channels[0].statistics.threshold]) csvwriter.writerow(['VICThreshold',qlwell.channels[1].statistics.threshold]) csvwriter.writerow(['WidthGate',qlwell.channels[0].statistics.min_width_gate,qlwell.channels[0].statistics.max_width_gate]) csvwriter.writerow(['MinQualityGate',qlwell.channels[0].statistics.min_quality_gate]) csvwriter.writerow([]) csvwriter.writerow(['Time','FAMAmplitude','FAMWidth','FAMQuality','VICAmplitude','VICWidth','VICQuality']) csvwriter.writerow([]) pts = peak_times(peaks) fas = fam_amplitudes(peaks) fws = fam_widths(peaks) fqs = fam_quality(peaks) vas = vic_amplitudes(peaks) vws = vic_widths(peaks) vqs = vic_quality(peaks) for row in zip(pts, fas, fws, fqs, vas, vws, vqs): csvwriter.writerow(row) csv = out.getvalue() out.close() return csv
def threshold(self, id=None, show_only_gated=True, *args, **kwargs): from qtools.lib.mplot import plot_fam_vic_peaks, cleanup, render as plt_render from qtools.lib.nstats.peaks import accepted_peaks response.content_type = 'image/png' qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']] # to emulate current behavior -- include gated events if show_only_gated != 'False': peaks = accepted_peaks(qlwell) else: peaks = qlwell.peaks fig = plot_fam_vic_peaks(peaks, thresholds=(c.fam_threshold, c.vic_threshold), max_amplitudes=max_amplitudes, background_rgbs=self.__get_1d_background_rgbs(qlwell)) response.content_type = 'image/png' imgdata = plt_render(fig, dpi=72) cleanup(fig) return imgdata
def cluster2d(self, id=None, *args, **kwargs): from qtools.lib.mplot import plot_cluster_2d, cleanup, render as plt_render from qtools.lib.nstats.peaks import accepted_peaks response.content_type = 'image/png' qlwell = self.__qlwell_from_threshold_form(id) self.__set_threshold_context(qlwell) max_amplitudes = [self.form_result['max_fam_amplitude'], self.form_result['max_vic_amplitude']] boundaries = (-2000,-2000,max_amplitudes[1],max_amplitudes[0]) # to emulate current behavior -- include gated events peaks = accepted_peaks(qlwell) threshold_fallback = qlwell.clustering_method == QLWell.CLUSTERING_TYPE_THRESHOLD fig = plot_cluster_2d(peaks, thresholds=(c.fam_threshold, c.vic_threshold), boundaries=boundaries, use_manual_clusters=not well_channel_automatic_classification(qlwell), highlight_thresholds=threshold_fallback) response.content_type = 'image/png' imgdata = plt_render(fig, dpi=72) cleanup(fig) return imgdata
def _compute_well_channel_metrics(qlwell, well_channel_metric, channel_num): """ Internal method for populating a WellChannelMetric object from statistics determined by analyzing the QLWell's channel object. This will populate the well_channel_metric object with information such as positives and negatives, concentration, polydispersity, and other metrics that have separate values for FAM and VIC channels. :param qlwell: The QLWell object created by reading a QLP file. :param well_channel_metric: The WellChannelMetric object to populate. :param channel_num: Which channel to analyze. """ # for convenience wcm = well_channel_metric stats = qlwell.channels[channel_num].statistics wcm.min_quality_gating = stats.min_quality_gate wcm.min_quality_gating_conf = stats.min_quality_gate_conf wcm.min_width_gate = stats.min_width_gate wcm.min_width_gate_conf = stats.min_width_gate_conf wcm.max_width_gate = stats.max_width_gate wcm.max_width_gate_conf = stats.max_width_gate_conf wcm.width_gating_sigma = stats.width_gating_sigma # TODO: try to guarantee automatic threshold here? wcm.threshold = stats.threshold wcm.threshold_conf = stats.threshold_conf wcm.auto_threshold_expected = False wcm.concentration = stats.concentration wcm.conc_lower_bound = stats.concentration_lower_bound wcm.conc_upper_bound = stats.concentration_upper_bound wcm.conc_calc_mode = stats.concentration_calc_mode wcm.clusters_automatic = well_channel_automatic_classification(qlwell, channel_num) wcm.decision_tree_flags = qlwell.channels[channel_num].decision_tree_flags ap = accepted_peaks(qlwell) if channel_num == 0: ampfunc = fam_amplitudes elif channel_num == 1: ampfunc = vic_amplitudes else: raise ValueError, "Incompatible channel number: %s" % channel_num wcm.amplitude_mean = np.mean(ampfunc(ap)) wcm.amplitude_stdev = np.std(ampfunc(ap)) allpeaks = qlwell.peaks wcm.total_events_amplitude_mean = np.mean(ampfunc(allpeaks)) wcm.total_events_amplitude_stdev = np.std(ampfunc(allpeaks)) above_min_peaks = above_min_amplitude_peaks(qlwell) quality_gated_peaks = quality_rejected(above_min_peaks, wcm.min_quality_gating, channel_num, include_vertical_streak_flagged=False) wcm.quality_gated_peaks = len(quality_gated_peaks) width_gated_peaks = width_rejected(above_min_peaks, wcm.min_width_gate, wcm.max_width_gate, channel_num) wcm.width_gated_peaks = len(width_gated_peaks) # TODO add min amplitude, vertical streak wcm.s_value = separation_value(ap, channel_num, wcm.threshold) p_plus, p, p_minus = rain_pvalues(ap, channel_num, wcm.threshold) wcm.rain_p_plus = p_plus wcm.rain_p = p wcm.rain_p_minus = p_minus ## extra cluster events... NEW_DROPLET_CLUSTER_METRICS_CALCULATOR.compute(qlwell, qlwell.channels[channel_num], wcm) # DEFAULT_TEAVALS.compute(qlwell, qlwell.channels[channel_num], wcm) DEFAULT_POLYD_CALC.compute(qlwell, qlwell.channels[channel_num], wcm) DEFAULT_EXTRAC_CALC.compute(qlwell, qlwell.channels[channel_num], wcm) DEFAULT_NTC_POSITIVE_CALCULATOR.compute(qlwell, qlwell.channels[channel_num], wcm) wcm.baseline_mean = qlwell.channels[channel_num].statistics.baseline_mean wcm.baseline_stdev = qlwell.channels[channel_num].statistics.baseline_stdev wcm.cluster_conf = qlwell.channels[channel_num].statistics.cluster_conf positive_peaks, negative_peaks, unclassified_peaks = well_observed_positives_negatives(qlwell, channel_num) if len(positive_peaks) > 0 or len(negative_peaks) > 0: wcm.positive_peaks = len(positive_peaks) wcm.negative_peaks = len(negative_peaks) wcm.positive_mean = np.mean(ampfunc(positive_peaks)) wcm.positive_stdev = np.std(ampfunc(positive_peaks)) wcm.negative_mean = np.mean(ampfunc(negative_peaks)) wcm.negative_stdev = np.std(ampfunc(negative_peaks)) wcm.positive_skew = skew(positive_peaks, channel_num) wcm.positive_kurtosis = kurtosis(positive_peaks, channel_num) wcm.nonpositive_skew = skew(negative_peaks, channel_num) wcm.nonpositive_kurtosis = kurtosis(negative_peaks, channel_num) # CLUSTER-TODO: this is not going to be right for clusters. Consider # changing this. wcm.concentration_rise_ratio = quartile_concentration_ratio(qlwell, peaks=ap, channel_num=channel_num, threshold=wcm.threshold, min_events=4000) del positive_peaks del negative_peaks del unclassified_peaks else: wcm.nonpositive_skew = skew(ap, channel_num) wcm.nonpositive_kurtosis = kurtosis(ap, channel_num) del ap # daisy chain just in case return wcm