source: orange-bioinformatics/orangecontrib/bio/widgets/OWFeatureSelection.py @ 1873:0810c5708cc5

Revision 1873:0810c5708cc5, 31.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 6 months ago (diff)

Moved '_bioinformatics' into orangecontrib namespace.

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