def __get_1d_background_rgbs(self, qlwell): rgbs = [None, None] if well_channel_automatic_classification(qlwell, 0): rgbs[0] = AUTO_THRESHOLD_FAM_BGCOLOR else: rgbs[0] = MANUAL_THRESHOLD_FAM_BGCOLOR if well_channel_automatic_classification(qlwell, 1): rgbs[1] = AUTO_THRESHOLD_VIC_BGCOLOR else: rgbs[1] = MANUAL_THRESHOLD_VIC_BGCOLOR return rgbs
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 command(self): from qtools.lib.mplot import plot_cluster_2d, cleanup as plt_cleanup app = self.load_wsgi_app() image_root = app.config['qlb.image_store'] image_source = QLBImageSource(image_root) # enforce config.ini if len(self.args) < 2: raise ValueError, self.__class_.usage analysis_group_id = int(self.args[0]) if len(self.args) == 3: reprocess_config = Session.query(ReprocessConfig).filter_by(code=self.args[1]).one() reprocess_config_id = reprocess_config.id else: reprocess_config = None reprocess_config_id = None if reprocess_config: data_root = app.config['qlb.reprocess_root'] storage = QLPReprocessedFileSource(data_root, reprocess_config) else: storage = QLStorageSource(app.config) analysis_group = Session.query(AnalysisGroup).get(analysis_group_id) if not analysis_group: raise ValueError, "No analysis group for id %s" % analysis_group_id plates = analysis_group.plates for plate in plates: # TODO: UGH THIS CODE INVARIANT SUCKS (should merge QLReprocessedFile/QLStorageSources) if reprocess_config: plate_path = storage.full_path(analysis_group, plate) else: plate_path = storage.plate_path(plate) print "Reading %s" % plate_path qlplate = get_plate(plate_path) if not qlplate: print "Could not read plate: %s" % plate.name continue print "Generating thumbnails for %s" % plate.name for name, qlwell in sorted(qlplate.analyzed_wells.items()): # TODO abstract into utility image generation function (thumbnail.py?) threshold_fallback = qlwell.clustering_method == QLWell.CLUSTERING_TYPE_THRESHOLD fig = plot_cluster_2d(qlwell.peaks, width=60, height=60, thresholds=[qlwell.channels[0].statistics.threshold, qlwell.channels[1].statistics.threshold], boundaries=[0,0,12000,24000], show_axes=False, antialiased=True, unclassified_alpha=0.5, use_manual_clusters=not well_channel_automatic_classification(qlwell), highlight_thresholds=threshold_fallback) image_path = image_source.get_path('%s/%s_2d.png' % (plate.qlbplate.id, name)) print image_path fig.savefig(image_path, format='png', dpi=72) plt_cleanup(fig)
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
def write_images_stats_for_plate(dbplate, qlplate, image_source, overwrite=False, override_plate_type=None): """ Write plate metrics to the database and thumbnails to local storage, as dictated by image_source. Metrics will be related to the supplied dbplate (Plate model) qlplate is a QLPlate object derived from reading the QLP file. """ if image_source.subdir_exists(str(dbplate.id)): if not overwrite: return else: image_source.make_subdir(str(dbplate.id)) max_amplitudes = (24000, 12000) show_only_gated = False # keep default behavior if qlplate: for well_name, qlwell in sorted(qlplate.analyzed_wells.items()): # TODO: common lib? if well_channel_automatic_classification(qlwell, 0): fig = plot_fam_peaks(qlwell.peaks, threshold=qlwell.channels[0].statistics.threshold, max_amplitude=max_amplitudes[0]) else: fig = plot_fam_peaks(qlwell.peaks, threshold=qlwell.channels[0].statistics.threshold, threshold_color='red', max_amplitude=max_amplitudes[0], background_rgb=MANUAL_THRESHOLD_FAM_BGCOLOR) fig.savefig(image_source.get_path('%s/%s_%s.png' % (dbplate.id, well_name, 0)), format='png', dpi=72) plt_cleanup(fig) if well_channel_automatic_classification(qlwell, 1): fig = plot_vic_peaks(qlwell.peaks, threshold=qlwell.channels[1].statistics.threshold, max_amplitude=max_amplitudes[1]) else: fig = plot_vic_peaks(qlwell.peaks, threshold=qlwell.channels[1].statistics.threshold, threshold_color='red', max_amplitude=max_amplitudes[1], background_rgb=MANUAL_THRESHOLD_VIC_BGCOLOR) fig.savefig(image_source.get_path('%s/%s_%s.png' % (dbplate.id, well_name, 1)), format='png', dpi=72) plt_cleanup(fig) if qlwell.clusters_defined: threshold_fallback = qlwell.clustering_method == QLWell.CLUSTERING_TYPE_THRESHOLD fig = plot_cluster_2d(qlwell.peaks, width=60, height=60, thresholds=[qlwell.channels[0].statistics.threshold, qlwell.channels[1].statistics.threshold], boundaries=[0,0,12000,24000], show_axes=False, antialiased=True, unclassified_alpha=0.5, use_manual_clusters=not well_channel_automatic_classification(qlwell), highlight_thresholds=threshold_fallback) fig.savefig(image_source.get_path('%s/%s_2d.png' % (dbplate.id, well_name)), format='png', dpi=72) plt_cleanup(fig) pm = [pm for pm in dbplate.plate.metrics if pm.reprocess_config_id is None] for p in pm: Session.delete(p) plate = dbplate_tree(dbplate.plate.id) # override plate_type if supplied (another artifact of bad abstraction) if override_plate_type: plate.plate_type = override_plate_type # this relies on apply_template/apply_setup working correctly on plate addition # verify on DR 10005 plate that this works if plate.plate_type and plate.plate_type.code in beta_plate_types: plate_metrics = get_beta_plate_metrics(plate, qlplate) else: plate_metrics = process_plate(plate, qlplate) Session.add(plate_metrics)