source: orange-bioinformatics/orangecontrib/bio/widgets/OWFeatureSelection.py @ 1874:b3e32cc5cf6f

Revision 1874:b3e32cc5cf6f, 32.1 KB checked in by Ales Erjavec <ales.erjavec@…>, 6 months ago (diff)

Added new style widget meta descriptions.

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