source: orange-bioinformatics/Orange/bioinformatics/widgets/OWFeatureSelection.py @ 1632:9cf919d0f343

Revision 1632:9cf919d0f343, 31.7 KB checked in by mitar, 2 years ago (diff)

Fixing imports.

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