def clear_estimate(self): self._af_op = AutofluorescenceOp() self._bleedthrough_op = BleedthroughLinearOp() self._bead_calibration_op = BeadCalibrationOp() self._color_translation_op = ColorTranslationOp() self.valid_model = False self.changed = (Changed.ESTIMATE_RESULT, self)
class TasbeCalibrationOp(PluginOpMixin): handler_factory = Callable(TasbeHandler) id = Constant('edu.mit.synbio.cytoflowgui.op_plugins.bleedthrough_piecewise') friendly_id = Constant("Quantitative Pipeline") name = Constant("TASBE") fsc_channel = DelegatesTo('_polygon_op', 'xchannel', estimate = True) ssc_channel = DelegatesTo('_polygon_op', 'ychannel', estimate = True) vertices = DelegatesTo('_polygon_op', 'vertices', estimate = True) channels = List(Str, estimate = True) blank_file = File(filter = ["*.fcs"], estimate = True) bleedthrough_list = List(_BleedthroughControl, estimate = True) beads_name = Str(estimate = True) beads_file = File(filter = ["*.fcs"], estimate = True) units_list = List(_Unit, estimate = True) bead_peak_quantile = Int(80, estimate = True) bead_brightness_threshold = Float(100, estimate = True) bead_brightness_cutoff = util.FloatOrNone("", estimate = True) do_color_translation = Bool(estimate = True) to_channel = Str(estimate = True) translation_list = List(_TranslationControl, estimate = True) mixture_model = Bool(False, estimate = True) do_estimate = Event valid_model = Bool(False, status = True) do_exit = Event input_files = List(File) output_directory = Directory _blank_exp = Instance(Experiment, transient = True) _blank_exp_file = File(transient = True) _blank_exp_channels = List(Str, status = True) _polygon_op = Instance(PolygonOp, kw = {'name' : 'polygon', 'xscale' : 'log', 'yscale' : 'log'}, transient = True) _af_op = Instance(AutofluorescenceOp, (), transient = True) _bleedthrough_op = Instance(BleedthroughLinearOp, (), transient = True) _bead_calibration_op = Instance(BeadCalibrationOp, (), transient = True) _color_translation_op = Instance(ColorTranslationOp, (), transient = True) status = Str(status = True) @on_trait_change('channels[], to_channel, do_color_translation', post_init = True) def _channels_changed(self, obj, name, old, new): for channel in self.channels: if channel not in [control.channel for control in self.bleedthrough_list]: self.bleedthrough_list.append(_BleedthroughControl(channel = channel)) if channel not in [unit.channel for unit in self.units_list]: self.units_list.append(_Unit(channel = channel)) to_remove = [] for control in self.bleedthrough_list: if control.channel not in self.channels: to_remove.append(control) for control in to_remove: self.bleedthrough_list.remove(control) to_remove = [] for unit in self.units_list: if unit.channel not in self.channels: to_remove.append(unit) for unit in to_remove: self.units_list.remove(unit) if self.do_color_translation: to_remove = [] for unit in self.units_list: if unit.channel != self.to_channel: to_remove.append(unit) for unit in to_remove: self.units_list.remove(unit) self.translation_list = [] for c in self.channels: if c == self.to_channel: continue self.translation_list.append(_TranslationControl(from_channel = c, to_channel = self.to_channel)) self.changed = (Changed.ESTIMATE, ('translation_list', self.translation_list)) self.changed = (Changed.ESTIMATE, ('bleedthrough_list', self.bleedthrough_list)) self.changed = (Changed.ESTIMATE, ('units_list', self.units_list)) @on_trait_change('_polygon_op:vertices', post_init = True) def _polygon_changed(self, obj, name, old, new): self.changed = (Changed.ESTIMATE, (None, None)) @on_trait_change("bleedthrough_list_items, bleedthrough_list.+", post_init = True) def _bleedthrough_controls_changed(self, obj, name, old, new): self.changed = (Changed.ESTIMATE, ('bleedthrough_list', self.bleedthrough_list)) @on_trait_change("translation_list_items, translation_list.+", post_init = True) def _translation_controls_changed(self, obj, name, old, new): self.changed = (Changed.ESTIMATE, ('translation_list', self.translation_list)) @on_trait_change('units_list_items,units_list.+', post_init = True) def _units_changed(self, obj, name, old, new): self.changed = (Changed.ESTIMATE, ('units_list', self.units_list)) # def estimate(self, experiment, subset = None): # if not self.subset: # warnings.warn("Are you sure you don't want to specify a subset " # "used to estimate the model?", # util.CytoflowOpWarning) # if experiment is None: # raise util.CytoflowOpError("No valid result to estimate with") # experiment = experiment.clone() if not self.fsc_channel: raise util.CytoflowOpError('fsc_channel', "Must set FSC channel") if not self.ssc_channel: raise util.CytoflowOpError('ssc_channel', "Must set SSC channel") if not self._polygon_op.vertices: raise util.CytoflowOpError(None, "Please draw a polygon around the " "single-cell population in the " "Morphology tab") experiment = self._blank_exp.clone() experiment = self._polygon_op.apply(experiment) self._af_op.channels = self.channels self._af_op.blank_file = self.blank_file self._af_op.estimate(experiment, subset = "polygon == True") self.changed = (Changed.ESTIMATE_RESULT, "Autofluorescence") experiment = self._af_op.apply(experiment) self.status = "Estimating bleedthrough" self._bleedthrough_op.controls.clear() for control in self.bleedthrough_list: self._bleedthrough_op.controls[control.channel] = control.file self._bleedthrough_op.estimate(experiment, subset = "polygon == True") self.changed = (Changed.ESTIMATE_RESULT, "Bleedthrough") experiment = self._bleedthrough_op.apply(experiment) self.status = "Estimating bead calibration" self._bead_calibration_op.beads = BeadCalibrationOp.BEADS[self.beads_name] self._bead_calibration_op.beads_file = self.beads_file self._bead_calibration_op.bead_peak_quantile = self.bead_peak_quantile self._bead_calibration_op.bead_brightness_threshold = self.bead_brightness_threshold self._bead_calibration_op.bead_brightness_cutoff = self.bead_brightness_cutoff self._bead_calibration_op.units.clear() for unit in self.units_list: self._bead_calibration_op.units[unit.channel] = unit.unit self._bead_calibration_op.estimate(experiment) self.changed = (Changed.ESTIMATE_RESULT, "Bead Calibration") if self.do_color_translation: self.status = "Estimating color translation" experiment = self._bead_calibration_op.apply(experiment) self._color_translation_op.mixture_model = self.mixture_model self._color_translation_op.controls.clear() for control in self.translation_list: self._color_translation_op.controls[(control.from_channel, control.to_channel)] = control.file self._color_translation_op.estimate(experiment, subset = 'polygon == True') self.changed = (Changed.ESTIMATE_RESULT, "Color Translation") self.status = "Done estimating" self.valid_model = True def should_clear_estimate(self, changed, payload): """ Should the owning WorkflowItem clear the estimated model by calling op.clear_estimate()? `changed` can be: - Changed.ESTIMATE -- the parameters required to call 'estimate()' (ie traits with estimate = True metadata) have changed - Changed.PREV_RESULT -- the previous WorkflowItem's result changed """ if changed == Changed.ESTIMATE: name, _ = payload if name == 'fsc_channel' or name == 'ssc_channel': return False return True def clear_estimate(self): self._af_op = AutofluorescenceOp() self._bleedthrough_op = BleedthroughLinearOp() self._bead_calibration_op = BeadCalibrationOp() self._color_translation_op = ColorTranslationOp() self.valid_model = False self.changed = (Changed.ESTIMATE_RESULT, self) def should_apply(self, changed, payload): """ Should the owning WorkflowItem apply this operation when certain things change? `changed` can be: - Changed.OPERATION -- the operation's parameters changed - Changed.PREV_RESULT -- the previous WorkflowItem's result changed - Changed.ESTIMATE_RESULT -- the results of calling "estimate" changed """ if changed == Changed.ESTIMATE_RESULT and \ self.blank_file != self._blank_exp_file: return True elif changed == Changed.OPERATION: name, _ = payload if name == "output_directory": return False return True return False def apply(self, experiment): # this "apply" function is a little odd -- it does not return an Experiment because # it always the only WI/operation in the workflow. if self.blank_file != self._blank_exp_file: self._blank_exp = ImportOp(tubes = [Tube(file = self.blank_file)] ).apply() self._blank_exp_file = self.blank_file self._blank_exp_channels = self._blank_exp.channels self.changed = (Changed.PREV_RESULT, None) return out_dir = Path(self.output_directory) for path in self.input_files: in_file_path = Path(path) out_file_path = out_dir / in_file_path.name if out_file_path.exists(): raise util.CytoflowOpError(None, "File {} already exists" .format(out_file_path)) tubes = [Tube(file = path, conditions = {'filename' : Path(path).stem}) for path in self.input_files] for tube in tubes: self.status = "Converting " + Path(tube.file).stem experiment = ImportOp(tubes = [tube], conditions = {'filename' : 'category'}).apply() experiment = self._af_op.apply(experiment) experiment = self._bleedthrough_op.apply(experiment) experiment = self._bead_calibration_op.apply(experiment) if self.do_color_translation: experiment = self._color_translation_op.apply(experiment) ExportFCS(path = self.output_directory, by = ['filename'], _include_by = False).export(experiment) self.input_files = [] self.status = "Done converting!" def default_view(self, **kwargs): return TasbeCalibrationView(op = self, **kwargs) def get_help(self): current_dir = os.path.abspath(__file__) help_dir = os.path.split(current_dir)[0] help_dir = os.path.join(help_dir, "help") help_file = None for klass in self.__class__.__mro__: mod = klass.__module__ mod_html = mod + ".html" h = os.path.join(help_dir, mod_html) if os.path.exists(h): help_file = h break with open(help_file, encoding = 'utf-8') as f: help_html = f.read() return help_html