source: orange-bioinformatics/Orange/bioinformatics/widgets/prototypes/OWEpistasisAnalysis.py @ 1625:cefeb35cbfc9

Revision 1625:cefeb35cbfc9, 14.5 KB checked in by mitar, 2 years ago (diff)

Moving files around.

Line 
1"""
2<name>Epistasis Analysis</name>
3<description>Epistasis analysis on microaray data</description>
4<icon>icons/EpistasisAnalysis.png</icon>
5<priority>1200</priority>
6"""
7
8import orange, OWGUI, statc, math
9#from qt import *
10#from qtcanvas import *
11from OWWidget import *
12from OWDataFiles import DataFiles, ExampleSelection
13
14##############################################################################
15# parameters that determine the canvas layout
16
17# constants for canvas drawing
18
19canvasW = 220 # canvas width and height
20canvasB = 30  # border
21circleR = (canvasW - 2 * canvasB)/2.
22
23##############################################################################
24# main class
25
26class OWEpistasisAnalysis(OWWidget):   
27    settingsList = ['distype']
28
29    def __init__(self, parent=None, signalManager = None):
30        OWWidget.__init__(self, parent, signalManager, 'Epistasis Analysis') 
31       
32        self.inputs = [("Examples", ExampleTable, self.dataset, Multiple), ("Structured  Data", DataFiles, self.chipdata, 1)]
33        self.outputs = [("Gene Selection", ExampleSelection), ("Examples A->B", ExampleTable), ("Examples B->A", ExampleTable), ("Examples A||B", ExampleTable)]
34
35        self.data = []
36        self.selectedFile = None
37        self.A, self.B, self.AB = (None, None, None)
38        self.epiA, self.epiB, self.para = (0, 0, 0)
39        self.distype = 0
40        #set default settings
41        self.loadSettings()
42
43        # Selection of data files
44        box = OWGUI.widgetBox(self.controlArea, "Data files", addSpace=True)
45#        box = QVButtonGroup("Data Files", self.controlArea)
46#        self.fileLB = OWGUI.listBox(box, self, "selectedFile", "files",
47#                                    tooltip="Select example table",
48##                                    callback=self.fileSelectionChanged,
49#                                    selectionMode=QListWidget.SingleSelection,
50#                                    )
51#        self.connect(self.fileLB, SIGNAL("currentRowChanged(int)"), self.fileSelectionChanged)
52        self.fileLB = QListWidget()
53#        self.fileLB.setMaximumWidth(10)
54        self.connect(self.fileLB, SIGNAL("highlighted(int)"), self.fileSelectionChanged)
55#        self.connect(self.fileLB, SIGNAL("selected(int)"), self.setFileReferenceBySelection)
56        box.layout().addWidget(self.fileLB)
57       
58        hbox = OWGUI.widgetBox(box, "", orientation="horizontal")
59#        hbox = QHBox(box)
60        self.markBtns = []
61        for (i, lbl) in enumerate(["A","B","D"]):
62            btn = OWGUI.button(hbox, self, lbl,
63                               callback=lambda i=i: self.setMark(i),
64                               disabled=1)
65#            btn.setMaximumWidth(45)
66#            btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
67            self.markBtns.append(btn)
68
69        # Relations, checkbox for gene selection
70        self.sbox = OWGUI.widgetBox(self.controlArea, "Relations (Gene Selection)")
71#        self.sbox = QVButtonGroup("Relations (Gene Selection)", self.controlArea)
72        self.selChkbox = []
73        self.cbinfo = (("epiA", "A -> B", "Gene B is epistatic to gene A"),
74                       ("epiB", "B -> A", "Gene A is epistatic to gene B"),
75                       ("para", "A || B", "Genes A and B are on parallel pathways"))
76        for (i, cb) in enumerate(self.cbinfo):
77            cb = OWGUI.checkBox(self.sbox, self, cb[0], cb[1],
78                                tooltip=cb[2],
79                                callback=self.filterSelectionChanged)
80            self.selChkbox.append(cb)
81        self.infochi = OWGUI.widgetLabel(self.sbox, "") #QLabel(self.sbox, '')
82        self.sbox.setDisabled(1)
83
84        OWGUI.radioButtonsInBox(self.controlArea, self, "distype", ["Average By Gene", "Average By Measurement"],
85                                box="Distance", tooltips=None, callback=self.analysis)
86
87        # scene
88        self.scene = QGraphicsScene()
89        self.sceneView = QGraphicsView()
90        self.sceneView.setScene(self.scene)
91        self.scene.setSceneRect(QRectF(0, 0, canvasW, canvasW))
92        self.mainArea.layout().addWidget(self.sceneView)
93       
94        # canvas
95#        self.canvas = QCanvas()
96#        self.layout = QVBoxLayout(self.mainArea)
97#        self.canvasView = QCanvasView(self.canvas, self.mainArea)
98#        self.canvas.resize(canvasW, canvasW)
99#        self.layout.add(self.canvasView)
100
101        self.resize(420,350)
102
103    ##########################################################################
104    # handling of input/output signals
105
106    def checkDomain(self, data, selection = None):
107       
108        cl = clo = data.domain.classVar
109        if cl:
110            if selection:
111                cl = orange.RemoveUnusedValues(cl, selection, removeOneValued = 1)
112            else:
113                cl = orange.RemoveUnusedValues(cl, data, removeOneValued = 1)
114
115        # Construct a new domain only if the class has changed
116        # (ie to lesser number of values or to one value (alias None))
117        if cl != clo:
118            domain = orange.Domain(data.domain.attributes, cl)
119            metas = data.domain.getmetas()
120            for key in metas:
121                domain.addmeta(key, metas[key])
122            return domain
123        else:
124            return None
125       
126    def dataset(self, data, id):
127        ids = [d.id for d in self.data]
128        if not data:
129            if id in ids:
130                k = ids.index(id)
131                del self.data[k]
132                self.fileLB.takeItem(k)
133#                self.fileLB.removeItem(k)
134        else:
135            # check if the same length
136            if data.domain.classVar:
137                domain = self.checkDomain(data)
138                if domain:
139                    data = orange.ExampleTable(domain, data)
140            data.setattr("id", id)
141            data.setattr("marker", None)
142            if id in ids:
143                data.id = id
144                indx = ids.index(id)
145                self.data[indx] = data
146                self.fileLB.takeItem(indx)
147                self.fileLB.insertItem(indx, self.createListItem(data))
148#                self.fileLB.changeItem(self.createListItem(data), indx)
149            else:
150                if len(self.data) < 3:
151                    data.setattr("marker", len(self.data)) #### REMOVE !!!
152                self.fileLB.addItem(self.createListItem(data))
153                self.data.append(data)
154               
155                if len(self.data) >= 3: #### REMOVE !!!
156                    self.analysis()
157
158    def chipdata(self, data):
159        self.data = [] # XXX should only remove the data from the same source, use id in this rutine
160        self.fileLB.clear()
161        if not data:
162            for i in self.canvas.allItems():
163                i.setCanvas(None)
164            self.canvas.update()
165            return
166        indx = 0
167        for (strainname, ds) in data:
168            for d in ds:
169                self.dataset(d, indx)
170                indx += 1
171
172    ##########################################################################
173    # handle events
174
175    # mark button pressed, mark the file appropriately
176    def setMark(self, mark):
177        sel = self.selectedFile
178        # remove this mark from previously marked file
179        marks = [d.marker for d in self.data]
180        if mark in marks:
181            indx = marks.index(mark)
182            self.data[indx].setattr("marker", None)
183            self.fileLB.takeItem(indx)
184            self.fileLB.insertItem(indx, self.createListItem(self.data[indx]))
185#            self.fileLB.changeItem(self.createListItem(self.data[indx]), indx)
186        self.data[sel].setattr("marker", mark)
187        self.fileLB.takeItem(sel)
188        self.fileLB.insertItem(sel, self.createListItem(self.datap[sel]))
189#        self.fileLB.changeItem(self.createListItem(self.data[sel]), sel)
190        self.analysis() # do the analysis (if all three selections are made)
191
192    # user has selected a different file from the file list
193    def fileSelectionChanged(self, sel):
194        self.selectedFile = sel
195        for btn in self.markBtns:
196            btn.setEnabled(True)
197
198    # user has selected a different file
199    def filterSelectionChanged(self):
200        pass
201       
202    def createListItem(self, data):
203        pixmap = QPixmap(QSize(14, 14))
204#        pixmap.resize(14,13)
205        pixmap.fill(Qt.white)
206       
207        if data.marker is not None:
208            painter = QPainter()
209            painter.begin(pixmap)
210            painter.setPen(Qt.black)
211            painter.setBrush(Qt.white)
212            painter.drawRect(0, 0, 13, 13)
213            c = ['A','B','D'][data.marker]
214            painter.drawText(3, 11, c)
215            painter.end()
216           
217        listItem = QListWidgetItem(QIcon(pixmap), data.name)
218#        listItem = QListBoxPixmap(pixmap)
219#        listItem.setText(data.name)
220        return listItem
221##        return QListBoxText(text)
222
223    ##########################################################################
224    # epistasis analysis
225
226    import math
227
228    def analysis(self):
229        markers = [d.marker for d in self.data]
230        if len(filter(lambda x: x is not None, markers)) < 3:
231            self.sbox.setDisabled(True)
232            for item in self.scene.items():
233                self.scene.removeItem(item)
234#                i.setCanvas(None)
235#            self.canvas.update()
236            return
237        self.sbox.setEnabled(True)
238
239        pa, pb, pab = [self.data[markers.index(x)] for x in range(3)]
240       
241        pb = orange.ExampleTable(pa.domain, pb)
242        pab = orange.ExampleTable(pa.domain, pab)
243       
244        dist = orange.ExamplesDistanceConstructor_Euclidean(pa, normalize=False)
245
246        ave = [0]*3
247        vote = [0]*3
248        genevote = []
249        for g in range(len(pa)):
250            d = [dist(pb[g], pab[g]), dist(pa[g], pab[g]), dist(pa[g], pb[g])]
251            voteindx = d.index(min(d))
252            vote[voteindx] += 1
253            genevote.append(voteindx)
254            if self.distype == 1:
255                for i in range(3):
256                    d[i] = d[i] * d[i]
257            for i in range(3):
258                ave[i] += d[i]
259        if self.distype == 1:
260            ave = [math.sqrt(x) / len(pa) for x in ave]
261        else:
262            ave = [x/len(pa) for x in ave]
263
264        # compute Chi^2 statistics,
265        # update the interface (report on results)
266        for i in range(3):
267            self.selChkbox[i].setText(self.cbinfo[i][1] + "  (%d genes)" % vote[i])
268        p = statc.chisquare([len(pa) / 3.] * 3, vote)[1]
269        self.infochi.setText('Chi Square: ' + ['p = %6.4f' % p, 'p < 0.0001'][p < 0.0001])
270
271        self.setAnalysisPlot(ave)
272        self.senddata(genevote)
273
274    def setAnalysisPlot(self, ds):
275        def plotDot(x, y, w=10, z=10):
276            dot = QGraphicsEllipseItem(x, y, w, w, self.scene)
277#            dot = QCanvasEllipse(w, w, self.canvas)
278            dot.setBrush(QBrush(Qt.black))
279            dot.setZValue(z)
280#            dot.setX(x); dot.setY(y); dot.setZ(z)
281            dot.show()
282           
283        def plotLine(x0, y0, x1, y1, w=2, z=10, color=Qt.black):
284            line = QGraphicsLineItem(x0, y0, x1, y1, self.scene)
285#            line = QCanvasLine(self.canvas)
286#            line.setPoints(x0, y0, x1, y1)
287            line.setPen(QPen(color, w))
288#            line.setZ(10)
289            line.setZValue(10)
290            line.show()
291           
292        def plotText(x, y, text, xoffset=0):
293            t = QGraphicsSimpleTextItem("", self.scene)
294#            t = QCanvasText(self.canvas)
295#            t.setText(text)
296            xw = t.boundingRect().width()
297            t.setPos(QPointF(x+xw*xoffset, y))
298            t.setZValue(20)
299#            t.setX(x+xw*xoffset); t.setY(y); t.setZ(20)
300            t.show()       
301
302        for item in self.scene.items():
303            self.scene.removeItem(item)
304
305        s = sum(ds)/2.
306        K = math.sqrt( s * reduce(lambda x,y: x*y, map(lambda x: s-x, ds)) )
307        R = reduce(lambda x,y: x*y, ds) / (4 * K)
308        scale = circleR / R
309        yab = canvasB + circleR - scale * math.sqrt(R**2 - (ds[2]/2)**2)
310        xa = canvasB + circleR - scale * ds[2]/2
311        xb = canvasB + circleR + scale * ds[2]/2
312        h = 2*K/ds[2]
313        yd = yab + scale * h
314        xd = xa + scale * math.sqrt(max(ds[0], ds[1])**2 - h**2)
315
316        # plot a circle
317        c = QGraphicsEllipseItem(0, 0, circleR*2, circleR*2, self.scene)
318#        c = QCanvasEllipse(circleR*2, circleR*2, self.canvas)
319        c.setBrush(QBrush(QColor(240,240,240)))
320        c.setPos(canvasB+circleR, canvasB+circleR)
321        c.setZValue(0)
322#        c.setX(canvasB+circleR); c.setY(canvasB+circleR); c.setZ(0)
323        c.show()
324
325        # plot triangle dots, line, ...
326        plotDot(xa, yab)
327        plotDot(xb, yab)
328        plotDot(xd, yd)
329
330        plotLine(xa, yab, xb, yab, color=Qt.red)
331        plotLine(xa, yab, xd, yd)
332        plotLine(xb, yab, xd, yd)
333
334        plotText(xa+(xb-xa)/2, yab-15, "%6.4f" % ds[2], xoffset=-0.5)
335        ymid = yab+(yd-yab)/2
336        plotText(xa+(xd-xa)/2-3, ymid, "%6.4f" % max(ds[0], ds[1]), xoffset=-1)
337        plotText(xd+(xb-xd)/2+3, ymid, "%6.4f" % min(ds[0], ds[1]))
338
339        # edge labels
340        markers = [d.marker for d in self.data]
341        labels = [self.data[markers.index(x)].name for x in range(3)]
342        plotText(xd, yd+8, labels[2], xoffset=-0.5)
343        plotText(xa, yab-20, labels[ds[:-1].index(min(ds[:-1]))], xoffset=-0.67)
344        plotText(xb, yab-20, labels[ds[:-1].index(max(ds[:-1]))], xoffset=-0.33)
345
346        self.canvas.update()
347
348    def senddata(self, genevotes):
349        def sendkeyeddata(channel, key):
350            for i in range(3):
351                d = datasets[i].select(genevotes, key)
352                d.name = datasets[i].name
353                self.send(channel, d, i)
354        markers = [d.marker for d in self.data]
355        datasets = [self.data[markers.index(x)] for x in range(3)]
356        channels= ["Examples A->B", "Examples B->A", "Examples A||B"]
357        for c in channels:
358            for i in range(3): # this should be excluded, repear in heat map
359                self.send(c, None, i)
360        for (i,ch) in enumerate(channels):
361            sendkeyeddata(ch, i)
362
363##################################################################################################
364# test script
365
366if __name__=="__main__":
367    import orange
368    a = QApplication(sys.argv)
369    ow = OWEpistasisAnalysis()
370    a.setMainWidget(ow)
371
372    ow.show()
373    names = ['wt1', 'wt2', 'wt3', 'wt4']
374##    names = [r'chipdata/pufA/pufA1.1.raw.tab', r'chipdata/yakA/yakA1.1.raw.tab', r'chipdata/yakApufA/yakApufA1.1.raw.tab', r'chipdata/yakApufA/yakApufA1.1.raw.tab']
375    for i, s in enumerate(names): 
376        d = orange.ExampleTable(s); d.name = s
377        ow.dataset(d, i)
378##    ow.dataset(None, 2)
379
380    a.exec_loop()
381    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.