source: orange-bioinformatics/_bioinformatics/widgets/OWFeatureSelection.py @ 1636:10d234fdadb9

Revision 1636:10d234fdadb9, 31.7 KB checked in by mitar, 2 years ago (diff)

Restructuring because we will not be using namespaces.

Line 
1"""
2<name>Gene Selection</name>
3<description>Gene differential expression scoring and selection.</description>
4<priority>1010</priority>
5<icon>icons/FeatureSelection.png</icon>
6"""
7
8from __future__ import absolute_import, with_statement
9
10from collections import defaultdict
11from functools import wraps
12from operator import add
13
14import numpy as np
15import numpy.ma as ma
16
17import orange
18from Orange.OrangeWidgets import OWGUI
19from Orange.OrangeWidgets.OWGraph import *
20from Orange.OrangeWidgets.OWGraphTools import PolygonCurve
21from Orange.OrangeWidgets.OWHist import OWInteractiveHist
22from Orange.OrangeWidgets.OWToolbars import ZoomSelectToolbar
23from Orange.OrangeWidgets.OWWidget import *
24
25from ..obiDifscale import ExpressionSignificance_AREA, ExpressionSignificance_FCts
26from ..obiExpression import *
27from ..obiGEO import transpose
28
29class ExpressionSignificance_TTest_PValue(ExpressionSignificance_TTest):
30    def __call__(self, *args, **kwargs):
31        return [(key, pval) for key, (t, pval) in \
32                ExpressionSignificance_TTest.__call__(self, *args, **kwargs)]
33   
34class ExpressionSignificance_TTest_T(ExpressionSignificance_TTest):
35    def __call__(self, *args, **kwargs):
36        return [(key, t) for key, (t, pval) in \
37                ExpressionSignificance_TTest.__call__(self, *args, **kwargs)]
38   
39class ExpressionSignificance_ANOVA_PValue(ExpressionSignificance_ANOVA):
40    def __call__(self, *args, **kwargs):
41        return [(key, pval) for key, (t, pval) in \
42                ExpressionSignificance_ANOVA.__call__(self, *args, **kwargs)]
43   
44class ExpressionSignificance_ANOVA_F(ExpressionSignificance_ANOVA):
45    def __call__(self, *args, **kwargs):
46        return [(key, f) for key, (f, pval) in \
47                ExpressionSignificance_ANOVA.__call__(self, *args, **kwargs)]
48   
49class ExpressionSignificance_Log2FoldChange(ExpressionSignificance_FoldChange):
50    def __call__(self, *args, **kwargs):
51        return [(key, math.log(fold, 2.0) if fold > 1e-300 and fold < 1e300 else 0.0) \
52                for key, fold in ExpressionSignificance_FoldChange.__call__(self, *args, **kwargs)]
53   
54class ExpressionSignigicance_MannWhitneyu_U(ExpressionSignificance_MannWhitneyu):
55    def __call__(self, *args, **kwargs):
56        return [(key, u) for key, (u, p_val) in \
57                ExpressionSignificance_MannWhitneyu.__call__(self, *args, **kwargs)]   
58   
59class ScoreHist(OWInteractiveHist):
60    def __init__(self, master, parent=None, type="hiTail"):
61        OWInteractiveHist.__init__(self, parent, type=type)
62        self.master = master
63        self.setAxisTitle(QwtPlot.xBottom, "Score")
64        self.setAxisTitle(QwtPlot.yLeft, "Frequency")
65       
66    def setBoundary(self, low, hi):
67        OWInteractiveHist.setBoundary(self, low, hi)
68        self.master.update_selected_info_label(low, hi)
69        self.master.commit_if()
70           
71def disable_controls(method):
72    """ Disable the widget's control area during the duration of this call.
73    """
74    @wraps(method)
75    def f(self, *args, **kwargs):
76        self.controlArea.setDisabled(True)
77        qApp.processEvents()
78        try:
79            return method(self, *args, **kwargs)
80        finally:
81            self.controlArea.setDisabled(False)
82    return f
83
84from Orange.orng.orngDataCaching import data_hints
85
86from .OWGenotypeDistances import SetContextHandler
87from .OWVulcanoPlot import LabelSelectionWidget
88
89class OWFeatureSelection(OWWidget):
90    settingsList = ["method_index", "dataLabelIndex", "compute_null",
91                    "permutations_count", "selectPValue", "auto_commit"]
92    contextHandlers={"Data": DomainContextHandler("Data", ["genes_in_columns"]),
93                     "TargetSelection": SetContextHandler("TargetSelection",
94                                                          findImperfect=False)}
95   
96    def __init__(self, parent=None, signalManager=None, name="Gene selection"):
97        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True, showSaveGraph=True)
98        self.inputs = [("Examples", ExampleTable, self.set_data)]
99        self.outputs = [("Example table with selected genes", ExampleTable), ("Example table with remaining genes", ExampleTable), ("Selected genes", ExampleTable)]
100
101        self.method_index = 0
102#        self.dataLabelIndex = 0
103        self.genes_in_columns = False
104        self.compute_null = False
105        self.permutations_count = 10
106        self.auto_commit = False
107        self.selectNBest = 20
108        self.selectPValue = 0.01
109        self.data_changed_flag = False
110        self.add_scores_to_output = True
111
112        self.oneTailTestHi = oneTailTestHi = lambda array, low, hi: array >= hi
113        self.oneTailTestLow = oneTailTestLow = lambda array, low, hi: array <= low
114        self.twoTailTest = twoTailTest = lambda array, low, hi: (array >= hi) | (array <= low)
115        self.middleTest = middleTest = lambda array, low, hi: (array <= hi) | (array >= low)
116       
117        self.histType = {oneTailTestHi:"hiTail", oneTailTestLow:"lowTail", twoTailTest:"twoTail", middleTest:"middle"}
118
119        # [(name, func, tail test, two sample test), ...]
120        self.score_methods = [("fold change", ExpressionSignificance_FoldChange, twoTailTest, True),
121                             ("log2 fold change", ExpressionSignificance_Log2FoldChange, twoTailTest, True),
122                             ("t-test", ExpressionSignificance_TTest_T, twoTailTest, True),
123                             ("t-test p-value", ExpressionSignificance_TTest_PValue, oneTailTestLow, True),
124                             ("anova", ExpressionSignificance_ANOVA_F, oneTailTestHi, False),
125                             ("anova p-value", ExpressionSignificance_ANOVA_PValue, oneTailTestLow, False),
126                             ("signal to noise ratio", ExpressionSignificance_SignalToNoise, twoTailTest, True),
127                             ("info gain", ExpressionSignificance_Info, oneTailTestHi, True),
128                             ("chi-square", ExpressionSignificance_ChiSquare, oneTailTestHi, True),
129                             ("mann-whitney", ExpressionSignigicance_MannWhitneyu_U, oneTailTestLow, True),
130                             ("AREA (timeseries)", ExpressionSignificance_AREA, oneTailTestHi, False),
131                             ("FC (timeseries)", ExpressionSignificance_FCts, oneTailTestHi, False)]
132
133        boxHistogram = OWGUI.widgetBox(self.mainArea)
134        self.histogram = ScoreHist(self, boxHistogram)
135        boxHistogram.layout().addWidget(self.histogram)
136        self.histogram.show()
137       
138        box = OWGUI.widgetBox(self.controlArea, "Info")
139        self.dataInfoLabel = OWGUI.widgetLabel(box, "\n\n")
140        self.dataInfoLabel.setWordWrap(True)
141        self.selectedInfoLabel = OWGUI.widgetLabel(box, "")
142
143        box1 = OWGUI.widgetBox(self.controlArea, "Scoring Method")
144        self.testRadioBox = OWGUI.comboBox(box1, self, "method_index",
145                                    items=[sm[0] for sm in self.score_methods],
146                                    callback=[self.on_scoring_method_changed, self.update_scores])
147       
148        box = OWGUI.widgetBox(self.controlArea, "Target Labels")
149        self.label_selection_widget = LabelSelectionWidget(self)
150        self.label_selection_widget.setMaximumHeight(150)
151        box.layout().addWidget(self.label_selection_widget)
152        self.connect(self.label_selection_widget,
153                     SIGNAL("selection_changed()"),
154                     self.on_target_changed)
155       
156        self.connect(self.label_selection_widget,
157                     SIGNAL("label_activated(int)"),
158                     self.on_label_activated)
159       
160        self.genes_in_columns_check = OWGUI.checkBox(box, self, "genes_in_columns",
161                                                  "Genes in columns",
162                                                  callback=self.on_genes_in_columns_change)
163   
164#        ZoomSelectToolbar(self, self.controlArea, self.histogram,
165#                          buttons=[ZoomSelectToolbar.IconSelect,
166#                                   ZoomSelectToolbar.IconZoom,
167#                                   ZoomSelectToolbar.IconPan])
168       
169        box = OWGUI.widgetBox(self.controlArea, "Selection")
170        box.layout().setSpacing(0)
171        callback = self.update_boundary
172        self.upperBoundarySpin = OWGUI.doubleSpin(box, self, "histogram.upperBoundary",
173                                                  min=-1e6, max=1e6, step= 1e-6,
174                                                  label="Upper threshold:", 
175                                                  callback=callback, 
176                                                  callbackOnReturn=True)
177       
178        self.lowerBoundarySpin = OWGUI.doubleSpin(box, self, "histogram.lowerBoundary", 
179                                                  min=-1e6, max=1e6, step= 1e-6, 
180                                                  label="Lower threshold:", 
181                                                  callback=callback, 
182                                                  callbackOnReturn=True)
183       
184        check = OWGUI.checkBox(box, self, "compute_null", "Compute null distribution",
185                               callback=self.update_scores)
186
187        check.disables.append(OWGUI.spin(box, self, "permutations_count", min=1, max=10, 
188                                         label="Permutations:", callback=self.update_scores, 
189                                         callbackOnReturn=True))
190
191        box1 = OWGUI.widgetBox(box, orientation='horizontal')
192        check.disables.append(OWGUI.doubleSpin(box1, self, "selectPValue", 
193                                               min=2e-7, max=1.0, step=1e-7, 
194                                               label="P-value:"))
195        check.disables.append(OWGUI.button(box1, self, "Select", callback=self.select_p_best))
196        check.makeConsistent()
197
198        box1 = OWGUI.widgetBox(box, orientation='horizontal')
199        OWGUI.spin(box1, self, "selectNBest", 0, 10000, step=1, label="Best Ranked:")
200        OWGUI.button(box1, self, "Select", callback=self.select_n_best)
201
202        box = OWGUI.widgetBox(self.controlArea, "Output")
203        b = OWGUI.button(box, self, "&Commit", callback=self.commit)
204        cb = OWGUI.checkBox(box, self, "auto_commit", "Commit on change")
205        OWGUI.setStopper(self, b, cb, "data_changed_flag", self.commit)
206        OWGUI.checkBox(box, self, "add_scores_to_output", "Add gene scores to output",
207                       callback=self.commit_if) 
208       
209        OWGUI.rubber(self.controlArea)
210
211        self.connect(self.graphButton, SIGNAL("clicked()"), self.histogram.saveToFile)
212       
213        self.loadSettings()
214
215        self.data = None
216        self.discData = None
217        self.scoreCache = {}
218        self.nullDistCache = {}
219        self.cuts = {}
220        self.discretizer = orange.EquiNDiscretization(numberOfIntervals=5)
221        self.null_dist = []
222        self.targets = []
223        self.scores = {}
224        self.genes_in_columns = True
225        self.target_selections = None
226       
227        self.on_scoring_method_changed()
228       
229        self.resize(800, 600)
230       
231    def clear(self):
232        """ Clear widget.
233        """
234        self.scoreCache = {}
235        self.nullDistCache = {}
236        self.discData = None
237        self.data = None
238        self.attribute_targets = []
239        self.class_targets = []
240        self.label_selection_widget.clear()
241        self.clear_plot()
242       
243    def clear_plot(self):
244        """ Clear the histogram plot.
245        """
246        self.histogram.removeDrawingCurves()
247        self.histogram.clear()
248        self.histogram.replot()
249       
250    def init_from_data(self, data):
251        """ Init widget state from the data.
252        """
253        if data:
254            items = [attr.attributes.items() for attr in data.domain.attributes]
255            items = reduce(add, items, [])
256           
257            targets = defaultdict(set)
258            for label, value in items:
259                targets[label].add(value)
260               
261            targets = [(key, sorted(vals)) for key, vals in targets.items() \
262                       if len(vals) >= 2]
263            self.attribute_targets = targets
264           
265            class_var = data.domain.class_var
266            if class_var and isinstance(class_var, orange.EnumVariable):
267                targets = [(class_var.name,
268                            list(class_var.values))]
269                self.class_targets = targets
270            else:
271                self.class_targets = []
272           
273    def update_targets_widget(self):
274        """ Update the contents of the targets widget.
275        """
276        if self.data:
277            if self.genes_in_columns:
278                targets = self.attribute_targets
279            elif self.data.domain.classVar:
280                targets = self.class_targets
281            else:
282                targets = []
283        else:
284            targets = []
285           
286        self.label_selection_widget.clear()
287        self.label_selection_widget.set_labels(targets)
288        self.data_labels = targets
289       
290    def set_data(self, data):
291        self.closeContext("Data")
292        self.closeContext("TargetSelection")
293        self.error([0, 1])
294        self.warning(0)
295        self.clear()
296        self.genes_in_columns_check.setEnabled(True)
297        self.data = data
298        self.init_from_data(data)
299       
300        if self.data:
301            self.genes_in_columns = not data_hints.get_hint(data, "genesinrows", False)
302            self.openContext("Data", data)
303           
304            # If only attr. labels or only class values then disable the 'Genes in columns' control
305            if not self.attribute_targets or not self.class_targets:
306                self.genes_in_columns_check.setEnabled(False)
307                self.genes_in_columns = bool(self.attribute_targets)
308       
309        self.update_targets_widget()
310       
311        # If both attr. labels and classes are missing, show an error
312        if not (self.attribute_targets or self.class_targets):
313#        if self.data and not self.data_labels:
314            self.error(1, "Cannot compute gene scores! Gene Selection widget requires a data-set with a discrete class variable or attribute labels!")
315            self.data = None
316       
317        if self.data:
318            # Load context selection
319            items = [(label, v) for label, values in self.data_labels for v in values]
320           
321            self.target_selections = [values[:1] for _, values in self.data_labels]
322            label, values = self.data_labels[0]
323            self.current_target_selection = label, values[:1] # Default selections
324           
325            self.openContext("TargetSelection", set(items)) # Load selections from context
326            self.label_selection_widget.set_selection(*self.current_target_selection)
327
328        if not self.data:
329            self.send("Example table with selected genes", None)
330            self.send("Example table with remaining genes", None)
331            self.send("Selected genes", None)
332           
333    def set_targets(self, targets):
334        """ Set the target groups for score computation.
335        """
336        self.targets = targets
337        self.update_scores()
338   
339    def compute_scores(self, data, score_func, use_attribute_labels,
340                       target=None, advance=lambda: None):
341        score_func = score_func(data, use_attribute_labels)
342        advance()
343        score = score_func(target=target)
344        score = [(key, val) for key, val in score if val is not ma.masked]
345        return score
346   
347    def compute_null_distribution(self, data, score_func, use_attributes,
348                                  target=None, perm_count=10, advance=lambda: None):
349        score_func = score_func(data, use_attributes)
350        dist = score_func.null_distribution(perm_count, target, advance=advance)
351        return [score for run in dist for k, score in run if score is not ma.masked]
352           
353    @disable_controls
354    def update_scores(self):
355        """ Compute the scores and update the histogram.
356        """
357        self.clear_plot()
358        self.error(0)
359        if not self.data:
360            return
361        _, score_func, _, two_sample_test = self.score_methods[self.method_index]
362       
363        target_label, target_values = self.current_target_selection
364        if two_sample_test:
365            target = self.targets
366            score_target = set(target)
367            ind1, ind2 = score_func(self.data, self.genes_in_columns).test_indices(score_target)
368            if not len(ind1) or not len(ind2):
369                self.error(0, "Target labels most exclude/include at least one value.")
370                return
371           
372        else: # ANOVA should use all labels.
373            label, values = self.current_target_selection
374            target = dict(self.data_labels)[label]
375            if self.genes_in_columns:
376                target = [(label, t) for t in target]
377            score_target = target
378#            indices = score_func(self.data, self.genes_in_columns).test_indices(score_target)
379            # TODO: Check that each label has more than one measurement, raise warning otherwise.
380         
381        pb = OWGUI.ProgressBar(self, 4 + self.permutations_count if self.compute_null else 3)
382        self.scores = dict(self.compute_scores(self.data, score_func,
383                    self.genes_in_columns, score_target, advance=pb.advance))
384        pb.advance()
385        if self.compute_null:
386            self.null_dist = self.compute_null_distribution(self.data,
387                        score_func, self.genes_in_columns, score_target,
388                        self.permutations_count, advance=pb.advance)
389        else:
390            self.null_dist = []
391        pb.advance()
392        self.histogram.type = self.histType[self.score_methods[self.method_index][2]]
393        if self.scores:
394            self.histogram.setValues(self.scores.values())
395            self.histogram.setBoundary(self.histogram.minx if self.histogram.type in ["lowTail", "twoTail"] else self.histogram.maxx,
396                                       self.histogram.maxx if self.histogram.type in ["hiTail", "twoTail"] else self.histogram.minx)
397            if self.compute_null and self.null_dist:
398                nullY, nullX = numpy.histogram(self.null_dist, bins=self.histogram.xData)
399                self.histogram.nullCurve = self.histogram.addCurve("nullCurve",
400                        Qt.black, Qt.black, 6, symbol=QwtSymbol.NoSymbol,
401                        style=QwtPlotCurve.Steps, xData = nullX,
402                        yData = nullY/self.permutations_count)
403               
404                minx = min(min(nullX), self.histogram.minx)
405                maxx = max(max(nullX), self.histogram.maxx)
406                miny = min(min(nullY/self.permutations_count), self.histogram.miny)
407                maxy = max(max(nullY/self.permutations_count), self.histogram.maxy)
408
409                self.histogram.setAxisScale(QwtPlot.xBottom, minx - (0.05 * (maxx - minx)), maxx + (0.05 * (maxx - minx)))
410                self.histogram.setAxisScale(QwtPlot.yLeft, miny - (0.05 * (maxy - miny)), maxy + (0.05 * (maxy - miny)))
411            state = dict(hiTail=(False, True), lowTail=(True, False), twoTail=(True, True))
412            for spin, visible in zip((self.upperBoundarySpin, self.lowerBoundarySpin), state[self.histogram.type]):
413                spin.setVisible(visible)
414           
415            # If this is a two sample test add markers to the left and right
416            # plot indicating which target group is over-expressed in that
417            # part 
418            if self.method_index in [0, 2, 6]:
419                if self.method_index == 0: ## fold change is centered on 1.0
420                    x1, y1 = (self.histogram.minx + 1) / 2 , self.histogram.maxy
421                    x2, y2 = (self.histogram.maxx + 1) / 2 , self.histogram.maxy
422                else:
423                    x1, y1 = (self.histogram.minx) / 2 , self.histogram.maxy
424                    x2, y2 = (self.histogram.maxx) / 2 , self.histogram.maxy
425                if self.genes_in_columns:
426                    label = target[0][0]
427                    target_values = [t[1] for t in target]
428                    values = dict(self.data_labels)[label]
429                else:
430                    target_values = target
431                    values = self.data_labels[0][1]
432                   
433                left = ", ".join(v for v in values if v not in target_values)
434                right = ", ".join(v for v in values if v in target_values)
435                   
436                self.histogram.addMarker(left, x1, y1)
437                self.histogram.addMarker(right, x2, y2)
438            self.warning(0)
439        else:
440            self.warning(0, "No scores obtained.")
441        self.histogram.replot()
442        pb.advance()
443        pb.finish()
444        self.update_data_info_label()
445           
446    def update_data_info_label(self):
447        if self.data:
448            samples, genes = len(self.data), len(self.data.domain.attributes)
449            if self.genes_in_columns:
450                samples, genes = genes, samples
451                target_labels = [t[1] for t in self.targets]
452            else:
453                target_labels = self.targets
454            text = "%i samples, %i genes\n" % (samples, genes)
455            text += "Sample target: '%s'" % (",".join(target_labels))
456        else:
457            text = "No data on input\n"
458        self.dataInfoLabel.setText(text)
459
460    def update_selected_info_label(self, cutOffLower=0, cutOffUpper=0):
461        self.cuts[self.method_index] = (cutOffLower, cutOffUpper)
462        if self.data:
463            scores = np.array(self.scores.values())
464            test = self.score_methods[self.method_index][2]
465            self.selectedInfoLabel.setText("%i selected genes" % len(np.nonzero(test(scores, cutOffLower, cutOffUpper))[0]))
466        else:
467            self.selectedInfoLabel.setText("0 selected genes")
468
469    def select_n_best(self):
470        scores = self.scores.items()
471        scores.sort(lambda a,b:cmp(a[1], b[1]))
472        if not scores:
473            return
474        if self.score_methods[self.method_index][2]==self.oneTailTestHi:
475            scores = scores[-max(self.selectNBest, 1):]
476            self.histogram.setBoundary(scores[0][1], scores[0][1])
477        elif self.score_methods[self.method_index][2]==self.oneTailTestLow:
478            scores = scores[:max(self.selectNBest,1)]
479            self.histogram.setBoundary(scores[-1][1], scores[-1][1])
480        else:
481            scoresHi = scores[-max(min(self.selectNBest, len(scores)/2), 1):]
482            scoresLo = scores[:max(min(self.selectNBest, len(scores)/2), 1)]
483            scores = [(abs(score), 1) for attr, score in scoresHi] + [(abs(score), -1) for attr, score in scoresLo]
484            if self.score_methods[self.method_index][0]=="fold change": ## comparing fold change on a logaritmic scale
485                scores =  [(abs(math.log(max(min(score, 1e300), 1e-300), 2.0)), sign) for score, sign in scores]
486            scores.sort()
487            scores = scores[-max(self.selectNBest, 1):]
488            countHi = len([score for score, sign in scores if sign==1])
489            countLo = len([score for score, sign in scores if sign==-1])
490            cutHi = scoresHi[-countHi][1] if countHi else scoresHi[-1][1] + 1e-7
491            cutLo = scoresLo[countLo-1][1] if countLo else scoresLo[0][1] - 1e-7
492            self.histogram.setBoundary(cutLo, cutHi)
493
494    def update_boundary(self):
495        if self.data != None and self.scores.items():
496            if self.score_methods[self.method_index][2]==self.oneTailTestHi:
497                self.histogram.setBoundary(self.histogram.lowerBoundary, self.histogram.lowerBoundary)
498            elif self.score_methods[self.method_index][2]==self.oneTailTestLow:
499                self.histogram.setBoundary(self.histogram.upperBoundary, self.histogram.upperBoundary)
500            else:
501                self.histogram.setBoundary(self.histogram.lowerBoundary, self.histogram.upperBoundary)
502
503    def select_p_best(self):
504        if not self.null_dist:
505            return
506        nullDist = sorted(self.null_dist)
507        test = self.score_methods[self.method_index][2]
508        count = min(int(len(nullDist)*self.selectPValue), len(nullDist))
509        if test == self.oneTailTestHi:
510            cut = nullDist[-count] if count else nullDist[-1] # + 1e-7
511            self.histogram.setBoundary(cut, cut)
512        elif test == self.oneTailTestLow:
513            cut = nullDist[count - 1] if count else nullDist[0] # - 1e-7
514            self.histogram.setBoundary(cut, cut)
515        elif count:
516            scoresHi = nullDist[-count:]
517            scoresLo = nullDist[:count]
518            scores = [(abs(score), 1) for score in scoresHi] + [(abs(score), -1) for score in scoresLo]
519            if self.score_methods[self.method_index][0] == "fold change": ## fold change is on a logaritmic scale
520                scores =  [(abs(math.log(max(min(score, 1e300), 1e-300), 2.0)), sign) for score, sign in scores]
521            scores = sorted(scores)[-count:]
522            countHi = len([score for score, sign in scores if sign==1])
523            countLo = len([score for score, sign in scores if sign==-1])
524            cutHi = scoresHi[-countHi] if countHi else scoresHi[-1] + 1e-7
525            cutLo = scoresLo[countLo-1] if countLo else scoresLo[0] - 1e-7
526            self.histogram.setBoundary(cutLo, cutHi)
527        else:
528            self.histogram.setBoundary(nullDist[0] - 1e-7, nullDist[-1] + 1e-7)
529           
530
531    def commit_if(self):
532        if self.auto_commit:
533            self.commit()
534        else:
535            self.data_changed_flag = True
536       
537    def commit(self):
538        if not self.data or not self.scores:
539            return
540        test = self.score_methods[self.method_index][2]
541       
542        cutOffUpper = self.histogram.upperBoundary
543        cutOffLower = self.histogram.lowerBoundary
544       
545        scores = np.array(self.scores.items())
546        scores[:, 1] = test(np.array(scores[:, 1], dtype=float), cutOffLower, cutOffUpper)
547        selected = set([key for key, test in scores if test])
548        remaining = set([key for key, test in scores if not test])
549        if self.data and self.genes_in_columns:
550            selected = sorted(selected)
551            if selected:
552                newdata = orange.ExampleTable(orange.Domain(self.data.domain),
553                                        [self.data[int(i)] for i in selected])
554            else:
555                newdata = None
556            if self.add_scores_to_output:
557                score_attr = orange.FloatVariable(self.score_methods[self.method_index][0])
558                mid = orange.newmetaid()
559               
560            if self.add_scores_to_output and newdata is not None:
561                newdata.domain.addmeta(mid, score_attr)
562                for ex, key in zip(newdata, selected):
563                    ex[mid] = self.scores[key]
564                   
565            self.send("Example table with selected genes", newdata)
566           
567            remaining = sorted(remaining)
568            if remaining:
569                newdata = orange.ExampleTable(orange.Domain(self.data.domain), [self.data[int(i)] for i in remaining])
570            else:
571                newdata = None
572           
573            if self.add_scores_to_output and newdata is not None:
574                newdata.domain.addmeta(mid, score_attr)
575                for ex, key in zip(newdata, remaining):
576                    ex[mid] = self.scores[key]
577                   
578            self.send("Example table with remaining genes", newdata)
579           
580        elif self.data and not self.genes_in_columns:
581           
582            selected_attrs = [attr for attr in self.data.domain.attributes \
583                             if attr in selected or \
584                                attr.varType == orange.VarTypes.String]
585            newdomain = orange.Domain(selected_attrs, self.data.domain.classVar)
586            if self.add_scores_to_output:
587                for attr in newdomain.attributes:
588                    attr.attributes[self.score_methods[self.method_index][0]] = str(self.scores[attr])
589            newdomain.addmetas(self.data.domain.getmetas())
590            newdata = orange.ExampleTable(newdomain, self.data)
591           
592            self.send("Example table with selected genes", newdata if selected_attrs else None)
593           
594            remaining_attrs = [attr for attr in self.data.domain.attributes if attr in remaining]
595            newdomain = orange.Domain(remaining_attrs, self.data.domain.classVar)
596            if self.add_scores_to_output:
597                for attr in newdomain.attributes:
598                    attr.attributes[self.score_methods[self.method_index][0]] = str(self.scores[attr])
599            newdomain.addmetas(self.data.domain.getmetas())
600            newdata = orange.ExampleTable(newdomain, self.data)
601           
602            self.send("Example table with remaining genes", newdata if remaining_attrs else None)
603           
604            domain = orange.Domain([orange.StringVariable("label"),
605                                    orange.FloatVariable(self.score_methods[self.method_index][0])],
606                                    False)
607            if selected_attrs:
608                selected_genes = orange.ExampleTable(domain,
609                            [[attr.name, self.scores.get(attr, 0)] for attr in selected_attrs])
610            else:
611                selected_genes = None
612            self.send("Selected genes",  selected_genes)
613           
614        else:
615            self.send("Example table with selected genes", None)
616            self.send("Example table with remaining genes", None)
617            self.send("Selected genes", None)
618        self.data_changed_flag = False
619       
620    def on_target_changed(self):
621        label, values  = self.label_selection_widget.current_selection()
622        if self.genes_in_columns:
623            targets = [(label, t) for t in values]
624        else:
625            targets = values
626        self.targets = targets
627        self.current_target_selection = label, values
628        # Save target label selection
629        labels = [l for l, _ in self.data_labels]
630        if label in labels:
631            label_index = labels.index(label)
632            self.target_selections[label_index] = values
633        self.set_targets(targets) 
634   
635    def on_label_activated(self, index):
636        selection = self.target_selections[index]
637        if not selection:
638            selection = self.data_labels[index][1][:1]
639        self.label_selection_widget.set_selection(index, selection)
640
641    def on_genes_in_columns_change(self):
642        self.closeContext("TargetSelection")
643        self.update_targets_widget()
644        items = [(label, v) for label, values in self.data_labels \
645                                for v in values]
646        if self.data_labels:
647            label, values = self.data_labels[0] 
648            self.current_target_selection = label, values[:1]
649            self.target_selections = [values[1:] for _, values in self.data_labels]
650            self.openContext("TargetSelection", set(items))
651            self.label_selection_widget.set_selection(*self.current_target_selection)
652       
653    def on_scoring_method_changed(self):
654        two_sample = self.score_methods[self.method_index][3]
655        self.label_selection_widget.values_view.setDisabled(not two_sample)
656       
657    def settingsFromWidgetCallbackTargetSelection(self, handler, context):
658        context.target_selections = self.target_selections
659        context.current_target_selection = self.current_target_selection
660       
661    def settingsToWidgetCallbackTargetSelection(self, handler, context):
662        self.target_selections = getattr(context, "target_selections", self.target_selections)
663        self.current_target_selection = getattr(context, "current_target_selection", self.current_target_selection)
664   
665if __name__=="__main__":
666    import sys
667    app = QApplication(sys.argv)
668#    data = orange.ExampleTable("/home/marko/t2.tab")
669#    data = orange.ExampleTable("../../../doc/datasets/brown-selected")
670    data = orange.ExampleTable(os.path.expanduser("~/Documents/GDS636"))
671    w = OWFeatureSelection()
672    w.show()
673    w.set_data(data)
674#    w.set_data(None)
675#    w.set_data(data)
676    app.exec_()
677    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.