예제 #1
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
예제 #2
0
def gap_rain(qlwell, channel_num=0, threshold=None, pct_boundary=0.3, gap_size=10000):
    """
    Return the rain in the gaps between non-rain droplets.
    """
    rain, nonrain = rain_split(qlwell,
                               channel_num=channel_num,
                               threshold=threshold,
                               pct_boundary=pct_boundary)
    
    # ok, now identify the gaps in the gates.
    times = peak_times(nonrain)
    if nonrain is None or len(nonrain) < 2:
        return np.ndarray([0],dtype=peak_dtype(2))
    
    intervals = np.ediff1d(times, to_begin=0, to_end=0)
    big_intervals = intervals > gap_size

    # find beginning of gaps with extract
    beginnings = np.extract(big_intervals[1:], times)
    ends = np.extract(big_intervals[:-1], times)

    gap_intervals = zip(beginnings, ends)
    gap_intervals.insert(0, (0, times[0]))
    gap_intervals.append((times[-1], times[-1]*100))
    
    # count the rain in the intervals
    gap_drops = np.extract(reduce(np.logical_or, [np.logical_and(peak_times(rain) > b,
                                                                 peak_times(rain) < e) for b, e in gap_intervals]),
                           rain)
    return gap_drops
예제 #3
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))))
예제 #4
0
def gap_air(qlwell, channel_num=0, threshold=None, pct_boundary=0.3, gap_size=10000, gap_buffer=250, max_amp=1000):
    """
    Return the air (gap rain < max_amp) in the gaps between non-rain droplets.

    :param channel_num: The channel on which to detect air droplets.
    :param threshold: The threshold dividing positives and negatives (used to detect 'rain')
    :param pct_boundary: The percentage outside of which a droplet is classified as rain.
    :param gap_size: The minimum size (in samples) of a gap.  Default 0.1s.
    :param gap_buffer: The distance a droplet must be from the main population to be considered an
                       air droplet, in samples.  Default 0.0025s.
    :param max_amp: The maximum color-corrected amplitude of an air droplet.  Default 1000 RFU.
    """
    rain, nonrain = rain_split(qlwell,
                               channel_num=channel_num,
                               threshold=threshold,
                               pct_boundary=pct_boundary,
                               split_all_peaks=True)
    
    low_amp = np.extract(channel_amplitudes(rain, channel_num) < max_amp, rain)

    times = peak_times(nonrain)
    if nonrain is None or len(nonrain) < 2:
        return np.ndarray([0], dtype=peak_dtype(2))
    
    intervals = np.ediff1d(times, to_begin=0, to_end=0)
    big_intervals = intervals > gap_size

    # find beginning of gaps with extract
    beginnings = [b+gap_buffer for b in np.extract(big_intervals[1:], times)]
    ends = [e-gap_buffer for e in np.extract(big_intervals[:-1], times)]

    gap_intervals = zip(beginnings, ends)
    gap_intervals.insert(0, (0, times[0]-gap_buffer))
    gap_intervals.append((times[-1]+gap_buffer, times[-1]*100))
    
    # count the rain in the intervals
    gap_drops = np.extract(reduce(np.logical_or, [np.logical_and(peak_times(low_amp) > b,
                                                                 peak_times(low_amp) < e) for b, e in gap_intervals]),
                           low_amp)
    return gap_drops
예제 #5
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
예제 #6
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))))
예제 #7
0
def revb_extracluster_peaks_by_region(well, channel_num, threshold=None, pct_boundary=0.3, exclude_min_amplitude_peaks=True):
    """
    Return the peaks that are not desired (outside clusters)
    and separate them by region.  The region order is:

    -- positive large peaks
    -- positive rain
    -- positive small peaks
    -- positive wide peaks (directly above positive cluster)
    -- positive narrow peaks (directly below positive cluster)
    -- middle large peaks
    -- middle rain
    -- middle small peaks
    -- negative large peaks
    -- negative rain
    -- negative small peaks
    -- negative wide peaks (directly above positive cluster)
    -- negative narrow peaks (directly below positive cluster)

    Returns this 9-tuple, then rain gates, then mean of FAM and VIC.
    """
    extra_peaks, rain_gates, means = \
        revb_extracluster_peaks(well, channel_num,
                                threshold=threshold,
                                pct_boundary=pct_boundary,
                                exclude_min_amplitude_peaks=exclude_min_amplitude_peaks)

    pos_gate, midhigh_gate, midlow_gate, neg_gate = rain_gates
    binned_peaks = bin_peaks_by_amplitude(extra_peaks, well.sum_amplitude_bins)
    plpeaks = np.ndarray([0], dtype=peak_dtype(2))
    prpeaks = np.ndarray([0], dtype=peak_dtype(2))
    pspeaks = np.ndarray([0], dtype=peak_dtype(2))
    pwpeaks = np.ndarray([0], dtype=peak_dtype(2))
    pnpeaks = np.ndarray([0], dtype=peak_dtype(2))
    mlpeaks = np.ndarray([0], dtype=peak_dtype(2))
    mrpeaks = np.ndarray([0], dtype=peak_dtype(2))
    mspeaks = np.ndarray([0], dtype=peak_dtype(2))
    nlpeaks = np.ndarray([0], dtype=peak_dtype(2))
    nrpeaks = np.ndarray([0], dtype=peak_dtype(2))
    nspeaks = np.ndarray([0], dtype=peak_dtype(2))
    nwpeaks = np.ndarray([0], dtype=peak_dtype(2))
    nnpeaks = np.ndarray([0], dtype=peak_dtype(2))

    for bin, (min_gate, max_gate, boundary) in zip(binned_peaks, well.sum_amplitude_bins):
        plpeaks = np.hstack([plpeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) > max_gate,
                    channel_amplitudes(bin, channel_num) > pos_gate)
            ), bin)])
        prpeaks = np.hstack([prpeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) >= min_gate,
                    channel_widths(bin, channel_num) <= max_gate,
                    channel_amplitudes(bin, channel_num) > pos_gate)
            ), bin)])
        pspeaks = np.hstack([pspeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) < min_gate,
                    channel_amplitudes(bin, channel_num) > pos_gate)
            ), bin)])
        if midhigh_gate and midlow_gate:
            mlpeaks = np.hstack([mlpeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) > max_gate,
                    channel_amplitudes(bin, channel_num) < midhigh_gate,
                    channel_amplitudes(bin, channel_num) > midlow_gate)
            ), bin)])
            mrpeaks = np.hstack([mrpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) >= min_gate,
                        channel_widths(bin, channel_num) <= max_gate,
                        channel_amplitudes(bin, channel_num) < midhigh_gate,
                        channel_amplitudes(bin, channel_num) > midlow_gate)
                ), bin)])
            mspeaks = np.hstack([mspeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) < min_gate,
                        channel_amplitudes(bin, channel_num) < midhigh_gate,
                        channel_amplitudes(bin, channel_num) > midlow_gate)
                ), bin)])
            # this means there are positives
            pwpeaks = np.hstack([pwpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) > max_gate,
                        channel_amplitudes(bin, channel_num) >= midhigh_gate,
                        channel_amplitudes(bin, channel_num) <= pos_gate)
                ), bin)])
            pnpeaks = np.hstack([pnpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) < min_gate,
                        channel_amplitudes(bin, channel_num) >= midhigh_gate,
                        channel_amplitudes(bin, channel_num) <= pos_gate)
                ), bin)])
            nwpeaks = np.hstack([nwpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) > max_gate,
                        channel_amplitudes(bin, channel_num) >= neg_gate,
                        channel_amplitudes(bin, channel_num) <= midlow_gate)
                ), bin)])
            nnpeaks = np.hstack([nnpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) < min_gate,
                        channel_amplitudes(bin, channel_num) >= neg_gate,
                        channel_amplitudes(bin, channel_num) <= midlow_gate)
                ), bin)])
        else:
            nwpeaks = np.hstack([nwpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) > max_gate,
                        channel_amplitudes(bin, channel_num) >= neg_gate,
                        channel_amplitudes(bin, channel_num) <= pos_gate)
                ), bin)])
            nnpeaks = np.hstack([nnpeaks, np.extract(
                reduce(np.logical_and,
                       (channel_widths(bin, channel_num) < min_gate,
                        channel_amplitudes(bin, channel_num) >= neg_gate,
                        channel_amplitudes(bin, channel_num) <= pos_gate)
                ), bin)])

        nlpeaks = np.hstack([nlpeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) > max_gate,
                    channel_amplitudes(bin, channel_num) < neg_gate)
            ), bin)])
        nrpeaks = np.hstack([nrpeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) >= min_gate,
                    channel_widths(bin, channel_num) <= max_gate,
                    channel_amplitudes(bin, channel_num) < neg_gate)
            ), bin)])
        
        pbpeaks = np.hstack([pspeaks, np.extract(
            reduce(np.logical_and,
                   (channel_widths(bin, channel_num) < min_gate,
                    channel_amplitudes(bin, channel_num) >= midhigh_gate,
                    channel_amplitudes(bin, channel_num) <= pos_gate)
            ), bin)])

    return ((plpeaks, prpeaks, pspeaks,
             pwpeaks, pnpeaks,
             mlpeaks, mrpeaks, mspeaks,
             nlpeaks, nrpeaks, nspeaks,
             nwpeaks, nnpeaks),
            rain_gates,
            means)
예제 #8
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))