source: orange-bioinformatics/widgets/prototypes/OWHypTest.py @ 972:bfb2c971bb0e

Revision 972:bfb2c971bb0e, 39.9 KB checked in by markotoplak, 5 years ago (diff)

bioinformatics: moved some widgets, which cannot be imported, to prototypes

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