source: orange-bioinformatics/_bioinformatics/widgets/OWFeatureSelection.py @ 1689:f3edbd78dbfd

Revision 1689:f3edbd78dbfd, 31.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 22 months ago (diff)

Check the target selection for a case where there are no labels/values.

Fixes #1208.

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