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.

RevLine 
[203]1"""
[1849]2<name>Differential expression</name>
[1051]3<description>Gene differential expression scoring and selection.</description>
[1052]4<priority>1010</priority>
[1726]5<icon>icons/GeneSelection.svg</icon>
[203]6"""
[929]7
[1632]8from __future__ import absolute_import, with_statement
[203]9
[830]10from collections import defaultdict
[1168]11from functools import wraps
[1407]12from operator import add
[1632]13
[929]14import numpy as np
15import numpy.ma as ma
[203]16
[1632]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
[1697]29
[1874]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
[929]43class ExpressionSignificance_TTest_PValue(ExpressionSignificance_TTest):
44    def __call__(self, *args, **kwargs):
[1407]45        return [(key, pval) for key, (t, pval) in \
46                ExpressionSignificance_TTest.__call__(self, *args, **kwargs)]
[1697]47
48
[929]49class ExpressionSignificance_TTest_T(ExpressionSignificance_TTest):
50    def __call__(self, *args, **kwargs):
[1407]51        return [(key, t) for key, (t, pval) in \
52                ExpressionSignificance_TTest.__call__(self, *args, **kwargs)]
[1697]53
54
[929]55class ExpressionSignificance_ANOVA_PValue(ExpressionSignificance_ANOVA):
56    def __call__(self, *args, **kwargs):
[1407]57        return [(key, pval) for key, (t, pval) in \
58                ExpressionSignificance_ANOVA.__call__(self, *args, **kwargs)]
[1697]59
60
[929]61class ExpressionSignificance_ANOVA_F(ExpressionSignificance_ANOVA):
62    def __call__(self, *args, **kwargs):
[1407]63        return [(key, f) for key, (f, pval) in \
64                ExpressionSignificance_ANOVA.__call__(self, *args, **kwargs)]
[1697]65
66
[929]67class ExpressionSignificance_Log2FoldChange(ExpressionSignificance_FoldChange):
68    def __call__(self, *args, **kwargs):
[1407]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)]
[1697]71
72
[1066]73class ExpressionSignigicance_MannWhitneyu_U(ExpressionSignificance_MannWhitneyu):
74    def __call__(self, *args, **kwargs):
[1407]75        return [(key, u) for key, (u, p_val) in \
[1697]76                ExpressionSignificance_MannWhitneyu.__call__(self, *args, **kwargs)]
77
78
[204]79class ScoreHist(OWInteractiveHist):
80    def __init__(self, master, parent=None, type="hiTail"):
81        OWInteractiveHist.__init__(self, parent, type=type)
[203]82        self.master = master
83        self.setAxisTitle(QwtPlot.xBottom, "Score")
84        self.setAxisTitle(QwtPlot.yLeft, "Frequency")
[1697]85        self.activateSelection()
86
[204]87    def setBoundary(self, low, hi):
88        OWInteractiveHist.setBoundary(self, low, hi)
[1407]89        self.master.update_selected_info_label(low, hi)
90        self.master.commit_if()
[1697]91
92
[1360]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
[1407]105
[1632]106from Orange.orng.orngDataCaching import data_hints
[1633]107
[1632]108from .OWGenotypeDistances import SetContextHandler
109from .OWVulcanoPlot import LabelSelectionWidget
[1407]110
[203]111class OWFeatureSelection(OWWidget):
[1407]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   
[830]118    def __init__(self, parent=None, signalManager=None, name="Gene selection"):
[407]119        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True, showSaveGraph=True)
[1407]120        self.inputs = [("Examples", ExampleTable, self.set_data)]
[951]121        self.outputs = [("Example table with selected genes", ExampleTable), ("Example table with remaining genes", ExampleTable), ("Selected genes", ExampleTable)]
[203]122
[1407]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
[204]129        self.selectNBest = 20
[758]130        self.selectPValue = 0.01
[1407]131        self.data_changed_flag = False
132        self.add_scores_to_output = True
[203]133
[929]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       
[204]139        self.histType = {oneTailTestHi:"hiTail", oneTailTestLow:"lowTail", twoTailTest:"twoTail", middleTest:"middle"}
[929]140
[1407]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),
[1448]151                             ("mann-whitney", ExpressionSignigicance_MannWhitneyu_U, oneTailTestLow, True),
152                             ("AREA (timeseries)", ExpressionSignificance_AREA, oneTailTestHi, False),
153                             ("FC (timeseries)", ExpressionSignificance_FCts, oneTailTestHi, False)]
[203]154
[204]155        boxHistogram = OWGUI.widgetBox(self.mainArea)
156        self.histogram = ScoreHist(self, boxHistogram)
157        boxHistogram.layout().addWidget(self.histogram)
[203]158        self.histogram.show()
159       
[1360]160        box = OWGUI.widgetBox(self.controlArea, "Info")
[203]161        self.dataInfoLabel = OWGUI.widgetLabel(box, "\n\n")
[1407]162        self.dataInfoLabel.setWordWrap(True)
[203]163        self.selectedInfoLabel = OWGUI.widgetLabel(box, "")
[828]164
165        box1 = OWGUI.widgetBox(self.controlArea, "Scoring Method")
[1407]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])
[1360]169       
[1407]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)
[830]185   
[1407]186#        ZoomSelectToolbar(self, self.controlArea, self.histogram,
187#                          buttons=[ZoomSelectToolbar.IconSelect,
188#                                   ZoomSelectToolbar.IconZoom,
189#                                   ZoomSelectToolbar.IconPan])
[758]190       
[1360]191        box = OWGUI.widgetBox(self.controlArea, "Selection")
[1226]192        box.layout().setSpacing(0)
[1407]193        callback = self.update_boundary
[1360]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       
[1407]206        check = OWGUI.checkBox(box, self, "compute_null", "Compute null distribution",
207                               callback=self.update_scores)
[828]208
[1407]209        check.disables.append(OWGUI.spin(box, self, "permutations_count", min=1, max=10, 
210                                         label="Permutations:", callback=self.update_scores, 
[1360]211                                         callbackOnReturn=True))
[828]212
213        box1 = OWGUI.widgetBox(box, orientation='horizontal')
[1360]214        check.disables.append(OWGUI.doubleSpin(box1, self, "selectPValue", 
215                                               min=2e-7, max=1.0, step=1e-7, 
216                                               label="P-value:"))
[1407]217        check.disables.append(OWGUI.button(box1, self, "Select", callback=self.select_p_best))
[758]218        check.makeConsistent()
[828]219
220        box1 = OWGUI.widgetBox(box, orientation='horizontal')
221        OWGUI.spin(box1, self, "selectNBest", 0, 10000, step=1, label="Best Ranked:")
[1407]222        OWGUI.button(box1, self, "Select", callback=self.select_n_best)
[828]223
[951]224        box = OWGUI.widgetBox(self.controlArea, "Output")
[1407]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) 
[952]230       
[203]231        OWGUI.rubber(self.controlArea)
[407]232
233        self.connect(self.graphButton, SIGNAL("clicked()"), self.histogram.saveToFile)
[203]234       
235        self.loadSettings()
236
237        self.data = None
238        self.discData = None
239        self.scoreCache = {}
[758]240        self.nullDistCache = {}
[204]241        self.cuts = {}
[203]242        self.discretizer = orange.EquiNDiscretization(numberOfIntervals=5)
[1407]243        self.null_dist = []
[929]244        self.targets = []
[767]245        self.scores = {}
[1407]246        self.genes_in_columns = True
247        self.target_selections = None
248       
249        self.on_scoring_method_changed()
250       
[929]251        self.resize(800, 600)
[203]252       
[1407]253    def clear(self):
254        """ Clear widget.
255        """
[203]256        self.scoreCache = {}
[758]257        self.nullDistCache = {}
[203]258        self.discData = None
[1407]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
[1689]311
[1407]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)
[203]319        self.data = data
[1407]320        self.init_from_data(data)
[1689]321
[830]322        if self.data:
[1407]323            self.genes_in_columns = not data_hints.get_hint(data, "genesinrows", False)
324            self.openContext("Data", data)
[1689]325
326            # If only attr. labels or only class values then disable
327            # the 'Genes in columns' control
[1407]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)
[1689]331
[1407]332        self.update_targets_widget()
[1689]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
[1849]337            self.error(1, "Cannot compute gene scores! Differential expression widget "
[1689]338                          "requires a data-set with a discrete class variable "
339                          "or attribute labels!")
[1139]340            self.data = None
[1689]341
[1407]342        if self.data:
343            # Load context selection
344            items = [(label, v) for label, values in self.data_labels for v in values]
[1689]345
[1407]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
[1689]349
[1407]350            self.openContext("TargetSelection", set(items)) # Load selections from context
351            self.label_selection_widget.set_selection(*self.current_target_selection)
352
[929]353        if not self.data:
[951]354            self.send("Example table with selected genes", None)
355            self.send("Example table with remaining genes", None)
356            self.send("Selected genes", None)
[1689]357
[1407]358    def set_targets(self, targets):
359        """ Set the target groups for score computation.
360        """
361        self.targets = targets
362        self.update_scores()
[929]363   
[1407]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)
[929]367        advance()
[1407]368        score = score_func(target=target)
[929]369        score = [(key, val) for key, val in score if val is not ma.masked]
370        return score
371   
[1407]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)
[1166]376        return [score for run in dist for k, score in run if score is not ma.masked]
[1360]377           
378    @disable_controls
[1407]379    def update_scores(self):
[1360]380        """ Compute the scores and update the histogram.
381        """
[1407]382        self.clear_plot()
383        self.error(0)
[1692]384        label, values = self.current_target_selection
385        if not self.data or label is None:
[1407]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)
[929]412        else:
[1407]413            self.null_dist = []
[929]414        pb.advance()
[1407]415        self.histogram.type = self.histType[self.score_methods[self.method_index][2]]
[1056]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)
[1407]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)
[1056]426               
427                minx = min(min(nullX), self.histogram.minx)
428                maxx = max(max(nullX), self.histogram.maxx)
[1407]429                miny = min(min(nullY/self.permutations_count), self.histogram.miny)
430                maxy = max(max(nullY/self.permutations_count), self.histogram.maxy)
[1056]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)
[929]437           
[1407]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
[1056]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
[1407]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)
[1057]461            self.warning(0)
[1056]462        else:
463            self.warning(0, "No scores obtained.")
[929]464        self.histogram.replot()
465        pb.advance()
466        pb.finish()
[1407]467        self.update_data_info_label()
[835]468           
[1407]469    def update_data_info_label(self):
[929]470        if self.data:
471            samples, genes = len(self.data), len(self.data.domain.attributes)
[1407]472            if self.genes_in_columns:
[929]473                samples, genes = genes, samples
[1407]474                target_labels = [t[1] for t in self.targets]
475            else:
476                target_labels = self.targets
[929]477            text = "%i samples, %i genes\n" % (samples, genes)
[1407]478            text += "Sample target: '%s'" % (",".join(target_labels))
[203]479        else:
[835]480            text = "No data on input\n"
[410]481        self.dataInfoLabel.setText(text)
[203]482
[1407]483    def update_selected_info_label(self, cutOffLower=0, cutOffUpper=0):
484        self.cuts[self.method_index] = (cutOffLower, cutOffUpper)
[929]485        if self.data:
486            scores = np.array(self.scores.values())
[1407]487            test = self.score_methods[self.method_index][2]
[929]488            self.selectedInfoLabel.setText("%i selected genes" % len(np.nonzero(test(scores, cutOffLower, cutOffUpper))[0]))
[203]489        else:
[816]490            self.selectedInfoLabel.setText("0 selected genes")
[204]491
[1407]492    def select_n_best(self):
[204]493        scores = self.scores.items()
494        scores.sort(lambda a,b:cmp(a[1], b[1]))
495        if not scores:
496            return
[1407]497        if self.score_methods[self.method_index][2]==self.oneTailTestHi:
[204]498            scores = scores[-max(self.selectNBest, 1):]
499            self.histogram.setBoundary(scores[0][1], scores[0][1])
[1407]500        elif self.score_methods[self.method_index][2]==self.oneTailTestLow:
[204]501            scores = scores[:max(self.selectNBest,1)]
502            self.histogram.setBoundary(scores[-1][1], scores[-1][1])
503        else:
[413]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]
[1407]507            if self.score_methods[self.method_index][0]=="fold change": ## comparing fold change on a logaritmic scale
[413]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])
[758]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
[413]515            self.histogram.setBoundary(cutLo, cutHi)
[758]516
[1407]517    def update_boundary(self):
[1056]518        if self.data != None and self.scores.items():
[1407]519            if self.score_methods[self.method_index][2]==self.oneTailTestHi:
[1056]520                self.histogram.setBoundary(self.histogram.lowerBoundary, self.histogram.lowerBoundary)
[1407]521            elif self.score_methods[self.method_index][2]==self.oneTailTestLow:
[1056]522                self.histogram.setBoundary(self.histogram.upperBoundary, self.histogram.upperBoundary)
523            else:
524                self.histogram.setBoundary(self.histogram.lowerBoundary, self.histogram.upperBoundary)
525
[1407]526    def select_p_best(self):
527        if not self.null_dist:
[758]528            return
[1407]529        nullDist = sorted(self.null_dist)
530        test = self.score_methods[self.method_index][2]
[1167]531        count = min(int(len(nullDist)*self.selectPValue), len(nullDist))
[758]532        if test == self.oneTailTestHi:
[929]533            cut = nullDist[-count] if count else nullDist[-1] # + 1e-7
[758]534            self.histogram.setBoundary(cut, cut)
535        elif test == self.oneTailTestLow:
[929]536            cut = nullDist[count - 1] if count else nullDist[0] # - 1e-7
[758]537            self.histogram.setBoundary(cut, cut)
538        elif count:
539            scoresHi = nullDist[-count:]
[759]540            scoresLo = nullDist[:count]
[758]541            scores = [(abs(score), 1) for score in scoresHi] + [(abs(score), -1) for score in scoresLo]
[1407]542            if self.score_methods[self.method_index][0] == "fold change": ## fold change is on a logaritmic scale
[758]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)
[929]552           
[1056]553
[1407]554    def commit_if(self):
555        if self.auto_commit:
556            self.commit()
[929]557        else:
[1407]558            self.data_changed_flag = True
[204]559       
[1407]560    def commit(self):
[1139]561        if not self.data or not self.scores:
[929]562            return
[1407]563        test = self.score_methods[self.method_index][2]
[929]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)
[935]570        selected = set([key for key, test in scores if test])
571        remaining = set([key for key, test in scores if not test])
[1407]572        if self.data and self.genes_in_columns:
[951]573            selected = sorted(selected)
[1407]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])
[951]581                mid = orange.newmetaid()
[1139]582               
[1407]583            if self.add_scores_to_output and newdata is not None:
584                newdata.domain.addmeta(mid, score_attr)
[951]585                for ex, key in zip(newdata, selected):
586                    ex[mid] = self.scores[key]
[1118]587                   
[951]588            self.send("Example table with selected genes", newdata)
[1118]589           
[951]590            remaining = sorted(remaining)
[1407]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
[1139]595           
[1407]596            if self.add_scores_to_output and newdata is not None:
597                newdata.domain.addmeta(mid, score_attr)
[951]598                for ex, key in zip(newdata, remaining):
599                    ex[mid] = self.scores[key]
[1118]600                   
[951]601            self.send("Example table with remaining genes", newdata)
[763]602           
[1407]603        elif self.data and not self.genes_in_columns:
[929]604           
[1407]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:
[951]610                for attr in newdomain.attributes:
[1407]611                    attr.attributes[self.score_methods[self.method_index][0]] = str(self.scores[attr])
[929]612            newdomain.addmetas(self.data.domain.getmetas())
613            newdata = orange.ExampleTable(newdomain, self.data)
[1118]614           
[1407]615            self.send("Example table with selected genes", newdata if selected_attrs else None)
[763]616           
[1407]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:
[951]620                for attr in newdomain.attributes:
[1407]621                    attr.attributes[self.score_methods[self.method_index][0]] = str(self.scores[attr])
[929]622            newdomain.addmetas(self.data.domain.getmetas())
623            newdata = orange.ExampleTable(newdomain, self.data)
[1118]624           
[1407]625            self.send("Example table with remaining genes", newdata if remaining_attrs else None)
[763]626           
[1407]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)
[410]636           
[203]637        else:
[951]638            self.send("Example table with selected genes", None)
639            self.send("Example table with remaining genes", None)
640            self.send("Selected genes", None)
[1407]641        self.data_changed_flag = False
[1689]642
[1407]643    def on_target_changed(self):
[1689]644        label, values = self.label_selection_widget.current_selection()
645
646        if values is None:
647            values = []
648
[1407]649        if self.genes_in_columns:
650            targets = [(label, t) for t in values]
651        else:
652            targets = values
[1689]653
[1407]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
[1689]661        self.set_targets(targets)
662
[1407]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)
[830]668
[1407]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   
[203]693if __name__=="__main__":
694    import sys
695    app = QApplication(sys.argv)
[1066]696#    data = orange.ExampleTable("/home/marko/t2.tab")
[1407]697#    data = orange.ExampleTable("../../../doc/datasets/brown-selected")
698    data = orange.ExampleTable(os.path.expanduser("~/Documents/GDS636"))
[203]699    w = OWFeatureSelection()
700    w.show()
[1407]701    w.set_data(data)
702#    w.set_data(None)
703#    w.set_data(data)
[686]704    app.exec_()
[498]705    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.