Exemple #1
0
    def compute(self, qlwell, qlwell_channel, well_channel_metric):
        # only return for >= 1000 peaks
        if len(qlwell.peaks) < 1000:
            return well_channel_metric
        
        data = polydisperse_peaks(qlwell, qlwell_channel.channel_num,
                               threshold=qlwell_channel.statistics.threshold)
        peaksets, rain_gates, width_gates = data
        
        poly_peaks = sum([len(p) for p in peaksets])
        # have to worry about min amplitude peaks here
        # found in well_metric but we don't have access in superclass
        above_min_amp_peaks = above_min_amplitude_peaks(qlwell)
        if len(above_min_amp_peaks) == 0:
            well_channel_metric.polydispersity = 0
        else:
            well_channel_metric.polydispersity = float(poly_peaks)/len(above_min_amp_peaks)

        if hasattr(qlwell, 'sum_amplitude_bins') and len(qlwell.sum_amplitude_bins) > 0:
            data = revb_polydisperse_peaks(qlwell, qlwell_channel.channel_num,
                                           threshold=qlwell_channel.statistics.threshold)
            peaksets, rain_gates, min_amps = data
            poly_peaks = sum([len(p) for p in peaksets])
            if len(above_min_amp_peaks) == 0:
                well_channel_metric.revb_polydispersity = 0
            else:
                well_channel_metric.revb_polydispersity = float(poly_peaks)/len(above_min_amp_peaks)
        else:
            well_channel_metric.revb_polydispersity = None
        return well_channel_metric
Exemple #2
0
    def galaxy_disperse_revb(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks
        from qtools.lib.mplot import galaxy_polydisperse_revb, cleanup, render as plt_render, empty_fig
        from qtools.lib.nstats.peaks import revb_polydisperse_peaks

        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))

        peaks = above_min_amplitude_peaks(qlwell)
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold

        title = 'GalaxyPDB - %s, %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        if hasattr(qlwell, 'sum_amplitude_bins') and len(qlwell.sum_amplitude_bins) > 0:
            polydisperse_data = revb_polydisperse_peaks(qlwell, channel_idx, threshold=threshold)
            poly_peaks, rain_boundaries, mean_amplitudes = polydisperse_data
            pos_peaks, midhigh_peaks, midlow_peaks, neg_peaks = poly_peaks
            pos, midhigh, midlow, neg = rain_boundaries
            fam_mean, vic_mean = mean_amplitudes
            
            fig = galaxy_polydisperse_revb(title, peaks, channel_idx, threshold,
                                           pos, midhigh, midlow, neg,
                                           pos_peaks, midhigh_peaks, midlow_peaks, neg_peaks,
                                           min_amplitude_excluded=True,
                                           sum_amplitude_bins=qlwell.sum_amplitude_bins, other_channel_mean=fam_mean if channel_idx == 1 else vic_mean)
            
        else:
            fig = empty_fig()
            ax = fig.add_subplot(111, title=title)
            ax.text(0.33,0.5, "No amplitude bins for this well.")
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Exemple #3
0
    def galaxy_extra(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks
        from qtools.lib.mplot import galaxy_extracluster, cleanup, render as plt_render
        from qtools.lib.nstats.peaks import extracluster_peaks

        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))

        peaks = above_min_amplitude_peaks(qlwell)
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold
        extra_data = extracluster_peaks(qlwell, channel_idx, threshold=threshold)
        extra_peaks, rain_boundaries, width_gates = extra_data
        pos, midhigh, midlow, neg = rain_boundaries
        min_gate, max_gate = width_gates
        title = 'GalaxyEX - %s, %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        fig = galaxy_extracluster(title, peaks, channel_idx, threshold, min_gate, max_gate,
                                  pos, midhigh, midlow, neg,
                                  extra_peaks,
                                  min_amplitude_excluded=True)
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Exemple #4
0
    def compute(self, qlwell, qlwell_channel, well_channel_metric):
        # only return for >= 1000 peaks
        if len(qlwell.peaks) < 1000:
            return well_channel_metric
        
        data = extracluster_peaks(qlwell, qlwell_channel.channel_num,
                                  threshold=qlwell_channel.statistics.threshold)
        peaks, rain_gates, width_gates = data
        # have to worry about min amplitude peaks here
        # found in well_metric but don't have access to wm in compute()
        above_min_amp_peaks = above_min_amplitude_peaks(qlwell)
        if len(above_min_amp_peaks) == 0:
            well_channel_metric.extracluster = 0
        else:
            well_channel_metric.extracluster = float(len(peaks))/len(above_min_amp_peaks)

        if hasattr(qlwell, 'sum_amplitude_bins') and len(qlwell.sum_amplitude_bins) > 0:
            data = revb_extracluster_peaks(qlwell, qlwell_channel.channel_num,
                                           threshold=qlwell_channel.statistics.threshold)
            peaks, rain_gates, mean_amps = data
            if len(above_min_amp_peaks) == 0:
                well_channel_metric.revb_extracluster = 0
            else:
                well_channel_metric.revb_extracluster = float(len(peaks))/len(above_min_amp_peaks)
        else:
            well_channel_metric.revb_extracluster = None
        return well_channel_metric
Exemple #5
0
    def contamination_carryover_peaks(self, qlplate, exclude_min_amplitude_peaks=True):
        """
        Returns (aggregate contamination peaks, aggregate gated contamination peaks, aggregate carryover peaks,
                 number of carryover wells, well name->#carryover well peaks per well)
        """
        well_pairs = []
        eventful_well = None
        stealth_well = None
        
        # FIXFIX relax when QuantaSoft bug is resolved
        #for well in qlplate.in_run_order:
        wells = sorted(qlplate.analyzed_wells.values(), cmp=QLWell.row_order_comparator)
        for well in sorted(qlplate.analyzed_wells.values(), cmp=QLWell.row_order_comparator):
            if well.original_sample_name not in self.empty_sample_names:
                stealth_well = None
                eventful_well = well
            elif well.original_sample_name in self.empty_sample_names:
                stealth_well = well
                if eventful_well:
                    well_pairs.append((eventful_well, stealth_well))
                    eventful_well = None
                    stealth_well = None
        
        contamination_peaks = np.ndarray([0], dtype=peak_dtype(2))
        gated_contamination_peaks = np.ndarray([0], dtype=peak_dtype(2))
        carryover_peaks = np.ndarray([0], dtype=peak_dtype(2))
        num_wells = 0
        carryover_well_peak_dict = dict()
        for e, s in well_pairs:
            num_wells = num_wells + 1
            stats = e.channels[self.channel_num].statistics
            threshold = stats.threshold
            min_width_gate, max_width_gate = well_static_width_gates(e)

            # TODO: what to do about quality gating?
            # get all contamination first above 750 RFU (assume threshold above 750?)
            if exclude_min_amplitude_peaks:
                peaks = above_min_amplitude_peaks(s)
            else:
                peaks = s.peaks
            
            well_contamination_peaks, too_low = cluster_1d(peaks, self.channel_num, 750)
            well_gated_contamination_peaks = width_gated(well_contamination_peaks,
                                                    min_width_gate=min_width_gate,
                                                    max_width_gate=max_width_gate,
                                                    on_channel_num=self.channel_num,
                                                    ignore_gating_flags=True)

            if threshold:
                well_carryover_peaks, under_threshold = cluster_1d(well_gated_contamination_peaks, self.channel_num, threshold)
            else:
                well_carryover_peaks = np.ndarray([0], dtype=peak_dtype(2))
            
            contamination_peaks = np.hstack([contamination_peaks, well_contamination_peaks])
            gated_contamination_peaks = np.hstack([gated_contamination_peaks, well_gated_contamination_peaks])
            carryover_peaks = np.hstack([carryover_peaks, well_carryover_peaks])
            carryover_well_peak_dict[s.name] = len(well_carryover_peaks)
        
        return contamination_peaks, gated_contamination_peaks, carryover_peaks, num_wells, carryover_well_peak_dict
Exemple #6
0
def revb_extracluster_peaks(well, channel_num, threshold=None, pct_boundary=0.3, exclude_min_amplitude_peaks=True):
    """
    Return the peaks that are outside the clusters.
    A superset of polydispersity peaks, meant primarily for dye wells,
    where there should be no biological basis for rain.

    Returns a 3-tuple: peaks, rain gates, width gates
    """
    if not threshold:
        threshold = well.channels[channel_num].statistics.threshold
    if not threshold:
        threshold = None
    
    if exclude_min_amplitude_peaks:
        peaks = above_min_amplitude_peaks(well)
    else:
        peaks = well.peaks
    
    # get rain_pvalues
    p_plus, p, p_minus, pos, middle_high, middle_low, neg = \
            rain_pvalues_thresholds(peaks,
                                    channel_num=channel_num,
                                    threshold=threshold,
                                    pct_boundary=pct_boundary)
    
    binned_peaks = bin_peaks_by_amplitude(peaks, well.sum_amplitude_bins)

    extra_peaks = np.ndarray([0], dtype=peak_dtype(2))
    for bin, (min_gate, max_gate, boundary) in zip(binned_peaks, well.sum_amplitude_bins):
        if middle_high and middle_low:
            extra_peaks = np.hstack([extra_peaks, np.extract(np.logical_not(
                np.logical_or(
                       reduce(np.logical_and,
                              (channel_widths(bin, channel_num) > min_gate,
                               channel_widths(bin, channel_num) < max_gate,
                               channel_amplitudes(bin, channel_num) > middle_high,
                               channel_amplitudes(bin, channel_num) < pos)),
                       reduce(np.logical_and,
                              (channel_widths(bin, channel_num) > min_gate,
                               channel_widths(bin, channel_num) < max_gate,
                               channel_amplitudes(bin, channel_num) > neg,
                               channel_amplitudes(bin, channel_num) < middle_low))
                )
            ), bin)])
        else:
            extra_peaks = np.hstack([extra_peaks, np.extract(np.logical_not(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) > min_gate,
                        channel_widths(bin, channel_num) < max_gate,
                        channel_amplitudes(bin, channel_num) > neg,
                        channel_amplitudes(bin, channel_num) < pos)
                )
            ), bin)])
    
    return (extra_peaks,
            (pos, middle_high, middle_low, neg),
            (np.mean(fam_amplitudes(peaks)), np.mean(vic_amplitudes(peaks))))
Exemple #7
0
def extracluster_peaks(well, channel_num, threshold=None, pct_boundary=0.3, exclude_min_amplitude_peaks=True):
    """
    Return the peaks that are outside the clusters.
    A superset of polydispersity peaks, meant primarily for dye wells,
    where there should be no biological basis for rain.

    Returns a 3-tuple: peaks, rain gates, width gates
    """
    if not threshold:
        threshold = well.channels[channel_num].statistics.threshold
    if not threshold:
        threshold = None
    
    if exclude_min_amplitude_peaks:
        peaks = above_min_amplitude_peaks(well)
    else:
        peaks = well.peaks
    
    # get rain_pvalues
    p_plus, p, p_minus, pos, middle_high, middle_low, neg = \
            rain_pvalues_thresholds(peaks,
                                    channel_num=channel_num,
                                    threshold=threshold,
                                    pct_boundary=pct_boundary)
    
    min_gate, max_gate = well_static_width_gates(well)

    if middle_high and middle_low:
        extracluster_peaks = np.extract(np.logical_not(
            np.logical_or(
                   reduce(np.logical_and,
                          (channel_widths(peaks, channel_num) > min_gate,
                           channel_widths(peaks, channel_num) < max_gate,
                           channel_amplitudes(peaks, channel_num) > middle_high,
                           channel_amplitudes(peaks, channel_num) < pos)),
                   reduce(np.logical_and,
                          (channel_widths(peaks, channel_num) > min_gate,
                           channel_widths(peaks, channel_num) < max_gate,
                           channel_amplitudes(peaks, channel_num) > neg,
                           channel_amplitudes(peaks, channel_num) < middle_low))
            )
        ), peaks)
    else:
        extracluster_peaks = np.extract(np.logical_not(
            reduce(np.logical_and,
                   (channel_widths(peaks, channel_num) > min_gate,
                    channel_widths(peaks, channel_num) < max_gate,
                    channel_amplitudes(peaks, channel_num) > neg,
                    channel_amplitudes(peaks, channel_num) < pos)
            )
        ), peaks)
    
    return (extracluster_peaks,
            (pos, middle_high, middle_low, neg),
            (min_gate, max_gate))
Exemple #8
0
    def nds(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks, NARROW_NORMALIZED_DROPLET_SPACING
        from qtools.lib.mplot import nds, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)

        title = 'NDS Histogram - %s - %s' % (c.well.plate.plate.name, c.well.well_name)

        ok_peaks = above_min_amplitude_peaks(qlwell)
        fig = nds(title, ok_peaks, NARROW_NORMALIZED_DROPLET_SPACING)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Exemple #9
0
    def temporal_galaxy(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.nstats.peaks import above_min_amplitude_peaks
        from pyqlb.nstats.peaks import peak_times, channel_amplitudes, channel_widths
        
        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        c.channel_num = int(channel_num)

        ok_peaks = above_min_amplitude_peaks(qlwell)
        c.taw = zip(peak_times(ok_peaks), channel_amplitudes(ok_peaks, c.channel_num), channel_widths(ok_peaks, c.channel_num))
        if c.channel_num == 0:
            c.channel_name = 'FAM'
        else:
            c.channel_name = 'VIC'

        return render('/well/temporal_galaxy.html')
Exemple #10
0
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
Exemple #11
0
    def widthbin(self, id=None, *args, **kwargs):
        from qtools.lib.nstats.peaks import above_min_amplitude_peaks
        from qtools.lib.mplot import plot_cluster_widthbins, cleanup, render as plt_render

        qlwell = self.__qlwell_from_threshold_form(id)
        title = 'Width Bins - %s, %s' % (c.well.plate.plate.name, c.well.well_name)

        min_gate = qlwell.channels[0].statistics.min_width_gate
        max_gate = qlwell.channels[0].statistics.max_width_gate

        peaks = above_min_amplitude_peaks(qlwell)
        fam_threshold = qlwell.channels[0].statistics.threshold
        vic_threshold = qlwell.channels[1].statistics.threshold
        fig = plot_cluster_widthbins(title, peaks, qlwell.sum_amplitude_bins, min_gate, max_gate,
                                     fam_threshold=fam_threshold, vic_threshold=vic_threshold)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Exemple #12
0
    def galaxy(self, id=None, channel_num=0, *args, **kwargs):
        from qtools.lib.nstats.peaks import above_min_amplitude_peaks
        from pyqlb.nstats.well import well_static_width_gates

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))

        from qtools.lib.mplot import galaxy, cleanup, render as plt_render

        peaks = above_min_amplitude_peaks(qlwell)
        title = 'Galaxy Lite - %s - %s, %s' % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold
        min_width_gate, max_width_gate = well_static_width_gates(qlwell)
        fig = galaxy(title, peaks, threshold, min_width_gate, max_width_gate, channel_idx)
        response.content_type = 'image/png'
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Exemple #13
0
    def galaxy_extra_region(self, id=None, *args, **kwargs):
        from pyqlb.nstats.well import above_min_amplitude_peaks
        from qtools.lib.mplot import graph_extracluster_by_region, cleanup, render as plt_render
        from qtools.lib.nstats.peaks import revb_extracluster_peaks_by_region

        response.content_type = 'image/png'

        qlwell = self.__qlwell_from_threshold_form(id)
        self.__set_threshold_context(qlwell)
        channel_idx = int(request.params.get("channel", 0))
        peaks = above_min_amplitude_peaks(qlwell)
        threshold = c.vic_threshold if channel_idx == 1 else c.fam_threshold
        extra_data = revb_extracluster_peaks_by_region(qlwell, channel_idx, threshold=threshold)
        peaks_by_region, rain_gates, means = extra_data
        title = "GalaxyEXR - %s, %s, %s" % (c.well.plate.plate.name, c.well.well_name, 'VIC' if channel_idx == 1 else 'FAM')
        fig = graph_extracluster_by_region(title, peaks, channel_idx, threshold,
                                           peaks_by_region, rain_gates,
                                           sum_amplitude_bins=qlwell.sum_amplitude_bins,
                                           other_channel_mean=means[channel_idx])
        imgdata = plt_render(fig, dpi=72)
        cleanup(fig)
        return imgdata
Exemple #14
0
def stats_for_qlp_well(well, compute_clusters=False, override_thresholds=None):
    """
    Return statistics about a QLWell object read from a QLP file.
    The QLWell object should have a populated `peaks` attribute (reading from QLBs won't work)

    For parameter explanations and return values, see :func:`stats_for_qlp_well`.
    """
    from pyqlb.nstats.peaks import cluster_1d, channel_amplitudes
    from pyqlb.nstats.well import accepted_peaks, above_min_amplitude_peaks, well_channel_sp_values, well_cluster_peaks
    from pyqlb.nstats.well import well_observed_positives_negatives, well_s2d_values, getClusters
    from pyqlb.nstats.well import high_flier_droplets, low_flier_droplets, singleRain_droplets, doubleRain_droplets, diagonal_scatter
    from numpy import mean as np_mean, std as np_std

    if not override_thresholds:
        override_thresholds = (None, None)

    statistics = well_statistics(well, override_thresholds=override_thresholds)
    accepted = len(accepted_peaks(well))
    num_above_min = len(above_min_amplitude_peaks(well))

    if num_above_min > 0 and accepted > 0:
        if well.sum_amplitude_bins:
            peaksets, boundaries, amps = revb_polydisperse_peaks(well, 0, threshold=override_thresholds[0])
            poly_peaks = sum([len(p) for p in peaksets])
            statistics[0].revb_polydispersity_pct = 100*float(poly_peaks)/num_above_min
        else:
            peaksets, boundaries, width_gates = polydisperse_peaks(well, 0, threshold=override_thresholds[0])
            poly_peaks = sum([len(p) for p in peaksets])
            statistics[0].revb_polydispersity_pct = 100*float(poly_peaks)/num_above_min
    else:
        statistics[0].revb_polydispersity_pct = 0

    s, p_plus, p, p_minus = well_channel_sp_values(well, 0, override_threshold=override_thresholds[0])
    statistics[0].s_value = s
    statistics[0].p_plus = p_plus
    statistics[0].p_plus_drops = int(p_plus*accepted) if p_plus is not None else None
    statistics[0].p = p
    statistics[0].p_drops = int(p*accepted) if p is not None else None
    statistics[0].p_minus = p_minus
    statistics[0].p_minus_drops = int(p_minus*accepted) if p_minus is not None else None

    if num_above_min > 0 and accepted > 0:
        if well.sum_amplitude_bins:
            peaksets, boundaries, amps = revb_polydisperse_peaks(well, 1, threshold=override_thresholds[1])
            poly_peaks = sum([len(p) for p in peaksets])
            statistics[1].revb_polydispersity_pct = 100*float(poly_peaks)/num_above_min
        else:
            peaksets, boundaries, width_gates = polydisperse_peaks(well, 1, threshold=override_thresholds[1])
            poly_peaks = sum([len(p) for p in peaksets])
            statistics[1].revb_polydispersity_pct = 100*float(poly_peaks)/num_above_min
    else:
        statistics[1].revb_polydispersity_pct = 0

    s, p_plus, p, p_minus = well_channel_sp_values(well, 1, override_threshold=override_thresholds[1])
    statistics[1].s_value = s
    statistics[1].p_plus = p_plus
    statistics[1].p_plus_drops = int(p_plus*accepted) if p_plus is not None else None
    statistics[1].p = p
    statistics[1].p_drops = int(p*accepted) if p is not None else None
    statistics[1].p_minus = p_minus
    statistics[1].p_minus_drops = int(p_minus*accepted) if p_minus is not None else None

    ## compute s2d plots
    s2d_vals = well_s2d_values( well, thresholds=override_thresholds)
    statistics[0].s2d_value = s2d_vals[0] if s2d_vals is not None else None
    statistics[1].s2d_value = s2d_vals[1] if s2d_vals is not None else None

    ## compute extra cluster metrics
    clusters = getClusters( well, override_thresholds )
    dscatter = diagonal_scatter( clusters )
    statistics.diagonal_scatter = dscatter[1] if dscatter is not None else None
    statistics.diagonal_scatter_pct  = dscatter[2] *100 if dscatter is not None else None
    for channel in [0,1]:
        high_fliers = high_flier_droplets( clusters, channel )
        statistics[channel].high_flier_value = high_fliers[1] if high_fliers is not None else None
        statistics[channel].high_flier_pct = high_fliers[2] * 100 if high_fliers is not None else None

        low_fliers  = low_flier_droplets( clusters, channel )
        statistics[channel].low_flier_value  = low_fliers[1] if low_fliers is not None else None
        statistics[channel].low_flier_pct    = low_fliers[2] * 100 if low_fliers is not None else None
        
        singleRain  = singleRain_droplets( clusters, channel )
        statistics[channel].single_rain_value  = singleRain[1] if singleRain is not None else None
        statistics[channel].single_rain_pct  = singleRain[2] * 100 if singleRain is not None else None
        
        doubleRain  = doubleRain_droplets( clusters, channel )
        statistics[channel].double_rain_value = doubleRain[1] if doubleRain is not None else None
        statistics[channel].double_rain_pct = doubleRain[2] * 100 if doubleRain is not None else None


    if compute_clusters:
        clusters = well_cluster_peaks(well, override_thresholds)
    else:
        clusters = {'positive_peaks': {'positive_peaks': [], 'negative_peaks': []},
                    'negative_peaks': {'positive_peaks': [], 'negative_peaks': []}}
 
    # cheap hack
    statistics.alg_version = "%s.%s/%s.%s" % (well.statistics.peak_alg_major_version,
                                              well.statistics.peak_alg_minor_version,
                                              well.statistics.quant_alg_major_version,
                                              well.statistics.quant_alg_minor_version)
    statistics.ref_copy_num = well.ref_copy_num
    statistics[0].decision_tree = well.channels[0].decision_tree_verbose
    statistics[1].decision_tree = well.channels[1].decision_tree_verbose
    # end cheap hack

    # SNR
    for chan in (0,1):
        if override_thresholds[chan]:
            # TODO add this to pyqlb.nstats.well instead
            pos, neg = cluster_1d(accepted_peaks(well), chan, override_thresholds[chan])
        else:
            pos, neg, unknown = well_observed_positives_negatives(well, chan)

        for attr, coll in (('positive_snr', pos),('negative_snr',neg)):
            if len(pos) > 0:
                amps = channel_amplitudes(coll, chan)
                amp_mean = np_mean(amps)
                amp_std = np_std(amps)
                if amp_std > 0:
                    setattr(statistics[chan], attr, amp_mean/amp_std)
                else:
                    setattr(statistics[chan], attr, 10000)
            else:
                setattr(statistics[chan], attr, 0)

    for channel in [0,1]:
        means,stds = total_events_amplitude_vals(well,channel) 
        statistics[channel].total_events_amplitude_mean = means if means is not None else None
        statistics[channel].total_events_amplitude_stdev = stds if stds is not None else None

    return statistics, clusters
Exemple #15
0
def revb_polydisperse_peaks(well, channel_num, threshold=None, pct_boundary=0.3, exclude_min_amplitude_peaks=True):
    """
    Computes polydispersity for a well which has amplitude bins defined.

    Returns a 3-tuple (4-tuple, 4-tuple, 2-tuple).  The first 4-tuple is:

    * positive droplets, with widths above the width gate set for that droplet's amplitude bin.
    * middle rain, with widths above the bin width gate.
    * middle rain, with width below the bin width gate.
    * negative rain, with width below the bin width gate.

    The second 4-tuple is:

    * positive rain boundary
    * middle rain upper boundary (can be None)
    * middle rain lower boundary (can be None)
    * negative rain boundary

    The third 2-tuple is:

    * mean FAM amplitude
    * mean VIC amplitude

    This is for being able to draw approximate single-channel polydispersity graphs
    down the line (this does beg the question, is there a better 2D definition of
    polydispersity?)

    Will raise an error if amplitude bins are not defined on the well.
    """
    if not hasattr(well, 'sum_amplitude_bins') or len(well.sum_amplitude_bins) == 0:
        raise ValueError("No amplitude bins for this well.")
    
    if not threshold:
        threshold = well.channels[channel_num].statistics.threshold
    if not threshold:
        threshold = None
    
    if exclude_min_amplitude_peaks:
        peaks = above_min_amplitude_peaks(well)
    else:
        peaks = well.peaks
    
    p_plus, p, p_minus, pos, middle_high, middle_low, neg = \
            rain_pvalues_thresholds(peaks,
                                    channel_num=channel_num,
                                    threshold=threshold,
                                    pct_boundary=pct_boundary)
    
    binned_peaks         = bin_peaks_by_amplitude(peaks, well.sum_amplitude_bins)
    
    pos_peaks     = np.ndarray([0], dtype=peak_dtype(2))
    midhigh_peaks = np.ndarray([0], dtype=peak_dtype(2))
    midlow_peaks  = np.ndarray([0], dtype=peak_dtype(2))
    neg_peaks     = np.ndarray([0], dtype=peak_dtype(2))

    for bin, (min_gate, max_gate, boundary) in zip(binned_peaks, well.sum_amplitude_bins):
        pos_peaks = np.hstack([pos_peaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) > max_gate,
                    channel_amplitudes(bin, channel_num) > pos)),
            bin)])
    
        if middle_high and middle_low:
            midhigh_peaks = np.hstack([midhigh_peaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) > max_gate,
                        reduce(np.logical_and,
                               (channel_amplitudes(bin, channel_num) < middle_high,
                                channel_amplitudes(bin, channel_num) > middle_low)))),
                bin)])
            
            midlow_peaks = np.hstack([midlow_peaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) < min_gate,
                        reduce(np.logical_and,
                               (channel_amplitudes(bin, channel_num) < middle_high,
                                channel_amplitudes(bin, channel_num) > middle_low)))),
                bin)])
        
        neg_peaks = np.hstack([neg_peaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) < min_gate,
                    channel_amplitudes(bin, channel_num) < neg)),
            bin)])
    
    return ((pos_peaks, midhigh_peaks, midlow_peaks, neg_peaks),
            (pos, middle_high, middle_low, neg),
            (np.mean(fam_amplitudes(peaks)), np.mean(vic_amplitudes(peaks))))
Exemple #16
0
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
Exemple #17
0
def polydisperse_peaks(well, channel_num, threshold=None, pct_boundary=0.3, exclude_min_amplitude_peaks=True):
    """
    Returns a 3-tuple (4-tuple, 4-tuple, 2-tuple).  The first 4-tuple is:
    
    * positive rain above the width gates.
    * middle rain above the width gates.
    * middle rain below the width gates.
    * negative rain below the width gates.

    The second 4-tuple is:

    * positive rain boundary
    * middle rain upper boundary (can be None)
    * middle rain lower boundary (can be None)
    * negative rain boundary

    The last 2-tuple is:

    * computed min width gate
    * computed max width gate

    Positives & negatives are computed on the specified channel number.
    """
    if not threshold:
        threshold = well.channels[channel_num].statistics.threshold
    if not threshold:
        threshold = None
    
    # filter out min_amplitude_peaks
    if exclude_min_amplitude_peaks:
        peaks = above_min_amplitude_peaks(well)
    else:
        peaks = well.peaks

    p_plus, p, p_minus, pos, middle_high, middle_low, neg = \
            rain_pvalues_thresholds(peaks,
                                    channel_num=channel_num,
                                    threshold=threshold,
                                    pct_boundary=pct_boundary)
    
    min_gate, max_gate = well_static_width_gates(well)

    pos_peaks = np.extract(
        reduce(np.logical_and,
               (channel_widths(peaks, channel_num) > max_gate,
                channel_amplitudes(peaks, channel_num) > pos)),
        peaks)
    
    
    if middle_high and middle_low:
        midhigh_peaks = np.extract(
            reduce(np.logical_and,
                   (channel_widths(peaks, channel_num) > max_gate,
                    reduce(np.logical_and,
                           (channel_amplitudes(peaks, channel_num) < middle_high,
                            channel_amplitudes(peaks, channel_num) > middle_low)))),
            peaks)
        midlow_peaks = np.extract(
            reduce(np.logical_and,
                   (channel_widths(peaks, channel_num) < min_gate,
                    reduce(np.logical_and,
                           (channel_amplitudes(peaks, channel_num) < middle_high,
                            channel_amplitudes(peaks, channel_num) > middle_low)))),
            peaks)
    else:
        midhigh_peaks = np.ndarray([0],dtype=peak_dtype(2))
        midlow_peaks = np.ndarray([0],dtype=peak_dtype(2))
    
    neg_peaks = np.extract(
        reduce(np.logical_and,
               (channel_widths(peaks, channel_num) < min_gate,
                channel_amplitudes(peaks, channel_num) < neg)),
        peaks)
    
    return ((pos_peaks, midhigh_peaks, midlow_peaks, neg_peaks),
            (pos, middle_high, middle_low, neg),
            (min_gate, max_gate))
Exemple #18
0
    def contamination_carryover_peaks(self, qlplate, exclude_min_amplitude_peaks=True):
        """
        For now, just count FAM HI carryover
        """
        carryover_upper_bound = None
        carryover_lower_bound = None
        min_width_gate = None
        max_width_gate = None

        contamination_peaks = np.ndarray([0], dtype=peak_dtype(2))
        gated_contamination_peaks = np.ndarray([0], dtype=peak_dtype(2))
        carryover_peaks = np.ndarray([0], dtype=peak_dtype(2))
        num_wells = 0
        carryover_well_peak_dict = dict()

        fam_bounds = []
        vic_bounds = []
        # TODO fixfix when QS bug resolved
        #for idx, well in enumerate(qlplate.in_run_order):
        for idx, well in enumerate(sorted(qlplate.analyzed_wells.values(), cmp=QLWell.row_order_comparator)):
            if exclude_min_amplitude_peaks:
                peaks = above_min_amplitude_peaks(well)
            else:
                peaks = well.peaks
            
            if well.original_sample_name not in ('FAM HI', 'FAM 350nM'):
                num_wells = num_wells+1
                for bounds, channel in zip((fam_bounds, vic_bounds),(0,1)):
                    for lower_bound, upper_bound, min_width_gate, max_width_gate in bounds:
                        # TODO: this will double-count contamination if the bounds overlap.  But if the bounds
                        # overlap, you have much bigger problems than carryover.  OK for now.
                        argument_bounds = [(None, None),(None, None)]
                        argument_bounds[channel] = (lower_bound, upper_bound)
                        well_contamination_peaks = filter_amplitude_range(peaks, argument_bounds)
                        well_carryover_peaks = width_gated(well_contamination_peaks,
                                                      min_width_gate=min_width_gate,
                                                      max_width_gate=max_width_gate,
                                                      on_channel_num=channel,
                                                      ignore_gating_flags=True)
                        if well.name not in carryover_well_peak_dict:
                            carryover_well_peak_dict[well.name] = len(well_carryover_peaks)
                        else:
                            carryover_well_peak_dict[well.name] = carryover_well_peak_dict[well.name] + len(well_carryover_peaks)
                        
                        contamination_peaks = np.hstack([contamination_peaks, well_contamination_peaks])
                        carryover_peaks = np.hstack([carryover_peaks, well_carryover_peaks])
            
            if well.original_sample_name in ('FAM HI', 'FAM 350nM', 'FAM LO', 'FAM 40nM', 'VIC HI', 'VIC 350nM'):
                if well.original_sample_name.startswith('VIC'):
                    add_to = vic_bounds
                    amps = vic_amplitudes(peaks)
                else:
                    add_to = fam_bounds
                    amps = fam_amplitudes(peaks)
                
                min_width_gate, max_width_gate = well_static_width_gates(well)

                mean = np.mean(amps)
                std = np.std(amps)
                lower_bound = mean - 3*std
                upper_bound = mean + 3*std

                add_to.append((lower_bound, upper_bound, min_width_gate, max_width_gate))
        
        return contamination_peaks, gated_contamination_peaks, carryover_peaks, num_wells, carryover_well_peak_dict