Source code for cytoflowgui.op_plugins.tasbe

#!/usr/bin/env python3.8
# coding: latin-1

# (c) Massachusetts Institute of Technology 2015-2018
# (c) Brian Teague 2018-2022
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

'''
TASBE Calibrated Flow Cytometry
-------------------------------

This module combines all of the other calibrated flow cytometry modules
(autofluorescence, bleedthrough compensation, bead calibration, and channel
translation) into one easy-use-interface.

.. object:: Channels

    Which channels are you calibrating?
    
.. object:: Autofluorescence

    .. object:: Blank File

        The FCS file with the blank (unstained or untransformed) cells, for 
        autofluorescence correction.
        
    .. plot:: 
       :context: close-figs
       :include-source: False

    
        import cytoflow as flow
        import_op = flow.ImportOp()
        import_op.tubes = [flow.Tube(file = "tasbe/rby.fcs")]
        ex = import_op.apply()
    
        af_op = flow.AutofluorescenceOp()
        af_op.channels = ["Pacific Blue-A", "FITC-A", "PE-Tx-Red-YG-A"]
        af_op.blank_file = "tasbe/blank.fcs"
    
        af_op.estimate(ex)
        af_op.default_view().plot(ex) 
        ex2 = af_op.apply(ex)

    
.. object:: Bleedthrough Correction

    A list of single-color controls to use in bleedthrough compensation.  
    There's one entry per channel to compensate.
    
    .. object:: Channel
    
    The channel that this file is the single-color control for.
    
    .. object:: File
    
    The FCS file containing the single-color control data.
    
    .. plot::
       :context: close-figs
       :include-source: False
    
        bl_op = flow.BleedthroughLinearOp()
        bl_op.controls = {'Pacific Blue-A' : 'tasbe/ebfp.fcs',
                          'FITC-A' : 'tasbe/eyfp.fcs',
                          'PE-Tx-Red-YG-A' : 'tasbe/mkate.fcs'}    
    
        bl_op.estimate(ex2)
        bl_op.default_view().plot(ex2)  
    
        ex3 = bl_op.apply(ex2)  
    
.. object:: Bead Calibration

    .. object: Beads
    
    The beads that you used for calibration.  Make sure to check the lot
    number as well!
    
    .. object: Beads File
    
    The FCS file containing the bead data.
    
    .. object: Beads Unit
    
    The unit (such as *MEFL*) to calibrate to.
    
    .. object:: Peak Quantile
    
    The minimum quantile required to call a peak in the bead data.  Check
    the diagnostic plot: if you have peaks that aren't getting called, decrease
    this.  If you have "noise" peaks that are getting called incorrectly, 
    increase this.
    
    .. object:: Peak Threshold
    
    The minumum brightness where the module will call a peak.
    
    .. object:: Peak Cutoff
    
    The maximum brightness where the module will call a peak.  Use this to 
    remove peaks that are saturating the detector.
    
    .. plot::
       :context: close-figs 
       :include-source: False
    
        bead_op = flow.BeadCalibrationOp()
        beads = "RCP-30-5A Lot AA01, AA02, AA03, AA04, AB01, AB02, AC01 & GAA01-R"
        bead_op.beads = flow.BeadCalibrationOp.BEADS[beads]
        bead_op.units = {"Pacific Blue-A" : "MEBFP",
                         "FITC-A" : "MEFL",
                         "PE-Tx-Red-YG-A" : "MEPTR"}
        bead_op.beads_file = "tasbe/beads.fcs"
    
        bead_op.estimate(ex2)
        bead_op.default_view().plot(ex2)  
        ex3 = bead_op.apply(ex2) 
    
.. object:: Color Translation

    .. object:: To Channel
    
    Which channel should we rescale all the other channels to?
    
    .. object:: Use mixture model?
    
    If this is set, the module will try to separate the data using a 
    mixture-of-Gaussians, then only compute the translation using the higher
    population.  This is the kind of behavior that you see in a transient
    transfection in mammalian cells, for example.
    
    .. object:: Translation list
    
    Each pair of channels must have a multi-color control from which to
    compute the scaling factor.

    .. plot::
       :context: close-figs 
       :include-source: False
    
        color_op = flow.ColorTranslationOp()
        color_op.controls = {("Pacific Blue-A", "FITC-A") : "tasbe/rby.fcs",
                             ("PE-Tx-Red-YG-A", "FITC-A") : "tasbe/rby.fcs"}
        color_op.mixture_model = True
    
        color_op.estimate(ex3)
        color_op.default_view().plot(ex3)  
        ex4 = color_op.apply(ex3)  
'''

from traits.api import provides, Property, List
from traitsui.api import View, Item, VGroup, ButtonEditor, FileEditor, HGroup, EnumEditor, Controller, CheckListEditor, TextEditor
from envisage.api import Plugin
from pyface.api import ImageResource

from cytoflow.operations.bead_calibration import BeadCalibrationOp

from ..view_plugins import ViewHandler
from ..editors import ColorTextEditor, InstanceHandlerEditor, VerticalListEditor, SubsetListEditor
from ..subset_controllers import subset_handler_factory
from ..workflow.operations import TasbeWorkflowOp, TasbeWorkflowView

from .i_op_plugin import IOperationPlugin, OP_PLUGIN_EXT
from .op_plugin_base import OpHandler, shared_op_traits_view, PluginHelpMixin


[docs]class BleedthroughControlHandler(Controller): control_view = View(HGroup(Item('channel', style = 'readonly'), Item('file', editor = FileEditor(dialog_style = 'open'), show_label = False), show_labels = False))
[docs]class TranslationControlHandler(Controller): control_view = View(HGroup(Item('from_channel', style = 'readonly', show_label = False), Item('', label = '->'), Item('to_channel', style = 'readonly', show_label = False), Item('file', editor = FileEditor(dialog_style = 'open'), show_label = False), show_labels = False))
[docs]class UnitHandler(Controller): unit_view = View(HGroup(Item('channel', style = 'readonly', show_label = False), Item('unit', editor = EnumEditor(name = 'context_handler.beads_units'), show_label = False)))
[docs]class TasbeHandler(OpHandler): beads_name_choices = Property(transient = True) beads_units = Property(observe = 'model.beads_name') def _get_beads_name_choices(self): return list(BeadCalibrationOp.BEADS.keys()) def _get_beads_units(self): if self.model.beads_name: return list(BeadCalibrationOp.BEADS[self.model.beads_name].keys()) else: return [] operation_traits_view = \ View(Item("channels", editor = CheckListEditor(cols = 2, name = 'context_handler.previous_channels'), style = 'custom'), VGroup( Item('blank_file', editor = FileEditor(dialog_style = 'open')), label = "Autofluorescence"), VGroup( Item('bleedthrough_list', editor = VerticalListEditor(editor = InstanceHandlerEditor(view = 'control_view', handler_factory = BleedthroughControlHandler), style = 'custom', mutable = False)), label = "Bleedthrough Correction", show_border = False, show_labels = False), VGroup( Item('beads_name', editor = EnumEditor(name = 'handler.beads_name_choices'), label = "Beads", width = -125), Item('beads_file', editor = FileEditor(dialog_style = 'open')), Item('beads_unit', editor = EnumEditor(name = 'handler.beads_units'), visible_when = 'do_color_translation == True'), Item('units_list', editor = VerticalListEditor(editor = InstanceHandlerEditor(view = 'unit_view', handler_factory = UnitHandler), style = 'custom', mutable = False), label = "Bead\nunits", visible_when = 'do_color_translation == False'), Item('bead_peak_quantile', editor = TextEditor(auto_set = False, evaluate = int, format_func = lambda x: "" if x is None else str(x), placeholder = "None"), label = "Peak\nQuantile"), Item('bead_brightness_threshold', editor = TextEditor(auto_set = False, evaluate = float, format_func = lambda x: "" if x is None else str(x), placeholder = "None"), label = "Peak\nThreshold "), Item('bead_brightness_cutoff', editor = TextEditor(auto_set = False, evaluate = float, format_func = lambda x: "" if x is None else str(x), placeholder = "None"), label = "Peak\nCutoff"), label = "Bead Calibration", show_border = False), VGroup( Item('do_color_translation', label = 'Do color translation?'), Item('to_channel', editor = EnumEditor(name = 'channels'), visible_when = 'do_color_translation == True'), Item('mixture_model', label = "Use mixture\nmodel?", visible_when = 'do_color_translation == True'), label = "Color Translation"), VGroup( Item('translation_list', editor = VerticalListEditor(editor = InstanceHandlerEditor(view = 'control_view', handler_factory = TranslationControlHandler), style = 'custom', mutable = False), visible_when = 'do_color_translation == True'), show_labels = False), VGroup(Item('subset_list', show_label = False, editor = SubsetListEditor(conditions = "context_handler.previous_conditions", editor = InstanceHandlerEditor(view = 'subset_view', handler_factory = subset_handler_factory))), label = "Subset", show_border = False, show_labels = False), Item('estimate_progress', style = 'readonly'), Item('do_estimate', editor = ButtonEditor(value = True, label = "Estimate!"), show_label = False), shared_op_traits_view)
[docs]class TasbeViewHandler(ViewHandler): view_traits_view = \ View(Item('context.view_warning', resizable = True, visible_when = 'context.view_warning', editor = ColorTextEditor(foreground_color = "#000000", background_color = "#ffff99")), Item('context.view_error', resizable = True, visible_when = 'context.view_error', editor = ColorTextEditor(foreground_color = "#000000", background_color = "#ff9191"))) view_params_view = View()
[docs]@provides(IOperationPlugin) class TasbePlugin(Plugin, PluginHelpMixin): id = 'edu.mit.synbio.cytoflowgui.op_plugins.tasbe' operation_id = 'edu.mit.synbio.cytoflowgui.workflow.operations.tasbe' view_id = 'edu.mit.synbio.cytoflowgui.workflow.operations.tasbeview' short_name = "TASBE Calibration" menu_group = "Gates"
[docs] def get_operation(self): return TasbeWorkflowOp()
[docs] def get_handler(self, model, context): if isinstance(model, TasbeWorkflowOp): return TasbeHandler(model = model, context = context) elif isinstance(model, TasbeWorkflowView): return TasbeViewHandler(model = model, context = context)
[docs] def get_icon(self): return ImageResource('tasbe')
plugin = List(contributes_to = OP_PLUGIN_EXT) def _plugin_default(self): return [self]