source: orange-bioinformatics/_bioinformatics/widgets/OWFeatureSelection.py @ 1692:66a285f2e160

Revision 1692:66a285f2e160, 31.7 KB checked in by Lan Zagar <lan.zagar@…>, 22 months ago (diff)

Hopefully fixes #1208 for good.

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
305            # the 'Genes in columns' control
306            if not self.attribute_targets or not self.class_targets:
307                self.genes_in_columns_check.setEnabled(False)
308                self.genes_in_columns = bool(self.attribute_targets)
309
310        self.update_targets_widget()
311
312        if self.data is not None  and \
313                not (self.attribute_targets or self.class_targets):
314            # If both attr. labels and classes are missing, show an error
315            self.error(1, "Cannot compute gene scores! Gene Selection widget "
316                          "requires a data-set with a discrete class variable "
317                          "or attribute labels!")
318            self.data = None
319
320        if self.data:
321            # Load context selection
322            items = [(label, v) for label, values in self.data_labels for v in values]
323
324            self.target_selections = [values[:1] for _, values in self.data_labels]
325            label, values = self.data_labels[0]
326            self.current_target_selection = label, values[:1] # Default selections
327
328            self.openContext("TargetSelection", set(items)) # Load selections from context
329            self.label_selection_widget.set_selection(*self.current_target_selection)
330
331        if not self.data:
332            self.send("Example table with selected genes", None)
333            self.send("Example table with remaining genes", None)
334            self.send("Selected genes", None)
335
336    def set_targets(self, targets):
337        """ Set the target groups for score computation.
338        """
339        self.targets = targets
340        self.update_scores()
341   
342    def compute_scores(self, data, score_func, use_attribute_labels,
343                       target=None, advance=lambda: None):
344        score_func = score_func(data, use_attribute_labels)
345        advance()
346        score = score_func(target=target)
347        score = [(key, val) for key, val in score if val is not ma.masked]
348        return score
349   
350    def compute_null_distribution(self, data, score_func, use_attributes,
351                                  target=None, perm_count=10, advance=lambda: None):
352        score_func = score_func(data, use_attributes)
353        dist = score_func.null_distribution(perm_count, target, advance=advance)
354        return [score for run in dist for k, score in run if score is not ma.masked]
355           
356    @disable_controls
357    def update_scores(self):
358        """ Compute the scores and update the histogram.
359        """
360        self.clear_plot()
361        self.error(0)
362        label, values = self.current_target_selection
363        if not self.data or label is None:
364            return
365        _, score_func, _, two_sample_test = self.score_methods[self.method_index]
366        if two_sample_test:
367            target = self.targets
368            score_target = set(target)
369            ind1, ind2 = score_func(self.data, self.genes_in_columns).test_indices(score_target)
370            if not len(ind1) or not len(ind2):
371                self.error(0, "Target labels most exclude/include at least one value.")
372                return
373           
374        else: # ANOVA should use all labels.
375            target = dict(self.data_labels)[label]
376            if self.genes_in_columns:
377                target = [(label, t) for t in target]
378            score_target = target
379#            indices = score_func(self.data, self.genes_in_columns).test_indices(score_target)
380            # TODO: Check that each label has more than one measurement, raise warning otherwise.
381         
382        pb = OWGUI.ProgressBar(self, 4 + self.permutations_count if self.compute_null else 3)
383        self.scores = dict(self.compute_scores(self.data, score_func,
384                    self.genes_in_columns, score_target, advance=pb.advance))
385        pb.advance()
386        if self.compute_null:
387            self.null_dist = self.compute_null_distribution(self.data,
388                        score_func, self.genes_in_columns, score_target,
389                        self.permutations_count, advance=pb.advance)
390        else:
391            self.null_dist = []
392        pb.advance()
393        self.histogram.type = self.histType[self.score_methods[self.method_index][2]]
394        if self.scores:
395            self.histogram.setValues(self.scores.values())
396            self.histogram.setBoundary(self.histogram.minx if self.histogram.type in ["lowTail", "twoTail"] else self.histogram.maxx,
397                                       self.histogram.maxx if self.histogram.type in ["hiTail", "twoTail"] else self.histogram.minx)
398            if self.compute_null and self.null_dist:
399                nullY, nullX = numpy.histogram(self.null_dist, bins=self.histogram.xData)
400                self.histogram.nullCurve = self.histogram.addCurve("nullCurve",
401                        Qt.black, Qt.black, 6, symbol=QwtSymbol.NoSymbol,
402                        style=QwtPlotCurve.Steps, xData = nullX,
403                        yData = nullY/self.permutations_count)
404               
405                minx = min(min(nullX), self.histogram.minx)
406                maxx = max(max(nullX), self.histogram.maxx)
407                miny = min(min(nullY/self.permutations_count), self.histogram.miny)
408                maxy = max(max(nullY/self.permutations_count), self.histogram.maxy)
409
410                self.histogram.setAxisScale(QwtPlot.xBottom, minx - (0.05 * (maxx - minx)), maxx + (0.05 * (maxx - minx)))
411                self.histogram.setAxisScale(QwtPlot.yLeft, miny - (0.05 * (maxy - miny)), maxy + (0.05 * (maxy - miny)))
412            state = dict(hiTail=(False, True), lowTail=(True, False), twoTail=(True, True))
413            for spin, visible in zip((self.upperBoundarySpin, self.lowerBoundarySpin), state[self.histogram.type]):
414                spin.setVisible(visible)
415           
416            # If this is a two sample test add markers to the left and right
417            # plot indicating which target group is over-expressed in that
418            # part 
419            if self.method_index in [0, 2, 6]:
420                if self.method_index == 0: ## fold change is centered on 1.0
421                    x1, y1 = (self.histogram.minx + 1) / 2 , self.histogram.maxy
422                    x2, y2 = (self.histogram.maxx + 1) / 2 , self.histogram.maxy
423                else:
424                    x1, y1 = (self.histogram.minx) / 2 , self.histogram.maxy
425                    x2, y2 = (self.histogram.maxx) / 2 , self.histogram.maxy
426                if self.genes_in_columns:
427                    label = target[0][0]
428                    target_values = [t[1] for t in target]
429                    values = dict(self.data_labels)[label]
430                else:
431                    target_values = target
432                    values = self.data_labels[0][1]
433                   
434                left = ", ".join(v for v in values if v not in target_values)
435                right = ", ".join(v for v in values if v in target_values)
436                   
437                self.histogram.addMarker(left, x1, y1)
438                self.histogram.addMarker(right, x2, y2)
439            self.warning(0)
440        else:
441            self.warning(0, "No scores obtained.")
442        self.histogram.replot()
443        pb.advance()
444        pb.finish()
445        self.update_data_info_label()
446           
447    def update_data_info_label(self):
448        if self.data:
449            samples, genes = len(self.data), len(self.data.domain.attributes)
450            if self.genes_in_columns:
451                samples, genes = genes, samples
452                target_labels = [t[1] for t in self.targets]
453            else:
454                target_labels = self.targets
455            text = "%i samples, %i genes\n" % (samples, genes)
456            text += "Sample target: '%s'" % (",".join(target_labels))
457        else:
458            text = "No data on input\n"
459        self.dataInfoLabel.setText(text)
460
461    def update_selected_info_label(self, cutOffLower=0, cutOffUpper=0):
462        self.cuts[self.method_index] = (cutOffLower, cutOffUpper)
463        if self.data:
464            scores = np.array(self.scores.values())
465            test = self.score_methods[self.method_index][2]
466            self.selectedInfoLabel.setText("%i selected genes" % len(np.nonzero(test(scores, cutOffLower, cutOffUpper))[0]))
467        else:
468            self.selectedInfoLabel.setText("0 selected genes")
469
470    def select_n_best(self):
471        scores = self.scores.items()
472        scores.sort(lambda a,b:cmp(a[1], b[1]))
473        if not scores:
474            return
475        if self.score_methods[self.method_index][2]==self.oneTailTestHi:
476            scores = scores[-max(self.selectNBest, 1):]
477            self.histogram.setBoundary(scores[0][1], scores[0][1])
478        elif self.score_methods[self.method_index][2]==self.oneTailTestLow:
479            scores = scores[:max(self.selectNBest,1)]
480            self.histogram.setBoundary(scores[-1][1], scores[-1][1])
481        else:
482            scoresHi = scores[-max(min(self.selectNBest, len(scores)/2), 1):]
483            scoresLo = scores[:max(min(self.selectNBest, len(scores)/2), 1)]
484            scores = [(abs(score), 1) for attr, score in scoresHi] + [(abs(score), -1) for attr, score in scoresLo]
485            if self.score_methods[self.method_index][0]=="fold change": ## comparing fold change on a logaritmic scale
486                scores =  [(abs(math.log(max(min(score, 1e300), 1e-300), 2.0)), sign) for score, sign in scores]
487            scores.sort()
488            scores = scores[-max(self.selectNBest, 1):]
489            countHi = len([score for score, sign in scores if sign==1])
490            countLo = len([score for score, sign in scores if sign==-1])
491            cutHi = scoresHi[-countHi][1] if countHi else scoresHi[-1][1] + 1e-7
492            cutLo = scoresLo[countLo-1][1] if countLo else scoresLo[0][1] - 1e-7
493            self.histogram.setBoundary(cutLo, cutHi)
494
495    def update_boundary(self):
496        if self.data != None and self.scores.items():
497            if self.score_methods[self.method_index][2]==self.oneTailTestHi:
498                self.histogram.setBoundary(self.histogram.lowerBoundary, self.histogram.lowerBoundary)
499            elif self.score_methods[self.method_index][2]==self.oneTailTestLow:
500                self.histogram.setBoundary(self.histogram.upperBoundary, self.histogram.upperBoundary)
501            else:
502                self.histogram.setBoundary(self.histogram.lowerBoundary, self.histogram.upperBoundary)
503
504    def select_p_best(self):
505        if not self.null_dist:
506            return
507        nullDist = sorted(self.null_dist)
508        test = self.score_methods[self.method_index][2]
509        count = min(int(len(nullDist)*self.selectPValue), len(nullDist))
510        if test == self.oneTailTestHi:
511            cut = nullDist[-count] if count else nullDist[-1] # + 1e-7
512            self.histogram.setBoundary(cut, cut)
513        elif test == self.oneTailTestLow:
514            cut = nullDist[count - 1] if count else nullDist[0] # - 1e-7
515            self.histogram.setBoundary(cut, cut)
516        elif count:
517            scoresHi = nullDist[-count:]
518            scoresLo = nullDist[:count]
519            scores = [(abs(score), 1) for score in scoresHi] + [(abs(score), -1) for score in scoresLo]
520            if self.score_methods[self.method_index][0] == "fold change": ## fold change is on a logaritmic scale
521                scores =  [(abs(math.log(max(min(score, 1e300), 1e-300), 2.0)), sign) for score, sign in scores]
522            scores = sorted(scores)[-count:]
523            countHi = len([score for score, sign in scores if sign==1])
524            countLo = len([score for score, sign in scores if sign==-1])
525            cutHi = scoresHi[-countHi] if countHi else scoresHi[-1] + 1e-7
526            cutLo = scoresLo[countLo-1] if countLo else scoresLo[0] - 1e-7
527            self.histogram.setBoundary(cutLo, cutHi)
528        else:
529            self.histogram.setBoundary(nullDist[0] - 1e-7, nullDist[-1] + 1e-7)
530           
531
532    def commit_if(self):
533        if self.auto_commit:
534            self.commit()
535        else:
536            self.data_changed_flag = True
537       
538    def commit(self):
539        if not self.data or not self.scores:
540            return
541        test = self.score_methods[self.method_index][2]
542       
543        cutOffUpper = self.histogram.upperBoundary
544        cutOffLower = self.histogram.lowerBoundary
545       
546        scores = np.array(self.scores.items())
547        scores[:, 1] = test(np.array(scores[:, 1], dtype=float), cutOffLower, cutOffUpper)
548        selected = set([key for key, test in scores if test])
549        remaining = set([key for key, test in scores if not test])
550        if self.data and self.genes_in_columns:
551            selected = sorted(selected)
552            if selected:
553                newdata = orange.ExampleTable(orange.Domain(self.data.domain),
554                                        [self.data[int(i)] for i in selected])
555            else:
556                newdata = None
557            if self.add_scores_to_output:
558                score_attr = orange.FloatVariable(self.score_methods[self.method_index][0])
559                mid = orange.newmetaid()
560               
561            if self.add_scores_to_output and newdata is not None:
562                newdata.domain.addmeta(mid, score_attr)
563                for ex, key in zip(newdata, selected):
564                    ex[mid] = self.scores[key]
565                   
566            self.send("Example table with selected genes", newdata)
567           
568            remaining = sorted(remaining)
569            if remaining:
570                newdata = orange.ExampleTable(orange.Domain(self.data.domain), [self.data[int(i)] for i in remaining])
571            else:
572                newdata = None
573           
574            if self.add_scores_to_output and newdata is not None:
575                newdata.domain.addmeta(mid, score_attr)
576                for ex, key in zip(newdata, remaining):
577                    ex[mid] = self.scores[key]
578                   
579            self.send("Example table with remaining genes", newdata)
580           
581        elif self.data and not self.genes_in_columns:
582           
583            selected_attrs = [attr for attr in self.data.domain.attributes \
584                             if attr in selected or \
585                                attr.varType == orange.VarTypes.String]
586            newdomain = orange.Domain(selected_attrs, self.data.domain.classVar)
587            if self.add_scores_to_output:
588                for attr in newdomain.attributes:
589                    attr.attributes[self.score_methods[self.method_index][0]] = str(self.scores[attr])
590            newdomain.addmetas(self.data.domain.getmetas())
591            newdata = orange.ExampleTable(newdomain, self.data)
592           
593            self.send("Example table with selected genes", newdata if selected_attrs else None)
594           
595            remaining_attrs = [attr for attr in self.data.domain.attributes if attr in remaining]
596            newdomain = orange.Domain(remaining_attrs, self.data.domain.classVar)
597            if self.add_scores_to_output:
598                for attr in newdomain.attributes:
599                    attr.attributes[self.score_methods[self.method_index][0]] = str(self.scores[attr])
600            newdomain.addmetas(self.data.domain.getmetas())
601            newdata = orange.ExampleTable(newdomain, self.data)
602           
603            self.send("Example table with remaining genes", newdata if remaining_attrs else None)
604           
605            domain = orange.Domain([orange.StringVariable("label"),
606                                    orange.FloatVariable(self.score_methods[self.method_index][0])],
607                                    False)
608            if selected_attrs:
609                selected_genes = orange.ExampleTable(domain,
610                            [[attr.name, self.scores.get(attr, 0)] for attr in selected_attrs])
611            else:
612                selected_genes = None
613            self.send("Selected genes",  selected_genes)
614           
615        else:
616            self.send("Example table with selected genes", None)
617            self.send("Example table with remaining genes", None)
618            self.send("Selected genes", None)
619        self.data_changed_flag = False
620
621    def on_target_changed(self):
622        label, values = self.label_selection_widget.current_selection()
623
624        if values is None:
625            values = []
626
627        if self.genes_in_columns:
628            targets = [(label, t) for t in values]
629        else:
630            targets = values
631
632        self.targets = targets
633        self.current_target_selection = label, values
634        # Save target label selection
635        labels = [l for l, _ in self.data_labels]
636        if label in labels:
637            label_index = labels.index(label)
638            self.target_selections[label_index] = values
639        self.set_targets(targets)
640
641    def on_label_activated(self, index):
642        selection = self.target_selections[index]
643        if not selection:
644            selection = self.data_labels[index][1][:1]
645        self.label_selection_widget.set_selection(index, selection)
646
647    def on_genes_in_columns_change(self):
648        self.closeContext("TargetSelection")
649        self.update_targets_widget()
650        items = [(label, v) for label, values in self.data_labels \
651                                for v in values]
652        if self.data_labels:
653            label, values = self.data_labels[0] 
654            self.current_target_selection = label, values[:1]
655            self.target_selections = [values[1:] for _, values in self.data_labels]
656            self.openContext("TargetSelection", set(items))
657            self.label_selection_widget.set_selection(*self.current_target_selection)
658       
659    def on_scoring_method_changed(self):
660        two_sample = self.score_methods[self.method_index][3]
661        self.label_selection_widget.values_view.setDisabled(not two_sample)
662       
663    def settingsFromWidgetCallbackTargetSelection(self, handler, context):
664        context.target_selections = self.target_selections
665        context.current_target_selection = self.current_target_selection
666       
667    def settingsToWidgetCallbackTargetSelection(self, handler, context):
668        self.target_selections = getattr(context, "target_selections", self.target_selections)
669        self.current_target_selection = getattr(context, "current_target_selection", self.current_target_selection)
670   
671if __name__=="__main__":
672    import sys
673    app = QApplication(sys.argv)
674#    data = orange.ExampleTable("/home/marko/t2.tab")
675#    data = orange.ExampleTable("../../../doc/datasets/brown-selected")
676    data = orange.ExampleTable(os.path.expanduser("~/Documents/GDS636"))
677    w = OWFeatureSelection()
678    w.show()
679    w.set_data(data)
680#    w.set_data(None)
681#    w.set_data(data)
682    app.exec_()
683    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.