source: orange-bioinformatics/_bioinformatics/widgets/prototypes/OWEpistasisAnalysis.py @ 1643:2cfa80dac3d3

Revision 1643:2cfa80dac3d3, 14.6 KB checked in by mitar, 2 years ago (diff)

Fixing some imports. Marking widgets as prototypes.

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