Changeset 1385:b4403b620014 in orange-bioinformatics


Ignore:
Timestamp:
05/12/11 14:33:07 (3 years ago)
Author:
ales_erjavec <ales.erjavec@…>
Branch:
default
Convert:
aeb451a4d1517eb894ad6bfdfb5fa50e0e225b1e
Message:

Changed the way target labels are selected by the user in Vulcano Plot.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • obiExpression.py

    r1284 r1385  
    180180    def test_indices(self, target, classes=None): 
    181181        classes = self.classes if classes is None else classes 
     182         
     183        def target_set(target): 
     184            if isinstance(target, tuple): 
     185                return set([target]) 
     186            else: 
     187                assert(isinstance(target, set)) 
     188                return target 
     189             
    182190        if self.useAttributeLabels: 
    183             if type(target) in [list]: 
    184                 ind = [[i for i, cl in enumerate(self.classes) if cl >= set([t])] for t in target] 
     191            if isinstance(target, list): 
     192                ind = [[i for i, cl in enumerate(self.classes) if target_set(t).intersection(cl)] for t in target] 
    185193            else: 
    186                 ind1 = [i for i, cl in enumerate(self.classes) if cl >= set([target])] 
    187                 ind2 = [i for i, cl in enumerate(self.classes) if not cl >= set([target])] 
     194                target = target_set(target) 
     195                 
     196                ind1 = [i for i, cl in enumerate(self.classes) if target.intersection(cl)] 
     197                ind2 = [i for i, cl in enumerate(self.classes) if not target.intersection(cl)] 
    188198                ind = [ind1, ind2] 
    189199        else: 
    190             if type(target) in [list, tuple]: 
     200            if isinstance(target, list): 
    191201                ind = [ma.nonzero(self.classes == t)[0] for t in target] 
    192202            else: 
    193                 ind1 = ma.nonzero(self.classes == target)[0] 
    194                 ind2 = ma.nonzero(self.classes != target)[0] 
     203                if isinstance(target, (basestring, orange.Variable)): 
     204                    target = set([target]) 
     205                else: 
     206                    assert(isinstance(target, set)) 
     207                target = list(target) 
     208                ind1 = [i for i, cl in enumerate(self.classes) if cl in target] 
     209                ind2 = [i for i, cl in enumerate(self.classes) if cl not in target] 
    195210                ind = [ind1, ind2] 
     211                 
    196212        return ind 
    197213     
  • widgets/OWVulcanoPlot.py

    r1383 r1385  
    1212import orange 
    1313import itertools 
     14from operator import add 
     15from collections import defaultdict 
    1416from math import log 
    1517from statc import mean, ttest_ind 
    1618from obiGEO import transpose 
    1719import obiExpression 
     20import numpy 
    1821 
    1922from orngDataCaching import data_hints 
     
    125128        return (numpy.abs(data[:, 0]) >= cutoffX) & (data[:, 1] >= cutoffY) 
    126129     
     130from OWItemModels import PyListModel 
     131 
     132def item_selection(indices, model, selection=None, column=0): 
     133    """ Create an QItemSelection for indices in model. 
     134    """ 
     135    if selection is None: 
     136        selection = QItemSelection() 
     137         
     138    for i in indices: 
     139        selection.select(model.index(i, column)) 
     140    return selection 
     141 
     142 
     143class LabelSelectionWidget(QWidget): 
     144    """ A widget for selection of label values. 
     145    """ 
     146    def __init__(self, parent=None): 
     147        QWidget.__init__(self, parent) 
     148        self._values_model = PyListModel([], parent=self) 
     149        layout = QVBoxLayout() 
     150        layout.setContentsMargins(0, 0, 0, 0) 
     151        def group_box(title): 
     152            box = QGroupBox(title) 
     153            box.setFlat(True) 
     154            lay = QVBoxLayout() 
     155            lay.setContentsMargins(0, 0, 0, 0) 
     156            box.setLayout(lay) 
     157            return box 
     158         
     159        self.labels_combo = QComboBox() 
     160        self.values_view = QListView() 
     161        self.values_view.setSelectionMode(QListView.ExtendedSelection) 
     162        self.values_view.setModel(self._values_model) 
     163         
     164         
     165        self.connect(self.labels_combo, SIGNAL("activated(int)"), 
     166                     self.on_label_activated) 
     167         
     168        self.connect(self.values_view.selectionModel(), 
     169                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), 
     170                     self.on_values_selection) 
     171         
     172        l_box = group_box("Label") 
     173        v_box = group_box("Values") 
     174         
     175        l_box.layout().addWidget(self.labels_combo) 
     176        v_box.layout().addWidget(self.values_view) 
     177         
     178        layout.addWidget(l_box) 
     179        layout.addWidget(v_box) 
     180         
     181        self.setLayout(layout) 
     182         
     183        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) 
     184         
     185        self._block_selection_emit = False 
     186         
     187        self.labels = [] 
     188        self.set_labels([]) 
     189         
     190    def clear(self): 
     191        self.labels_combo.clear() 
     192#        self.values_view.clear() 
     193        self._values_model[:] = [] 
     194        self.labels = [] 
     195         
     196    def set_labels(self, labels): 
     197        """ Set the labels to display. 
     198        """ 
     199        self.clear() 
     200        if isinstance(labels, dict): 
     201            labels = labels.items() 
     202             
     203        self.labels = labels 
     204        for label, values in labels: 
     205            self.labels_combo.addItem(label) 
     206             
     207        if labels: 
     208            self.set_current_label(0) 
     209#            self.labels_combo.setCurrentIndex(0) 
     210             
     211    def set_selection(self, label, values): 
     212        """ Set the selection to label and values 
     213        """ 
     214        if isinstance(label, basestring): 
     215            labels = [l for l, _ in self.labels] 
     216            index = labels.index(label) if label in labels else -1 
     217        else: 
     218            index = label 
     219             
     220        if index >= 0: 
     221            if index != self.labels_combo.currentIndex(): 
     222                self.set_current_label(index) 
     223                 
     224            all_values = list(self._values_model) 
     225            values = [v for v in values if v in all_values] 
     226            selection = QItemSelection() 
     227            for i, v in enumerate(self._values_model): 
     228                if v in values: 
     229                    index = self._values_model.index(i, 0) 
     230                    selection.select(index, index) 
     231            self.values_view.selectionModel().select(selection,  QItemSelectionModel.ClearAndSelect) 
     232             
     233    def set_current_label(self, index): 
     234        """ Set the current label 
     235        """ 
     236        self.labels_combo.setCurrentIndex(index) 
     237        label, values = self.labels[index] 
     238#        self._block_selection_emit = True 
     239        # Block selection changed 
     240        with self._blocked_signals(): 
     241            self._values_model[:] = values 
     242#        self._block_selection_emit = False 
     243         
     244    def on_label_activated(self, index): 
     245        label, values = self.labels[index] 
     246        with self._blocked_signals(): 
     247            self._values_model[:] = values 
     248        self.emit(SIGNAL("label_activated()")) 
     249        self.emit(SIGNAL("label_activated(int)"), index) 
     250     
     251    def on_values_selection(self, selected, deselected): 
     252        label, values = self.current_selection() 
     253        self.emit(SIGNAL("selection_changed()")) 
     254        self.emit(SIGNAL("selection_changed(PyQt_PyObject, PyQt_PyObject)"), 
     255                  label, values) 
     256         
     257    def selection_indexes(self): 
     258        """ Return the values selection indices. 
     259        """ 
     260        selection = self.values_view.selectionModel().selection() 
     261        indexes = selection.indexes() 
     262        return sorted(set([i.row() for i in indexes]))         
     263         
     264    def current_selection(self): 
     265        """ Return the current label and selected values. 
     266        """ 
     267        i = self.labels_combo.currentIndex() 
     268        label, all_values = self.labels[i] 
     269        values = [all_values[i] for i in self.selection_indexes()] 
     270        return label, values 
     271     
     272    def _blocked_signals(self): 
     273        """ Return a context handler blocking all emited signals from this 
     274        object. 
     275          
     276        """ 
     277        class block(object): 
     278            def __enter__(blocker): 
     279                self.blockSignals(True) 
     280            def __exit__(blocker, *args): 
     281                self.blockSignals(False) 
     282                return False 
     283        return block() 
     284                 
     285    def sizeHint(self): 
     286        return QSize(100, 200) 
     287             
     288         
    127289class VulcanoGraph(OWGraph): 
    128290    def __init__(self, master, *args, **kwargs): 
     
    255417        setSize(self.unselectedCurve, self.symbolSize) 
    256418        self.replot() 
     419         
     420from OWGenotypeDistances import SetContextHandler 
     421from OWFeatureSelection import disable_controls 
    257422 
    258423class OWVulcanoPlot(OWWidget): 
    259424    settingsList =["targetClass", "graph.cutoffX", "graph.cutoffY", "graph.symbolSize", "graph.symetricSelections", "showXTitle", "showYTitle"] 
    260425    contextHandlers = {"":DomainContextHandler("", [ContextField("targetClass"), ContextField("graph.cutoffX"), 
    261                                                     ContextField("graph.cutoffY")])} 
     426                                                    ContextField("graph.cutoffY")]), 
     427                       "targets": SetContextHandler("targets")} 
    262428    def __init__(self, parent=None, signalManager=None, name="Vulcano Plot"): 
    263429        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True) 
     
    274440        self.autoCommit = False 
    275441        self.selectionChangedFlag = False 
     442        self.target_group = None, [] 
     443        self.label_selections = [] 
    276444 
    277445        self.graph = VulcanoGraph(self) 
    278446        self.mainArea.layout().addWidget(self.graph) 
    279447 
     448        self.loadSettings() 
     449         
    280450        ## GUI 
    281451        box = OWGUI.widgetBox(self.controlArea, "Info") 
    282452        self.infoLabel = OWGUI.label(box, self, "") 
    283         self.infoLabel.setText("No data on input\n") 
     453        self.infoLabel.setText("No data on input") 
    284454        self.infoLabel2 = OWGUI.label(box, self, "") 
    285455        self.infoLabel2.setText("0 selected genes") 
    286456         
    287         box = OWGUI.widgetBox(self.controlArea, "Group By") 
    288         self.genesInColumnsCheck = OWGUI.checkBox(box, self, "genesInColumns", "Genes in columns", callback=[self.setTargetCombo, self.plot]) 
    289         self.targetClassCombo = OWGUI.comboBox(box, self, "targetClass", callback=self.plot) 
     457        box = OWGUI.widgetBox(self.controlArea, "Target Labels") 
     458         
     459        self.target_widget = LabelSelectionWidget(self) 
     460        self.connect(self.target_widget, 
     461                     SIGNAL("selection_changed(PyQt_PyObject, PyQt_PyObject)"), 
     462                     self.on_target_changed) 
     463        self.connect(self.target_widget, 
     464                     SIGNAL("label_activated(int)"), 
     465                     self.on_label_activated) 
     466         
     467        box.layout().addWidget(self.target_widget) 
     468         
     469        self.genesInColumnsCheck = OWGUI.checkBox(box, self, "genesInColumns", 
     470                                    "Genes in columns",  
     471                                    callback=[self.update_target_labels, self.plot]) 
    290472 
    291473        box = OWGUI.widgetBox(self.controlArea, "Settings") 
     
    306488            button_layotu.addItem(item) 
    307489         
    308          
    309490        OWGUI.checkBox(toolbar, self, "graph.symetricSelections", "Symetric selection", callback=self.graph.reselect) 
    310491 
     
    319500 
    320501        self.data = None 
     502        self.target_group = None, [] 
    321503         
    322504        self.resize(800, 600) 
     
    324506    def setData(self, data=None): 
    325507        self.closeContext() 
     508        self.closeContext("targets") 
    326509        self.data = data 
    327         self.targetClassCombo.clear() 
    328         self.targetClass = 0 
     510        self.target_group = None, [] 
    329511        self.error(0) 
    330512        if data: 
     
    333515            if self.genesInColumns: 
    334516                self.genesInColumns = not data_hints.get_hint(data, "genesinrows", not self.genesInColumns)  
    335             self.setTargetCombo() 
     517            self.update_target_labels() 
    336518            self.error() 
    337519            if not self.targets: 
    338520                self.error(0, "Data set with no column labels (attribute tags) or row labels (classes).") 
    339521        else: 
    340             self.infoLabel.setText("No data on input\n") 
     522            self.infoLabel.setText("No data on input") 
    341523            self.targets = [] 
     524            self.plot() 
     525             
    342526        self.openContext("", data) 
    343         self.plot() 
    344          
    345     def setTargetCombo(self): 
    346         if self.genesInColumns: 
    347             items = set(reduce(list.__add__, [attr.attributes.items() for attr in (self.data.domain.attributes if self.data else [])], [])) 
    348             grouped = itertools.groupby(sorted(items), key=lambda pair: pair[0]) 
    349             targets = [(key, [value for _, value in group]) for key, group in grouped] 
    350             targets = [(key, values) for key, values in targets if len(values) > 1] 
    351              
    352             self.targets = [(key, value) for key, values in targets for value in values] 
    353             measurements = [attr.attributes.items() for attr in (self.data.domain.attributes if self.data else [])] 
    354             targets = ["%s: %s" % t for t in self.targets] 
    355              
    356         else: 
    357             self.targets = list(self.data.domain.classVar.values if self.data else []) 
    358             measurements = [set([str(ex.getclass())]) for ex in (self.data if self.data else [])] 
    359             targets = self.targets 
    360                                  
    361         self.targetMeasurements = [len([m for m in measurements if target in m]) for target in self.targets] 
    362          
    363         self.targetClassCombo.clear() 
    364         self.targetClassCombo.addItems(targets) 
    365                               
     527        self.openContext("targets", [(label, v) for label, vals in self.targets \ 
     528                                                for v in vals]) 
     529         
     530        if self.target_group == (None, []) and self.targets: 
     531            label, values = self.targets[0] 
     532            self.target_group = (label, values[:1]) 
     533             
     534        if self.target_group != (None, []): 
     535            self.target_widget.set_selection(*self.target_group) 
     536 
     537    def update_target_labels(self): 
     538        if self.data: 
     539            if self.genesInColumns: 
     540                items = [a.attributes.items() for a in self.data.domain.attributes] 
     541                items = reduce(add, items, []) 
     542                 
     543                targets = defaultdict(set) 
     544                for label, value in items: 
     545                    targets[label].add(value) 
     546                     
     547                targets = [(key, list(sorted(vals))) for key, vals in targets.items() \ 
     548                           if len(vals) >= 2] 
     549                self.targets = targets 
     550                 
     551            else: 
     552                var = self.data.domain.classVar 
     553                values = list(var.values) 
     554                if len(values) >= 2: 
     555                    self.targets = [(var.name, values)] 
     556                else: 
     557                    self.targets = [] 
     558        else: 
     559            self.targets = [] 
     560             
     561        self.label_selections = [[] for t in self.targets] 
     562        self.target_widget.set_labels(self.targets) 
     563                 
     564         
     565    def on_label_activated(self, index): 
     566        """ Try to restore a saved selection. 
     567        """ 
     568        selected = self.label_selections[index] 
     569        if not selected: 
     570            selected = self.targets[index][:1] 
     571             
     572        self.target_widget.set_selection(index, selected) 
     573         
     574    def on_target_changed(self, label, values): 
     575        self.target_group = label, values 
     576        # Save the selection 
     577        labels = [l for l, _ in self.targets] 
     578        if label in labels: 
     579            index = labels.index(label) 
     580            self.label_selections[index] = values 
     581             
     582        # replot 
     583        if label and values: 
     584            self.plot() 
     585     
     586    @disable_controls 
    366587    def plot(self): 
    367588        self.values = {} 
    368         if self.data and self.targets: 
     589        target_label, target_values = self.target_group 
     590        if self.data and target_values: 
    369591            self.warning([0, 1]) 
    370             targetClassIndex = min(self.targetClass, len(self.targets) - 1) 
    371             if self.targetMeasurements[targetClassIndex] < 2 and sum(self.targetMeasurements) - self.targetMeasurements[targetClassIndex] < 2: 
     592            target_label, target_values = self.target_group 
     593            if self.genesInColumns: 
     594                target = set([(target_label, value) for value in target_values]) 
     595            else: 
     596                target = set(target_values) 
     597             
     598            ttest = obiExpression.ExpressionSignificance_TTest(self.data, useAttributeLabels=self.genesInColumns) 
     599            ind1, ind2 = ttest.test_indices(target) 
     600             
     601            if len(ind1) < 2 and len(ind2) < 2: 
    372602                self.warning(0, "Insufficient data to compute statistics. More than one measurement per class should be provided") 
    373             targetClass = self.targets[targetClassIndex] 
     603             
    374604            self.progressBarInit() 
    375             tt = obiExpression.ExpressionSignificance_TTest(self.data, useAttributeLabels=self.genesInColumns)(targetClass) 
     605            tt = ttest(target) 
     606             
    376607            self.progressBarSet(25) 
    377             fold = obiExpression.ExpressionSignificance_FoldChange(self.data, useAttributeLabels=self.genesInColumns)(targetClass) 
     608            fold = obiExpression.ExpressionSignificance_FoldChange(self.data, useAttributeLabels=self.genesInColumns)(target) 
    378609            self.progressBarSet(50) 
    379610            self.infoLabel.setText("%i genes on input" % len(fold)) 
    380             import numpy 
     611             
    381612            invalid = set([key for (key, (t, p)), (_, f) in zip(tt, fold) if any(v is numpy.ma.masked for v in [t, p, f]) or f==0.0]) 
    382613            tt = [t for t in tt if t[0] not in invalid] 
     
    430661        else: 
    431662            self.selectionChangedFlag = True 
     663             
     664    def settingsToWidgetCallbacktargets(self, handler, context): 
     665        self.label_selections = list(getattr(context, "label_selections", self.label_selections)) 
     666        self.target_group = getattr(context, "target_group", self.target_group) 
     667         
     668    def settingsFromWidgetCallbacktargets(self, handler, context): 
     669        context.label_selections = list(self.label_selections) 
     670        context.target_group = self.target_group 
    432671         
    433672if __name__ == "__main__": 
Note: See TracChangeset for help on using the changeset viewer.