Beispiel #1
0
    def default_traits_view(self):
        return View(Item("channels",
                         editor = CheckListEditor(cols = 2,
                                                  name = 'context.previous_wi.channels'),
                         style = 'custom'),
                    VGroup(
                        Item('blank_file'),
                        label = "Autofluorescence"),
                    VGroup(
                        Item('bleedthrough_list',
                                editor = VerticalListEditor(editor = InstanceEditor(view = self.bleedthrough_traits_view()),
                                                            style = 'custom',
                                                            mutable = False),
                                style = 'custom'),
                        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'),
                        Item('beads_unit', 
                             editor = EnumEditor(name = 'handler.beads_units')),
                        Item('bead_peak_quantile',
                             label = "Peak\nQuantile"),
                        Item('bead_brightness_threshold',
                             label = "Peak\nThreshold "),
                        Item('bead_brightness_cutoff',
                             label = "Peak\nCutoff"),
                        label = "Bead Calibration",
                        show_border = False),
                    VGroup(
                        Item('to_channel',
                             editor = EnumEditor(name = 'channels')),
                        Item('mixture_model',
                             label = "Use mixture\nmodel?"),
                           label = "Color Translation"),
                    VGroup(
                        Item('translation_list',
                                editor = VerticalListEditor(editor = InstanceEditor(view = self.translation_traits_view()),
                                                            style = 'custom',
                                                            mutable = False),
                                style = 'custom'),

                        show_labels = False),
                    VGroup(Item('subset_list',
                                show_label = False,
                                editor = SubsetListEditor(conditions = "context.previous_wi.conditions",
                                                      metadata = "context.previous_wi.metadata",
                                                      when = "'experiment' not in vars() or not experiment")),
                           label = "Subset",
                           show_border = False,
                           show_labels = False),
                    Item('do_estimate',
                         editor = ButtonEditor(value = True,
                                               label = "Estimate!"),
                         show_label = False),
                    shared_op_traits)
 def default_traits_view(self):
     return View(VGroup(Item('controls_list',
                             editor = VerticalListEditor(editor = InstanceEditor(view = self.control_traits_view()),
                                                         style = 'custom',
                                                         mutable = False),
                             style = 'custom'),
                 Item('handler.add_control',
                      editor = ButtonEditor(value = True,
                                            label = "Add a control")),
                 Item('handler.remove_control',
                      editor = ButtonEditor(value = True,
                                            label = "Remove a control")),
                 label = "Controls",
                 show_labels = False),
                 Item('mixture_model',
                      label = "Use mixture\nmodel?"),
                 VGroup(Item('subset_list',
                             show_label = False,
                             editor = SubsetListEditor(conditions = "context.previous_wi.conditions",
                                                       metadata = "context.previous_wi.metadata",
                                                       when = "'experiment' not in vars() or not experiment")),
                        label = "Subset",
                        show_border = False,
                        show_labels = False),
                 Item('do_estimate',
                      editor = ButtonEditor(value = True,
                                            label = "Estimate!"),
                      show_label = False),
                 shared_op_traits)
Beispiel #3
0
 def default_traits_view(self):
     return View(
         VGroup(
             Item('beads_name',
                  editor=EnumEditor(name='handler.beads_name_choices'),
                  label="Beads",
                  width=-125), Item('beads_file', width=-125)),
         VGroup(Item('units_list',
                     editor=VerticalListEditor(editor=InstanceEditor(
                         view=self.unit_traits_view()),
                                               style='custom',
                                               mutable=False),
                     style='custom'),
                Item('handler.add_channel',
                     editor=ButtonEditor(value=True,
                                         label="Add a channel")),
                Item('handler.remove_channel',
                     editor=ButtonEditor(value=True,
                                         label="Remove a channel")),
                label="Controls",
                show_labels=False),
         Item('bead_peak_quantile', label="Peak\nQuantile"),
         Item('bead_brightness_threshold', label="Peak\nThreshold "),
         Item('bead_brightness_cutoff', label="Peak\nCutoff"),
         Item('do_estimate',
              editor=ButtonEditor(value=True, label="Estimate!"),
              show_label=False), shared_op_traits)
 def default_traits_view(self):
     return View(
         VGroup(Item('channels_list',
                     editor=VerticalListEditor(editor=InstanceEditor(
                         view=self.channel_traits_view()),
                                               style='custom',
                                               mutable=False),
                     style='custom'),
                Item('handler.add_channel',
                     editor=ButtonEditor(value=True,
                                         label="Add a channel")),
                Item('handler.remove_channel',
                     editor=ButtonEditor(value=True,
                                         label="Remove a channel")),
                show_labels=False),
         VGroup(Item('xfacet',
                     editor=ExtendableEnumEditor(
                         name='handler.conditions_names',
                         extra_items={"None": ""}),
                     label="Horizontal\nFacet"),
                Item('yfacet',
                     editor=ExtendableEnumEditor(
                         name='handler.conditions_names',
                         extra_items={"None": ""}),
                     label="Vertical\nFacet"),
                Item('huefacet',
                     editor=ExtendableEnumEditor(
                         name='handler.conditions_names',
                         extra_items={"None": ""}),
                     label="Color\nFacet"),
                Item('huescale', label="Color\nScale"),
                Item('plotfacet',
                     editor=ExtendableEnumEditor(
                         name='handler.conditions_names',
                         extra_items={"None": ""}),
                     label="Tab\nFacet"),
                label="2D Histogram",
                show_border=False),
         VGroup(Item(
             'subset_list',
             show_label=False,
             editor=SubsetListEditor(conditions="context.conditions")),
                label="Subset",
                show_border=False,
                show_labels=False),
         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")))
Beispiel #5
0
 def default_traits_view(self):
     return View(Item('name',
                      editor = TextEditor(auto_set = False)),
                 VGroup(Item('channels_list',
                             editor = VerticalListEditor(editor = InstanceEditor(view = self.channel_traits_view()),
                                                         style = 'custom',
                                                         mutable = False),
                             style = 'custom'),
                 Item('handler.add_channel',
                      editor = ButtonEditor(value = True,
                                            label = "Add a channel"),
                      show_label = False),
                 Item('handler.remove_channel',
                      editor = ButtonEditor(value = True,
                                            label = "Remove a channel")),
                 show_labels = False),
                 VGroup(Item('num_components',
                             editor = TextEditor(auto_set = False),
                             label = "Num\nComponents"),
                        Item('whiten'),
                        Item('by',
                             editor = CheckListEditor(cols = 2,
                                                      name = 'handler.previous_conditions_names'),
                             label = 'Group\nEstimates\nBy',
                             style = 'custom'),
                        label = "Estimate parameters"),
                 VGroup(Item('subset_list',
                             show_label = False,
                             editor = SubsetListEditor(conditions = "context.previous_wi.conditions",
                                                       metadata = "context.previous_wi.metadata",
                                                       when = "'experiment' not in vars() or not experiment")),
                        label = "Subset",
                        show_border = False,
                        show_labels = False),
                 Item('do_estimate',
                      editor = ButtonEditor(value = True,
                                            label = "Estimate!"),
                      show_label = False),
                 shared_op_traits)
Beispiel #6
0
 def default_traits_view(self):
     return View(
         VGroup(Label(label="Channels", visible_when='model.tubes'),
                Item('object.channels_list',
                     editor=VerticalListEditor(editor=InstanceEditor(),
                                               style='custom',
                                               mutable=False,
                                               deletable=True),
                     show_label=False),
                Item('handler.reset_channels', show_label=False),
                visible_when='object.channels_list'),
         Item('object.events',
              editor=TextEditor(auto_set=False,
                                format_func=lambda x: ""
                                if x == None else str(x)),
              label="Events per\nsample"),
         Item('handler.samples', label='Samples', style='readonly'),
         Item('ret_events', label='Events', style='readonly'),
         Item('handler.setup_event', show_label=False),
         Item('do_estimate',
              editor=ButtonEditor(value=True, label="Import!"),
              show_label=False), shared_op_traits)
Beispiel #7
0
 def default_traits_view(self):
     return View(
                 VGroup(
                     Item('blank_file'),
                     label = "Autofluorescence"),
                 VGroup(
                     Item('fsc_channel',
                          editor = EnumEditor(name = '_blank_exp_channels'),
                          label = "Forward Scatter Channel"),
                     Item('ssc_channel',
                          editor = EnumEditor(name = '_blank_exp_channels'),
                          label = "Side Scatter Channel"),
                     label = "Morphology"),
                 VGroup(
                     Item("channels",
                          editor = CheckListEditor(cols = 2,
                                                   name = '_blank_exp_channels'),
                          style = 'custom'),
                     label = "Channels To Calibrate",
                     show_labels = False),
                 VGroup(
                     Item('bleedthrough_list',
                             editor = VerticalListEditor(editor = InstanceEditor(view = self.bleedthrough_traits_view()),
                                                         style = 'custom',
                                                         mutable = False),
                             style = 'custom'),
                     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'),
                     Item('units_list',
                             editor = VerticalListEditor(editor = InstanceEditor(view = self.unit_traits_view()),
                                                         style = 'custom',
                                                         mutable = False),
                             style = 'custom',
                             label = "Bead\nunits"),
                     Item('bead_peak_quantile',
                          label = "Peak\nQuantile"),
                     Item('bead_brightness_threshold',
                          label = "Peak\nThreshold "),
                     Item('bead_brightness_cutoff',
                          label = "Peak\nCutoff"),
                     label = "Bead Calibration",
                     show_border = False),
                 VGroup(
                     Item('do_color_translation',
                          label = "Do color translation?",
                          editor = ToggleButtonEditor(),
                          show_label = False),
                     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'),
                     VGroup(
                         Item('translation_list',
                              editor = VerticalListEditor(editor = InstanceEditor(view = self.translation_traits_view()),
                                                          style = 'custom',
                                                          mutable = False),
                            style = 'custom'),
                            show_labels = False,
                            visible_when = 'do_color_translation == True'),
                     label = "Color Translation",
                     show_border = False),
                 VGroup(
                     Item('status',
                          style = 'readonly'),
                     Item('output_directory'),
                     Item('do_estimate',
                          editor = ButtonEditor(value = True,
                                                label = "Estimate parameters"),
                          show_label = False),
                     Item('handler.do_convert',
                          editor = ButtonEditor(value = True,
                                                label = "Convert files..."),
                          enabled_when = "valid_model == True",
                          show_label = False),
                     label = "Output",
                     show_border = False),
                 Item('do_exit',
                      editor = ButtonEditor(value = True,
                                            label = "Return to Cytoflow"),
                      show_label = False),
                 shared_op_traits)
Beispiel #8
0
class ExperimentDialogHandler(Controller):
    
    
    # bits for model initialization
    import_op = Instance('cytoflowgui.op_plugins.import_op.ImportPluginOp')
        
    # events
    add_tubes = Event
    remove_tubes = Event
    add_variable = Event
    import_csv = Event
    
    # traits to communicate with the TabularEditor
    selected_tubes = List
    
    default_view = View(
            HGroup(
                VGroup(
                    Label("Variables"),
                    Item('tube_traits',
                         editor = VerticalListEditor(editor = InstanceEditor(),
                                                     style = 'custom',
                                                     mutable = False,
                                                     deletable = True),
                         show_label = False),
                    HGroup(
                        Item('handler.add_variable',
                             editor = ButtonEditor(label = "Add a variable"),
                             show_label = False))),
                VGroup(
                    Label("Tubes"),
                    Item(name = 'tubes', 
                         id = 'table', 
                         editor = TableEditor(editable = True,
                                              sortable = True,
                                              auto_size = True,
                                              configurable = False,
                                              selection_mode = 'rows',
                                              selected = 'handler.selected_tubes',
                                              columns = [ObjectColumn(name = 'index',
                                                                      read_only_cell_color = 'lightgrey',
                                                                      editable = False)]),
                         enabled_when = "object.tubes",
                         show_label = False),
                    HGroup(
                        Item('handler.add_tubes',
                             editor = ButtonEditor(label = "Add tubes..."),
                             show_label = False),
                        Item('handler.remove_tubes',
                             editor = ButtonEditor(label = "Remove tubes"),
                             show_label = False,
                             enabled_when = 'object.tubes'),
                        Item('handler.import_csv',
                             editor = ButtonEditor(label = "Import from CSV..."),
                             show_label = False)))),
            title     = 'Experiment Setup',
            buttons = OKCancelButtons,
            resizable = True,
            width = 0.3,
            height = 0.3
        )

    # keep a ref to the table editor so we can add columns dynamically
    table_editor = Instance(TableEditorQt)
    
    updating = Bool(False)
    
    def init(self, info):
                       
        # save a reference to the table editor
        self.table_editor = info.ui.get_editors('tubes')[0]
        
        # init the model
        self.model.init(self.import_op)
                
        return True
    
    def close(self, info, is_ok):
        """ Handles the user attempting to close a dialog-based user interface.

        This method is called when the user attempts to close a window, by
        clicking an **OK** or **Cancel** button, or clicking a Close control
        on the window). It is called before the window is actually destroyed.
        Override this method to perform any checks before closing a window.

        While Traits UI handles "OK" and "Cancel" events automatically, you
        can use the value of the *is_ok* parameter to implement additional
        behavior.

        Parameters
        ----------
        info : UIInfo object
            The UIInfo object associated with the view
        is_ok : Boolean
            Indicates whether the user confirmed the changes (such as by
            clicking **OK**.)

        Returns
        -------
        allow_close : bool
            A Boolean, indicating whether the window should be allowed to close.
        """
        if is_ok:
            if not self.model.valid:
                error(None, 
                      "Each tube must have a unique set of experimental conditions",
                      "Invalid experiment!")
                return False

        if not is_ok:
            # we don't need to "undo" anything, we're throwing this model away
            info.ui.history = None

        return True
    
    
    def closed(self, info, is_ok):
        for trait in self.model.tube_traits:
            if trait.type != 'metadata':
                for tube in self.model.tubes:
                    tube.on_trait_change(self._try_multiedit, 
                                         trait.name, 
                                         remove = True)
        if is_ok:
            self.model.update_import_op(self.import_op)
        
            
    @on_trait_change('add_variable')
    def _on_add_variable(self):
        self.model.tube_traits.append(TubeTrait(model = self.model))
        
            
    @on_trait_change('import_csv')
    def _on_import(self):
        """
        Import format: CSV, first column is filename, path relative to CSV.
        others are conditions, type is autodetected.  first row is header
        with names.
        """
        file_dialog = FileDialog()
        file_dialog.wildcard = "CSV files (*.csv)|*.csv|"
        file_dialog.action = 'open'
        file_dialog.open()
        
        if file_dialog.return_code != PyfaceOK:
            return
        
        csv = pandas.read_csv(file_dialog.path)
        csv_folder = Path(file_dialog.path).parent
        
        if self.model.tubes or self.model.tube_traits:
            if confirm(parent = None,
                       message = "This will clear the current conditions and tubes! "
                                 "Are you sure you want to continue?",
                       title = "Clear tubes and conditions?") != YES:
                return
        
        
        for col in csv.columns[1:]:
            self.model.tube_traits.append(TubeTrait(model = self.model,
                                                    name = util.sanitize_identifier(col),
                                                    type = 'category'))
            
            
        for _, row in csv.iterrows():
            filename = csv_folder / row[0]
            
            try:
                metadata, _ = parse_tube(str(filename), metadata_only = True)
            except Exception as e:
                warning(None, "Had trouble loading file {}: {}".format(filename, str(e)))
                continue

            metadata['CF_File'] = Path(filename).stem
            new_tube = Tube(file = str(filename), parent = self.model, metadata = sanitize_metadata(metadata))
            self.model.tubes.append(new_tube)

            for col in csv.columns[1:]:
                new_tube.trait_set(**{util.sanitize_identifier(col) : row[col]})
            
        
        
    @on_trait_change('add_tubes')
    def _on_add_tubes(self):
        """
        Handle "Add tubes..." button.  Add tubes to the experiment.
        """
        
        file_dialog = FileDialog()
        file_dialog.wildcard = "Flow cytometry files (*.fcs *.lmd)|*.fcs *.lmd|"
        file_dialog.action = 'open files'
        file_dialog.open()
        
        if file_dialog.return_code != PyfaceOK:
            return
        
        for path in file_dialog.paths:
            try:
                metadata, _ = parse_tube(path, metadata_only = True)
            except Exception as e:
                raise RuntimeError("FCS reader threw an error on tube {0}: {1}"\
                                   .format(path, e.value))
                
            # if we're the first tube loaded, create a dummy experiment
            # and setup default metadata columns
            if not self.model.dummy_experiment:
                self.model.dummy_experiment = \
                    ImportOp(tubes = [CytoflowTube(file = path)]).apply(metadata_only = True)
                                                       
            # check the next tube against the dummy experiment
            try:
                check_tube(path, self.model.dummy_experiment)
            except util.CytoflowError as e:
                error(None, e.__str__(), "Error importing tube")
                return
            
            metadata['CF_File'] = Path(path).stem    
            tube = Tube(file = path, parent = self.model, metadata = sanitize_metadata(metadata))
            
            self.model.tubes.append(tube)
            
            for trait in self.model.tube_traits:
                if trait.type != 'metadata' and trait.name:
                    tube.on_trait_change(self._try_multiedit, trait.name)
         
            
    @on_trait_change('remove_tubes')
    def _on_remove_tubes(self):
        conf = confirm(None,
                       "Are you sure you want to remove the selected tube(s)?",
                       "Remove tubes?")
        if conf == YES:
            for tube in self.selected_tubes:
                self.model.tubes.remove(tube)
                
        if not self.model.tubes:
            self.model.dummy_experiment = None

                
    @on_trait_change('model:tube_traits_items', post_init = True)
    def _tube_traits_changed(self, event):
        for trait in event.added:
            if not trait.name:
                continue
            
            if self.table_editor:
                self.table_editor.columns.append(ExperimentColumn(name = trait.name,
                                                                  editable = (trait.type != 'metadata')))                 
            for tube in self.model.tubes:   
                if trait.type != 'metadata' and trait.name:
                    tube.on_trait_change(self._try_multiedit, trait.name)

        for trait in event.removed:
            if not trait.name:
                continue
            
            table_column = next((x for x in self.table_editor.columns if x.name == trait.name))
            self.table_editor.columns.remove(table_column)
            
            for tube in self.model.tubes:
                if trait.type != 'metadata' and trait.name:
                    tube.on_trait_change(self._try_multiedit, trait.name, remove = True)
                    
                    
    @on_trait_change('model:tube_traits:name')
    def _tube_trait_name_changed(self, trait, _, old_name, new_name):
        if old_name:
            old_table_column = next((x for x in self.table_editor.columns if x.name == old_name))
            column_idx = self.table_editor.columns.index(old_table_column)
        else:
            column_idx = len(self.table_editor.columns)
                
        if new_name:
            self.table_editor.columns.insert(column_idx,
                                             ExperimentColumn(name = new_name,
                                                              editable = (trait.type != 'metadata')))
            
        if old_name:          
            self.table_editor.columns.remove(old_table_column)
               
        for tube in self.model.tubes:   
            if trait.type != 'metadata':
                if old_name:
                    tube.on_trait_change(self._try_multiedit, old_name, remove = True)
                    
                if new_name:
                    tube.on_trait_change(self._try_multiedit, new_name)
                
            if old_name:
                tube.remove_trait(old_name)
                
            
        self.model.counter.clear()
        for tube in self.model.tubes:
            tube_hash = tube.conditions_hash()
            if tube_hash in self.model.counter:
                self.model.counter[tube_hash] += 1
            else:
                self.model.counter[tube_hash] = 1
                
    @on_trait_change('model:tube_traits:type')
    def _tube_trait_type_changed(self, trait, _, old_type, new_type):
        if not trait.name:
            return
        
        table_column = next((x for x in self.table_editor.columns if x.name == trait.name))
        
        table_column.editable = (new_type != 'metadata')  
        
        for tube in self.model.tubes:
            if trait.name:
                if old_type != 'metadata':
                    tube.on_trait_change(self._try_multiedit, trait.name, remove = True)
                    
                if new_type != 'metadata':
                    tube.on_trait_change(self._try_multiedit, trait.name)
                  
                    
            
    def _try_multiedit(self, obj, name, old, new):
        """
        See if there are multiple elements selected when a tube's trait changes
        
        and if so, edit the same trait for all the selected tubes.
        """
        
        if self.updating:
            return
        
        self.updating = True

        for tube in self.selected_tubes:
            if tube != obj:
                old_hash = tube.conditions_hash()
                self.model.counter[old_hash] -= 1
                if self.model.counter[old_hash] == 0:
                    del self.model.counter[old_hash]            
    
                # update the underlying traits without notifying the editor
                # we do this all here for performance reasons
                tube.trait_setq(**{name: new})
                tube.conditions[name] = new
                
                new_hash = tube.conditions_hash()
                if new_hash not in self.model.counter:
                    self.model.counter[new_hash] = 1
                else:
                    self.model.counter[new_hash] += 1
                

        # now refresh the editor all at once
        self.table_editor.refresh_editor()
        self.updating = False