source: orange-bioinformatics/orangecontrib/bio/widgets/prototypes/OWHypTest.py @ 1873:0810c5708cc5

Revision 1873:0810c5708cc5, 40.1 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Moved '_bioinformatics' into orangecontrib namespace.

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