source: orange-bioinformatics/_bioinformatics/widgets/prototypes/OWHypTest.py @ 1636:10d234fdadb9

Revision 1636:10d234fdadb9, 40.1 KB checked in by mitar, 2 years ago (diff)

Restructuring because we will not be using namespaces.

Line 
1## Automatically adapted for numpy.oldnumeric Oct 04, 2007 by
2
3"""
4<name>Hypotheses test</name>
5<description>Single Sample / Related Samples t-test, One/Two Way Analysis of Variance, Local-Pooled-Error Two Sample Z-test.</description>
6<icon>icons/ChipANOVA.png</icon>
7<priority>1071</priority>
8<contact>Peter Juvan (peter.juvan@fri.uni-lj.si)</contact>
9"""
10
11from __future__ import absolute_import
12
13import qt, qwt
14
15import numpy.oldnumeric as Numeric, numpy.oldnumeric.ma as MA
16
17import scipy.stats
18
19from Orange.OrangeWidgets import OWGUI
20from Orange.OrangeWidgets.OWWidget import *
21
22from .. import Anova
23from .OWDataFiles import DataFiles, ExampleSelection
24
25class OWHypTest(OWWidget):
26    settingsList  = ["anovaType", "popMean", "_interaction", "selectorA", "selectorB", "selectorI", "alphaA", "alphaB", "alphaI", "autoUpdateSelName", "sendNotSelectedData", "sendProbabilities", "commitOnChange"]
27
28    StNames = ["Single sample t-test", "Related samples t-test", "[not impl.: LPE (local-pooled-error two sample z-test)]", "Single-factor ANOVA (A, variables)", "Single-factor ANOVA (B, data sets)", "Two-factor ANOVA", "Two-factor ANOVA with interaction effect"]
29    StSST  = 0   # single sample t-test
30    StRST  = 1   # related seamples t-test (either by A or B)
31    StLPE  = 2   # Local-pool-error two sample z-test
32    St1A   = 3   # One-way ANOVA by variables (A)
33    St1B   = 4   # One-way ANOVA by datasets (B)
34    St2AB  = 5   # Two-way ANOVA
35    St2ABI = 6   # Two-way ANOVA with interaction
36
37    def __init__(self, parent=None, signalManager = None):
38        OWWidget.__init__(self, parent, signalManager, 'ANOVA')
39        # input / output data: [("name1", [orange.ExampleTable1a,...]), ("name2", [orange.ExampleTable2a,...])]
40        self.inputs = [("Structured Data", DataFiles, self.onDataInput)]
41        self.outputs = [("Example Selection", ExampleSelection, Default), ("Selected Structured Data", DataFiles, Default), ("Other Structured Data", DataFiles)]
42
43        # data, p-values, selected examples
44        self.dataStructure = None                       # input data
45        self.numExamples = 0
46        self.numVariables = 0
47        self.ps = Numeric.ones((3,0), Numeric.Float)    # p-values: 2D Numeric.array of shape (3, numExamples)
48        self.selectorName = ""                          # for Example Selection output: (self.selectorName, [0,1,0,...])
49
50        # Settings
51        self.anovaType = OWHypTest.StSST
52        self.popMean = 0         # single sample t-test, value to compare to
53        self.useFactors = [0,0,0]       # [use factor A, use factor B, use interaction]
54        self._interaction = 0           # to store last setting: 0: no interaction, 1: test for interaction effect (set this value manually !!!)
55        self.selectorA = True
56        self.selectorB = False
57        self.selectorI = False
58        self.alphaA = "0.05"
59        self.alphaB = "0.05"
60        self.alphaI = "0.05"
61        self.autoUpdateSelName = 1
62        self.sendNotSelectedData = 1
63        self.sendProbabilities = 0
64        self.commitOnChange = 0
65        self.loadSettings()
66
67        # GUI
68        self.mainArea.setFixedWidth(0)
69        ca=QFrame(self.controlArea)
70        gl=QGridLayout(ca,4,1,5)
71       
72        # info
73        box = QVGroupBox("Info", ca)
74        gl.addWidget(box,0,0)
75        self.infoa = QLabel('No data on input.', box)
76        self.infob = QLabel('', box)
77        self.infoc = QLabel('', box)
78
79        # ANOVA type
80        self.boxAnovaType = QVButtonGroup("Statistics", ca)
81        gl.addWidget(self.boxAnovaType,1,0)
82        self.boxAnovaType.setDisabled(1)
83
84        self.boxAnovaType.setRadioButtonExclusive(1)
85        self.boxAnovaType.buttons = []
86##        for i,lbl in enumerate(OWHypTest.StNames):
87##            w = QRadioButton(lbl, self.boxAnovaType)
88##            w.setOn(self.anovaType == i)
89##            self.boxAnovaType.buttons.append(w)
90##            if i == OWHypTest.StSST:
91##                self.boxPopMean = QHBox(self.boxAnovaType)
92##                QLabel("             population mean  ", self.boxPopMean)
93##                OWGUI.lineEdit(self.boxPopMean, self, "popMean", callback=self.onPopMeanChange)
94        for i,lbl in enumerate(OWHypTest.StNames):
95            w = QRadioButton(lbl, self.boxAnovaType)
96            w.setOn(self.anovaType == i)
97            self.boxAnovaType.buttons.append(w)
98            if i == OWHypTest.StSST:
99                self.boxPopMean = QHBox(self.boxAnovaType)
100                QLabel("       population mean  ", self.boxPopMean)
101                OWGUI.lineEdit(self.boxPopMean, self, "popMean", callback=self.onPopMeanChange)
102        OWGUI.connectControl(self.boxAnovaType, self, "anovaType", self.onAnovaType, "clicked(int)", OWGUI.CallFront_radioButtons(self.boxAnovaType))
103       
104        # selection of examples
105        self.boxSelection = QVGroupBox("Example Selection", ca)
106        gl.addWidget(self.boxSelection,2,0)
107        self.lblNumGenes = []   # list of labels
108        # selector A
109        self.boxSelectorA = QVBox(self.boxSelection)
110        self.cbSelectorA = OWGUI.checkBox(self.boxSelectorA, self, "selectorA", "Factor A (variables)", callback=self.onSelectionChange,
111                                          tooltip='H0: The mean does not depend on factor A (represented by variables).')
112        frmA = QFrame(self.boxSelectorA)
113        glA = QGridLayout(frmA,1,3,5)
114        leA = OWGUI.lineEdit(frmA, self, "alphaA", orientation="horizontal", controlWidth=None, callback=lambda x=0: self.onAlphaChange(x))
115        glA.addWidget(leA,0,1) # Qt.AlignRight
116        glA.addWidget(QLabel("     p <= ", frmA), 0,0)
117        self.lblNumGenes.append(QLabel('', frmA))
118        glA.addWidget(self.lblNumGenes[-1],0,2) # Qt.AlignRight | 0x22
119
120        # selector B
121        self.boxSelectorB = QVBox(self.boxSelection)
122        self.cbSelectorB = OWGUI.checkBox(self.boxSelectorB, self, "selectorB", "Factor B (data sets)", callback=self.onSelectionChange,
123                                          tooltip='H0: The mean does not depend on factor B (represented by data sets).')
124        frmB = QFrame(self.boxSelectorB)
125        glB = QGridLayout(frmB,1,3,5)
126        leB = OWGUI.lineEdit(frmB, self, "alphaB", orientation="horizontal", callback=lambda x=1: self.onAlphaChange(x))
127        glB.addWidget(leB,0,1)
128        glB.addWidget(QLabel("     p <= ", frmB), 0,0)
129        self.lblNumGenes.append(QLabel('', frmB))
130        glB.addWidget(self.lblNumGenes[-1],0,2)
131       
132        # selector I
133        self.boxSelectorI = QVBox(self.boxSelection)
134        self.cbSelectorI = OWGUI.checkBox(self.boxSelectorI, self, "selectorI", "Interaction (variables * data sets)", callback=self.onSelectionChange,
135                                          tooltip='H0: There is no interaction between factor A and factor B.')
136        frmI = QFrame(self.boxSelectorI)
137        glI = QGridLayout(frmI,1,3,5)
138        leI = OWGUI.lineEdit(frmI, self, "alphaI", orientation="horizontal", callback=lambda x=2: self.onAlphaChange(x))
139        ## slider could be used to replace lineEdit (but not sensitive enough)
140        ##        self.alphaIf = 0.05
141        ##        leI = OWGUI.qwtHSlider(self.boxSelectorI, self, "alphaIf", box="", label="      p < ", labelWidth=None, minValue=0.0001, maxValue=1.0, step=0.1, precision=3, callback=lambda x=2: self.onAlphaChange(x), logarithmic=1, ticks=0, maxWidth=None)
142        glI.addWidget(leI,0,1)
143        glI.addWidget(QLabel("     p <= ", frmI), 0,0)
144        self.lblNumGenes.append(QLabel('', frmI))
145        glI.addWidget(self.lblNumGenes[-1],0,2)
146       
147        # output
148        box = QVGroupBox("Output", ca)
149        gl.addWidget(box,3,0)
150        self.leSelectorName = OWGUI.lineEdit(box, self, 'selectorName', label='Selector Name: ')
151        self.leSelectorName.setReadOnly(self.autoUpdateSelName)
152        OWGUI.checkBox(box, self, 'autoUpdateSelName', 'Automatically update selector name', callback=self.onAutoUpdateSelNameChange)
153        OWGUI.checkBox(box, self, 'sendNotSelectedData', 'Send not selected data', callback=self.onSendNotSelectedChange)
154        OWGUI.checkBox(box, self, 'sendProbabilities', 'Show p-values', callback=self.onSendProbabilitiesChange)
155        OWGUI.checkBox(box, self, 'commitOnChange', 'Commit data on selection change', callback=lambda: self.onCommit(self.commitOnChange))
156        self.btnCommit = OWGUI.button(box, self, "Commit", callback=self.onCommit)
157
158        # enable/disable anova type box, example selection box, commit button, update the number of examples for individual selectors
159        self.updateAnovaTypeBox()
160        self.updateSelectorBox()
161        self.updateSelectorInfos()
162        self.updateSelectorName()
163        self.resize(283, self.sizeHint().height())
164
165
166    def onDataInput(self, structuredData):
167        """handles input data; sets self.dataStructure, self.numExamples, self.numVariables and self.ps;
168        updates info, calls updateAnovaTypeBox(), runs ANOVA and sends out new data.
169        """
170        self.dataStructure = structuredData
171        self.numExamples = 0
172        self.numVariables = 0
173        self.ps = Numeric.ones((3,0), Numeric.Float)
174        if structuredData:
175            numFiles = reduce(lambda a,b: a+len(b[1]), structuredData, 0)
176            lenSD = len(structuredData)
177            self.infoa.setText("%d set%s, total of %d data file%s." % (lenSD, ["","s"][lenSD!=1], numFiles, ["","s"][numFiles!=1]))
178            numExamplesList = []
179            numVariablesList = []
180            # construct a list of ExampleTable lengths and a list of number of variables
181            for (name, etList) in structuredData:
182                for et in etList:
183                    numExamplesList.append(len(et))
184                    numVariablesList.append(len(et.domain.variables))
185            # test that all ExampleTables consist of equal number of examples and variables
186            if len(numExamplesList) == 0 or Numeric.add.reduce(Numeric.equal(numExamplesList, numExamplesList[0])) != len(numExamplesList):
187                self.dataStructure = None
188                self.numExamples = -1
189                self.infob.setText("Error: data files contain unequal number of examples, aborting ANOVA computation.")
190                self.infoc.setText('')
191            elif len(numVariablesList) == 0 or Numeric.add.reduce(Numeric.equal(numVariablesList, numVariablesList[0])) != len(numVariablesList):
192                self.dataStructure = None
193                self.numVariables = -1
194                self.infob.setText("Error: data files contain unequal number of variables, aborting ANOVA computation.")
195                self.infoc.setText('')
196            else:
197                self.numExamples = numExamplesList[0]
198                self.numVariables = numVariablesList[0]
199                self.infob.setText("%d variable%s, %d example%s in each file." % (self.numVariables, ["","s"][self.numVariables!=1], self.numExamples, ["","s"][self.numExamples!=1]))
200                if self.numExamples > 0:
201                    self.infoc.setText('Press Commit button to start ANOVA computation.')
202                else:
203                    self.infoc.setText('')
204                self.boxAnovaType.setEnabled(1)
205                self.boxSelection.setEnabled(1)
206                self.btnCommit.setEnabled(True)
207        else:
208            self.infoa.setText('No data on input.')
209            self.infob.setText('')
210            self.infoc.setText('')
211        # enable/disable anova type selection depending on the type of input data
212        self.updateAnovaTypeBox()
213        self.updateSelectorBox()
214        if self.autoUpdateSelName:
215            self.updateSelectorName()
216        # run ANOVA
217        if self.commitOnChange:
218            self.runANOVA()
219            self.senddata()
220        self.updateSelectorInfos()
221
222       
223    def runANOVA(self):
224        """converts structured data [(name, [orngET1, orngET2, ...]),...] to a 3D masked array
225        with the following axes: 0: examples, 1: variables, 2: ExampleTables;
226        runs ANOVA computations and sets self.ps;
227        """
228        if self.dataStructure and self.numExamples > 0:
229            ma3d = MA.zeros((self.numExamples, self.numVariables, reduce(lambda a,b: a+len(b[1]), self.dataStructure, 0)), Numeric.Float) * MA.masked
230            groupLens = []
231            etIdx = 0
232            for dsName, etList in self.dataStructure:
233                for et in etList:
234                    ma3d[:,:,etIdx] = et.toNumpyMA("ac")[0]
235                    etIdx += 1
236                groupLens.append(len(etList))
237            # run ANOVA
238            self.infoc.setText('ANOVA computation started...')
239            self.progressBarInit()
240            pbStep = 100./self.numExamples
241            self.ps = Numeric.ones((3, self.numExamples), Numeric.Float)
242
243            if self.anovaType == OWHypTest.St2AB or self.anovaType == OWHypTest.St2ABI:
244                ps = self.anova2(ma3d, groupLens, addInteraction=self.anovaType==OWHypTest.St2ABI, repMeasuresOnA=False, callback=lambda: self.progressBarAdvance(pbStep))
245                for rIdx in range(ps.shape[0]):
246                    self.ps[rIdx] = ps[rIdx]
247
248            elif self.anovaType == OWHypTest.St1B:
249                self.ps[1] = self.anova1B(ma3d, groupLens, repMeasures=False, callback=lambda: self.progressBarAdvance(pbStep))
250
251            elif self.anovaType == OWHypTest.St1A:
252                self.ps[0] = self.anova1A(ma3d, repMeasures=False, callback=lambda: self.progressBarAdvance(pbStep))
253
254            elif self.anovaType == OWHypTest.StSST:
255                try:
256                    popMeanVal = float(self.popMean)
257                except ValueError:
258                    print "Warning: cannot convert %s to float, using 0" % str(self.popMean)
259                    self.popMean = 0
260                    popMeanVal = 0
261                self.ps[0] = self.ttest_ssmpl(ma3d, popMeanVal, callback=lambda: self.progressBarAdvance(pbStep))
262
263            elif self.anovaType == OWHypTest.StLPE:
264               raise Exception, "NOT IMPLEMENTED"
265               if self.numVariables == 2:
266                  self.ps[0] = self.lpeA(ma3d, callback=lambda: self.progressBarAdvance(pbStep))
267               elif self.numVariables == 1:
268                  self.ps[1] = self.lpeB(ma3d, groupLens, callback=lambda: self.progressBarAdvance(pbStep))
269               else:
270                  raise RuntimeError, "%s: expected 2 variables and 1 group, or 1 variable and 2 groups, got %s variables and %s groups" % (OWHypTest.StNames[self.anovaType], self.numVariables, len(groupLens))
271
272            elif self.anovaType == OWHypTest.StRST:
273               if self.numVariables == 2 and len(groupLens) == 1:
274                  self.ps[0] = self.ttest_rsmplA(ma3d, callback=lambda: self.progressBarAdvance(pbStep))
275               elif self.numVariables == 1 and len(groupLens) == 2 and groupLens[0] == groupLens[1]:
276                  self.ps[1] = self.ttest_rsmplB(ma3d, groupLens, callback=lambda: self.progressBarAdvance(pbStep))
277               else:
278                  raise RuntimeError, "%s: expected 2 variables and 1 group, or 1 variable and 2 groups of equal length, got %s variables and %s groups of length %s" % (OWHypTest.StNames[self.anovaType], self.numVariables, len(groupLens), str(groupLens))
279                 
280            self.progressBarFinished()
281
282
283    def lpeA(self, ma3d, callback):
284        """conducts local-pooled-error test;
285        reference: Jain et.al. (2003) Bioinformatics.
286        """
287        raise Exception, "NOT IMPLEMENTED"
288
289    def lpeB(self, ma3d, callback):
290        """conducts local-pooled-error test;
291        reference: Jain et.al. (2003) Bioinformatics.
292        """
293        raise Exception, "NOT IMPLEMENTED"
294
295
296    def ttest_ssmpl(self, ma3d, popMeanVal, callback):
297        """conducts single-sample t-test on individual examples wrt factor A (variables, ma3d axis 1);
298        returns Numeric array of p-values in shape (1, numExamples).
299        """
300        ps = -1*Numeric.ones((ma3d.shape[0],), Numeric.Float)
301        for eIdx in range(ma3d.shape[0]):
302            data = Numeric.asarray(MA.transpose(ma3d[eIdx]).compressed())
303            if len(data) >= 2:
304                try:
305                    ps[eIdx] = scipy.stats.ttest_1samp(data, popMeanVal)[1]
306                except:
307                    print "Warning: zero variance, check the example %i:" % eIdx, data
308                    ps[eIdx] = 1.0
309            else:
310##                print "Warning: removing example %i:\n%s\n%s\n" % (eIdx, str(data))
311                print "Warning: removing example %i:" % eIdx, str(data)
312                ps[eIdx] = 1.0
313            callback()
314        return ps
315
316
317    def ttest_rsmplA(self, ma3d, callback):
318        """conducts related samples t-test on individual examples wrt factor A (variables, ma3d axis 1);
319        returns Numeric array of p-values in shape (1, numExamples).
320        """
321        ps = -1*Numeric.ones((ma3d.shape[0],), Numeric.Float)
322        for eIdx in range(ma3d.shape[0]):
323            a = ma3d[eIdx][0]
324            b = ma3d[eIdx][1]
325            cond = Numeric.logical_not(Numeric.logical_or(MA.getmaskarray(a), MA.getmaskarray(b)))
326            a = Numeric.asarray(MA.compress(cond, a))
327            b = Numeric.asarray(MA.compress(cond, b))
328            if len(a) >= 2:
329                try:
330                    ps[eIdx] = scipy.stats.ttest_rel(a,b)[1]
331                except Exception, inst:
332                    print "Warning: %s" % str(inst)
333                    print "Example %i:\n%s\n%s\n" % (eIdx, str(a), str(b))
334                    ps[eIdx] = 1.0
335            else:
336                print "Warning: removing example %i:\n%s\n%s\n" % (eIdx, str(a), str(b))
337                ps[eIdx] = 1.0
338            callback()
339        return ps
340
341
342    def ttest_rsmplB(self, ma3d, groupLens, callback):
343        """conducts related samples t-test on individual examples wrt factor B (datasets, ma3d axis 2);
344        ma3d axis 2 also contains replicas according to groupLens;
345        returns Numeric array of p-values in shape (1, numExamples).
346        """
347        ps = -1*Numeric.ones((ma3d.shape[0],), Numeric.Float)
348        for eIdx in range(ma3d.shape[0]):
349            a = ma3d[eIdx][0][:groupLens[0]]
350            b = ma3d[eIdx][0][groupLens[0]:]
351            cond = Numeric.logical_not(Numeric.logical_or(MA.getmaskarray(a), MA.getmaskarray(b)))
352            a = Numeric.asarray(MA.compress(cond, a))
353            b = Numeric.asarray(MA.compress(cond, b))
354            if len(a) >= 2:
355                try:
356                    ps[eIdx] = scipy.stats.ttest_rel(a,b)[1]
357                except Exception, inst:
358                    print "Warning: %s" % str(inst)
359                    print "Example %i:\n%s\n%s\n" % (eIdx, str(a), str(b))
360                    ps[eIdx] = 1.0
361            else:
362                print "Warning: removing example %i:\n%s\n%s\n" % (eIdx, str(a), str(b))
363                ps[eIdx] = 1.0
364            callback()
365        return ps
366
367
368    def anova1A(self, ma3d, repMeasures, callback):
369        """conducts one-way ANOVA on individual examples wrt factor A (variables, ma3d axis 1);
370        returns Numeric array of p-values in shape (1, numExamples).
371        """
372        ps = -1*Numeric.ones((ma3d.shape[0],), Numeric.Float)
373        if repMeasures:
374            fAnova = Anova.AnovaRM12LR
375        else:
376            fAnova = Anova.Anova1wayLR_2D
377        for eIdx in range(ma3d.shape[0]):
378            an = fAnova(MA.transpose(ma3d[eIdx]))
379            ps[eIdx] = an.Fprob
380            callback()
381        return ps
382
383    def anova1B(self, ma3d, groupLens, repMeasures, callback):
384        """conducts one-way ANOVA on individual examples wrt factor B (data sets);
385        ma3d axis 2 also contains replicas according to groupLens;
386        returns Numeric array of p-values in shape (1, numExamples).
387        WARNING: works slower than anova1A because it requires to copy 1D array to 2D array
388                 although we could use Anova1wayLR instead of Anova1wayLR_2D, but not for repeated measures
389                 additionaly, Anova1wayLR_2D handles missing factor levels correctly, which is not the case for Anova1wayLR
390        """
391        ps = -1*Numeric.ones((ma3d.shape[0],), Numeric.Float)
392        # groupLens [2,3,4] -> groupInd [[0,1],[2,3,4],[5,6,7,8]]
393        if repMeasures:
394            fAnova = Anova.AnovaRM12LR
395        else:
396            fAnova = Anova.Anova1wayLR_2D
397        grpLensAcc = Numeric.concatenate([[0],Numeric.add.accumulate(groupLens)])
398        grpInd = map(lambda i,j: range(i, j), grpLensAcc[:-1], grpLensAcc[1:])
399        for eIdx in range(ma3d.shape[0]):
400            m2 = MA.zeros((max(groupLens)*ma3d.shape[1], len(groupLens)), Numeric.Float) * MA.masked # axis0: replicas, axis1: factor B levels
401            for groupIdx,takeInd in enumerate(grpInd):
402                m2[:groupLens[groupIdx]*ma3d.shape[1], groupIdx] = MA.ravel(ma3d[eIdx].take(takeInd, 1))
403            an = fAnova(m2)
404            ps[eIdx] = an.Fprob
405            callback()
406        return ps
407
408    def anova2(self, ma3d, groupLens, addInteraction, repMeasuresOnA, callback):
409        """Conducts two-way ANOVA on individual examples;
410        returns a Numeric array of p-values in shape (2, numExamples) or (3, numExamples), depending whether we test for interaction;
411        Note: levels of factors A and B that cause empty cells are removed prior to conducting ANOVA.
412        """
413        groupLens = Numeric.asarray(groupLens)
414        # arrays to store p-vals
415        if addInteraction:
416            ps = Numeric.ones((3, ma3d.shape[0]), Numeric.Float)
417        else:
418            ps = Numeric.ones((2, ma3d.shape[0]), Numeric.Float)
419        # decide between non-repeated / repeated measures ANOVA for factor time
420        if repMeasuresOnA:
421            fAnova = Anova.AnovaRM12LR
422        else:
423            fAnova = Anova.Anova2wayLR
424        # check for empty cells for all genes at once and remove them
425        tInd2rem = []
426        ax2Ind = Numeric.concatenate(([0], Numeric.add.accumulate(groupLens)))
427        for aIdx in range(ma3d.shape[1]):
428            for rIdx in range(groupLens.shape[0]):
429                if Numeric.add.reduce(MA.count(ma3d[:,aIdx,ax2Ind[rIdx]:ax2Ind[rIdx+1]],1)) == 0:
430                    tInd2rem.append(aIdx)
431                    break
432        if len(tInd2rem) > 0:
433            print "Warning: removing time indices %s for all genes" % (str(tInd2rem))
434            tInd2keep = range(ma3d.shape[1])
435            for aIdx in tInd2rem:
436                tInd2keep.remove(aIdx)
437            ma3d = ma3d.take(tInd2keep, 1)
438        # for each gene...
439        for eIdx in range(ma3d.shape[0]):
440            # faster check for empty cells for that gene -> remove time indices with empty cells
441            ma2d = ma3d[eIdx]
442            cellCount = MA.zeros((ma2d.shape[0], groupLens.shape[0]), Numeric.Int)
443            for g,(i0,i1) in enumerate(zip(ax2Ind[:-1], ax2Ind[1:])):
444                cellCount[:,g] = MA.count(ma2d[:,i0:i1], 1)
445            ma2dTakeInd = Numeric.logical_not(Numeric.add.reduce(Numeric.equal(cellCount,0),1)) # 1 where to take, 0 where not to take
446            if Numeric.add.reduce(ma2dTakeInd) != ma2dTakeInd.shape[0]:
447                print "Warning: removing time indices %s for gene %i" % (str(Numeric.compress(ma2dTakeInd == 0, Numeric.arange(ma2dTakeInd.shape[0]))), eIdx)
448                ma2d = MA.compress(ma2dTakeInd, ma2d, 0)
449            an = fAnova(ma2d, groupLens, addInteraction, allowReductA=True, allowReductB=True)
450            ps[:,eIdx] = an.ps
451            callback()
452        return ps
453
454
455    def updateAnovaTypeBox(self):
456        """Sets self.anovaType according to the size of the dataset;
457           enables/disables: - anova type selection box;
458                             - individual anova type radio buttons;
459                             - compareTo box;
460                             - commit button
461        """
462        if self.dataStructure and self.numExamples > 0:
463            # enable anova type box and commit button
464            self.boxAnovaType.setEnabled(1)
465            self.btnCommit.setEnabled(1)
466            # disable all radio buttions
467            for i in range(len(OWHypTest.StNames)):
468                self.boxAnovaType.buttons[i].setEnabled(0)
469            # select appropriate anova type and enable corresponding radio buttons
470            if len(self.dataStructure) == 1 and self.numVariables == 1:
471                # single-sample t-test (factor A)
472                self.anovaType = OWHypTest.StSST
473                self.boxAnovaType.buttons[self.anovaType].setEnabled(1)
474                self.boxAnovaType.buttons[self.anovaType].setChecked(1)
475            elif len(self.dataStructure) == 1 and self.numVariables == 2:
476                # RST or LPE or ANOVA1 by variables (A)
477                self.boxAnovaType.buttons[OWHypTest.StRST].setEnabled(1)
478                self.boxAnovaType.buttons[OWHypTest.StLPE].setEnabled(1)
479                self.boxAnovaType.buttons[OWHypTest.St1A].setEnabled(1)
480                if not self.boxAnovaType.buttons[OWHypTest.StLPE].isChecked() and not self.boxAnovaType.buttons[OWHypTest.St1A].isChecked():
481                    self.anovaType = OWHypTest.StRST
482                    self.boxAnovaType.buttons[self.anovaType].setChecked(1)
483            elif len(self.dataStructure) == 2 and self.numVariables == 1:
484                # RST or LPE or ANOVA1 by datasets (B)
485                self.boxAnovaType.buttons[OWHypTest.StRST].setEnabled(1)
486                self.boxAnovaType.buttons[OWHypTest.StLPE].setEnabled(1)
487                self.boxAnovaType.buttons[OWHypTest.St1B].setEnabled(1)
488                if not self.boxAnovaType.buttons[OWHypTest.StLPE].isChecked() and not self.boxAnovaType.buttons[OWHypTest.St1B].isChecked():
489                    self.anovaType = OWHypTest.StRST
490                    self.boxAnovaType.buttons[self.anovaType].setChecked(1)
491            elif len(self.dataStructure) == 1 and self.numVariables > 1:
492                # single-factor (A) ANOVA
493                self.anovaType = OWHypTest.St1A
494                self.boxAnovaType.buttons[self.anovaType].setEnabled(1)
495                self.boxAnovaType.buttons[self.anovaType].setChecked(1)
496            elif len(self.dataStructure) > 1 and self.numVariables == 1:
497                # single-factor (B) ANOVA
498                self.anovaType = OWHypTest.St1B
499                self.boxAnovaType.buttons[self.anovaType].setEnabled(1)
500                self.boxAnovaType.buttons[self.anovaType].setChecked(1)
501            elif len(self.dataStructure) > 1 and self.numVariables > 1:
502                # two-factor ANOVA
503                self.boxAnovaType.buttons[OWHypTest.St1A].setEnabled(1)
504                self.boxAnovaType.buttons[OWHypTest.St1B].setEnabled(1)
505                self.boxAnovaType.buttons[OWHypTest.St2AB].setEnabled(1)
506                self.boxAnovaType.buttons[OWHypTest.St2ABI].setEnabled(1)
507                if not self.boxAnovaType.buttons[OWHypTest.St1A].isChecked() and not self.boxAnovaType.buttons[OWHypTest.St1B].isChecked() and not self.boxAnovaType.buttons[OWHypTest.St2AB].isChecked() and not self.boxAnovaType.buttons[OWHypTest.St2ABI].isChecked():
508                    if self._interaction:
509                        self.anovaType = OWHypTest.St2ABI
510                    else:
511                        self.anovaType = OWHypTest.St2AB
512                    self.boxAnovaType.buttons[self.anovaType].setChecked(1)
513            # enable/disable compareTo lineEdit
514            self.boxPopMean.setEnabled(self.anovaType == OWHypTest.StSST)
515        else:
516            # disable anova type box and commit button
517            self.boxAnovaType.setDisabled(1)
518            self.btnCommit.setDisabled(1)
519
520
521    def updateSelectorBox(self):
522        """enables / disables individual selectors
523        """
524        if self.dataStructure and self.numExamples > 0:
525            # enable example selection box
526            self.boxSelection.setEnabled(1)
527            # enable/disable selectors A, B and I
528            self.boxSelectorA.setEnabled(self.anovaType == OWHypTest.StSST or
529                                         self.anovaType == OWHypTest.St1A or
530                                         (self.anovaType == OWHypTest.StRST and self.numVariables == 2) or
531                                         (self.anovaType == OWHypTest.StLPE and self.numVariables == 2) or
532                                         self.anovaType == OWHypTest.St2AB or
533                                         self.anovaType == OWHypTest.St2ABI)
534            self.boxSelectorB.setEnabled(self.anovaType == OWHypTest.St1B or
535                                         (self.anovaType == OWHypTest.StRST and self.numVariables == 1) or
536                                         (self.anovaType == OWHypTest.StLPE and self.numVariables == 1) or
537                                         self.anovaType == OWHypTest.St2AB or
538                                         self.anovaType == OWHypTest.St2ABI)
539            self.boxSelectorI.setEnabled(self.anovaType == OWHypTest.St2ABI)
540        else:
541            # disable example selection box
542            self.boxSelection.setDisabled(1)
543
544
545    def updateSelectorInfos(self, selectorIdx=None):
546        """updates the number of examples that match individual selectors;
547        if selectorIdx is given, updates only the corresponding info.
548        """
549        if not selectorIdx:
550            selectorInd = range(3)
551        else:
552            selectorInd = [selectorIdx]
553        alphas = [self.alphaA, self.alphaB, self.alphaI]
554        boxSelectors = [self.boxSelectorA, self.boxSelectorB, self.boxSelectorI]
555        for si in selectorInd:
556            try:
557                alpha = float(alphas[si])
558                ps = self.ps[si]
559            except ValueError:
560                alpha = None
561                ps = None
562##            if ps != None and alpha != None and self.anovaType in [[0,1,3,4],[2,3,4],[4]][si]:
563            if ps != None and alpha != None and boxSelectors[si].isEnabled():               
564                numSelected = Numeric.add.reduce(Numeric.less(self.ps[si], alpha))
565                self.lblNumGenes[si].setText('  (%d example%s)' % (numSelected, ['', 's'][int(numSelected!=1)]))
566            else:
567                self.lblNumGenes[si].setText('  (no examples)')
568
569
570    def senddata(self):
571        """computes selectionList, partitions the examples and updates infoc;
572        sends out selectionList and selected/other dataStructure or None;
573        """
574        if self.dataStructure and self.ps.shape[1]:
575            # set selectionList
576            alphas = [self.alphaA, self.alphaB, self.alphaI]
577            selectors = [self.selectorA, self.selectorB, self.selectorI]
578            selectionList = Numeric.ones((self.numExamples,))
579            boxSelectors = [self.boxSelectorA, self.boxSelectorB, self.boxSelectorI]
580            for si in range(3):
581                try:
582##                    if selectors[si] and self.anovaType in [[0,1,3,4],[2,3,4],[4]][si]:
583                    if selectors[si] and boxSelectors[si].isEnabled():
584                        selectionList = Numeric.logical_and(selectionList, Numeric.less(self.ps[si], float(alphas[si])))
585                except ValueError:
586                    print "Warning: cannot convert %s to float" % str(alphas[si])
587                    pass
588            self.infoc.setText('Sending out data...')
589           
590            if self.sendProbabilities:
591                # create example table with probabilities
592##                print self.ps
593##                print Numeric.transpose(self.ps).shape
594                etProb = orange.ExampleTable(orange.Domain([orange.FloatVariable("Factor A p-val"),orange.FloatVariable("Factor B p-val"),orange.FloatVariable("Interaction p-val")]), Numeric.transpose(self.ps))
595                # in etProb, convert p-val to meta attribute
596                domProb = orange.Domain([])
597                domProb.addmetas(dict(zip([orange.newmetaid(),orange.newmetaid(),orange.newmetaid()], etProb.domain.variables)))
598                etProb = orange.ExampleTable(domProb, etProb)
599            else:
600                # create new etProb without attributes/metas and of length equal to etProb
601                etProb = orange.ExampleTable(orange.Domain([]), Numeric.zeros((selectionList.shape[0],0)))
602
603            # partition dataStructure and send out data
604            selectionList = selectionList.tolist()
605            self.send("Example Selection", (self.selectorName, selectionList))
606            dataStructS = []
607            dataStructN = []
608            self.progressBarInit()
609
610            if self.sendNotSelectedData:
611                pbStep = 50./len(self.dataStructure)
612            else:
613                pbStep = 100./len(self.dataStructure)
614
615            for (dsName, etList) in self.dataStructure:
616                etListS = [et.select(selectionList) for et in etList]
617                for i in range(len(etList)):
618                    # append probabilities (if etProb not empty)
619                    etListS[i] = orange.ExampleTable([etListS[i], etProb.select(selectionList)])
620                    # add name
621                    etListS[i].name = etList[i].name
622                dataStructS.append((dsName, etListS))
623                self.progressBarAdvance(pbStep)
624            self.send("Selected Structured Data", dataStructS)
625
626            if self.sendNotSelectedData:
627                for (dsName, etList) in self.dataStructure:
628                    etListN = [et.select(selectionList, negate=1) for et in etList]
629                    for i in range(len(etList)):
630                        # append probabilities (if etProb not empty)
631                        etListN[i] = orange.ExampleTable([etListN[i], etProb.select(selectionList, negate=1)])
632                        # add name
633                        etListN[i].name = etList[i].name
634                    dataStructN.append((dsName, etListN))
635                    self.progressBarAdvance(pbStep)
636                self.send("Other Structured Data", dataStructN)
637            else:
638                self.send("Other Structured Data", None)
639
640            self.progressBarFinished()
641            # report the number of selected examples
642            numExamples = Numeric.add.reduce(Numeric.greater(selectionList, 0))
643            self.infoc.setText('Total of %d example%s match criteria.' % (numExamples, ['', 's'][int(numExamples!=1)]))
644        else:
645            self.send("Example Selection", None)
646            self.send("Selected Structured Data", None)
647            self.send("Other Structured Data", None)
648           
649
650##    def updateSelectorName(self):
651##        """update selector name shown in selector edit box
652##        """
653##        if self.dataStructure:
654##            if self.anovaType == 0:
655##                s = '1 smpl. t-test, compared to %s' % self.popMean
656##            else:
657##                s = 'ANOVA'
658##            s += " (%s)" % reduce(lambda a,b: a + ", " + b[0], self.dataStructure, "")[2:]
659##            if self.selectorA and self.anovaType in [0,1,3,4]:
660##                s += ", pA<%s" % self.alphaA
661##            if self.selectorB and self.anovaType in [2,3,4]:
662##                s += ", pB<%s" % self.alphaB
663##            if self.selectorI and self.anovaType == 4:
664##                s += ", pI<%s" % self.alphaI
665##            self.selectorName = s.strip()
666##        else:
667##            self.selectorName = ""
668    def updateSelectorName(self):
669        """update selector name shown in selector edit box
670        """
671        if self.dataStructure:
672            s = OWHypTest.StNames[self.anovaType]
673            if self.anovaType == OWHypTest.StSST:
674               s += " (pop. mean: %s)" % self.popMean
675            s += " (%s)" % reduce(lambda a,b: a + ", " + b[0], self.dataStructure, "")[2:]
676            if self.selectorA and self.boxSelectorA.isEnabled():
677                s += ", pA<%s" % self.alphaA
678            if self.selectorB and self.boxSelectorB.isEnabled():
679                s += ", pB<%s" % self.alphaB
680            if self.selectorI and self.boxSelectorI.isEnabled():
681                s += ", pI<%s" % self.alphaI
682            self.selectorName = s.strip()
683        else:
684            self.selectorName = ""
685
686
687    #==========================================================================
688    # Event handlers
689    #==========================================================================
690
691    def onPopMeanChange(self):
692        """handles changes of ANOVA type:
693            - resets self.ps;
694            - updates infoc
695            - calls updateSelectorInfos()
696        runs ANOVA and sends out new data;
697        """
698        if self.anovaType == OWHypTest.StSST:
699            self.ps = Numeric.ones((3,0), Numeric.Float)
700            if self.autoUpdateSelName:
701                self.updateSelectorName()
702            if self.commitOnChange:
703                self.runANOVA()
704                self.senddata()
705            elif self.dataStructure and self.numExamples > 0:
706                self.infoc.setText('Press Commit button to start ANOVA computation.')
707            self.updateSelectorInfos()
708
709
710    def onAnovaType(self):
711        """handles changes of ANOVA type:
712            - resets self.ps;
713            - calls updateSelectorBox()
714            - updates infoc
715            - calls updateSelectorInfos()
716        runs ANOVA and sends out new data;
717        """
718        # store info whether we have tested for interaction effect
719        self._interaction = self.anovaType == OWHypTest.St2ABI
720        self.ps = Numeric.ones((3,0), Numeric.Float)
721        self.updateSelectorBox()
722        if self.autoUpdateSelName:
723            self.updateSelectorName()
724        if self.commitOnChange:
725            self.runANOVA()
726            self.senddata()
727        elif self.dataStructure and self.numExamples > 0:
728            self.infoc.setText('Press Commit button to start ANOVA computation.')
729        self.updateSelectorInfos()
730
731
732    def onSelectionChange(self):
733        """handles changes in example selector checkboxes;
734        sends out new data;
735        """
736        if self.autoUpdateSelName:
737            self.updateSelectorName()
738        if self.commitOnChange:
739            self.senddata()
740
741
742    def onAlphaChange(self, selectorIdx):
743        """handles changes in example selector alphas;
744        prints number of selected examples for individual selectors and sends out new data;
745        """
746        if self.autoUpdateSelName:
747            self.updateSelectorName()
748        if self.commitOnChange:
749            self.senddata()
750        self.updateSelectorInfos(selectorIdx)
751
752
753    def onAutoUpdateSelNameChange(self):
754        """handles clicks on auto update selector name checkbox
755        """
756        self.leSelectorName.setReadOnly(self.autoUpdateSelName)
757
758           
759    def onSendNotSelectedChange(self):
760        """handles clicks on sendNotSelectedData checkbox
761        """
762        if self.commitOnChange:
763            self.senddata()
764
765    def onSendProbabilitiesChange(self):           
766        """handles clicks on show p-values checkbox
767        """
768        if self.commitOnChange:
769            self.senddata()
770           
771    def onCommit(self, commit=True):
772        """handles Commit clicks; runs ANOVA (if not already computed) and sends out data;
773        """
774        if commit:
775            if self.dataStructure:
776                if self.ps.shape[1] == 0:
777                    self.runANOVA()
778                self.senddata()
779            self.updateSelectorInfos()
780
781
782if __name__=="__main__":
783    from . import OWDataFiles
784    from Orange.orng import orngSignalManager
785    signalManager = orngSignalManager.SignalManager(0)
786    a=QApplication(sys.argv)
787    ow=OWHypTest(signalManager = signalManager)
788    a.setMainWidget(ow)
789    ow.show()
790    ds = OWDataFiles.OWDataFiles(signalManager = signalManager)
791##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\potato.sub100")
792##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\potato.sub1000")
793##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\DictyChipData_BR_ACS_10_yakApufA")
794##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\DictyChipData_BR_ACS_10_yakApufA_time0")
795##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\DictyChipData_BR_ACS_10_yakApufA_time0_swappedAB")
796##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\DictyChipData_BR_ACS")
797
798##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\_one-sample t-test")
799##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\_factor A")
800##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\_factor B")
801##    ds.loadData(r"C:\Documents and Settings\peterjuv\My Documents\Orange\ANOVA\_factors A and B")
802
803    signalManager.addWidget(ow)
804    signalManager.addWidget(ds)
805    signalManager.setFreeze(1)
806    signalManager.addLink(ds, ow, 'Structured Data', 'Structured Data', 1)
807    signalManager.setFreeze(0)
808    a.exec_loop()
809    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.