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

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

Moved '_bioinformatics' into orangecontrib namespace.

Line 
1"""<name>GeneMANIA</name>
2<icon>icons/GeneMANIA.svg</icon>
3"""
4
5from __future__ import absolute_import
6
7import os, sys
8import multiprocessing
9import random
10
11import Orange
12from Orange.OrangeWidgets import OWGUI
13from Orange.OrangeWidgets.OWWidget import *
14
15from .. import obiGeneMania
16
17class BarItemDelegate(QStyledItemDelegate):
18    BarRole = OWGUI.OrangeUserRole.next() 
19    BarForegroundRole = OWGUI.OrangeUserRole.next()
20   
21    def __init__(self, parent, brush=QBrush(QColor(255, 170, 127)), scale=(0.0, 1.0)):
22        QStyledItemDelegate.__init__(self, parent) 
23        self.brush = brush
24        self.scale = scale
25       
26       
27    def paint(self, painter, option, index):
28        painter.save()
29        qApp.style().drawPrimitive(QStyle.PE_PanelItemViewRow, option, painter)
30        qApp.style().drawPrimitive(QStyle.PE_PanelItemViewItem, option, painter)
31        rect = option.rect
32        try:
33            val, ok = index.data(self.BarRole).toDouble()
34            if ok:
35                color = index.data(self.BarForegroundRole)
36                if color.isValid() and color.type() == QVariant.Color:
37                    brush = QBrush(color)
38                else:
39                    brush = self.brush
40                   
41                minval, maxval = self.scale
42                val = (val - minval) / (maxval - minval)
43                painter.save()
44                if option.state & QStyle.State_Selected:
45                    painter.setOpacity(0.75)
46                painter.setBrush(brush)
47                painter.drawRect(rect.adjusted(1, 1, max(-rect.width() * (1.0 - val) - 2, - rect.width() + 2), -2))
48                painter.restore()
49        except Exception, ex:
50            print >> sys.stderr, ex
51           
52        text = index.data(Qt.DisplayRole).toString()
53        if text:
54            align, ok = index.data(Qt.TextAlignmentRole).toInt()
55            if not ok:
56                align = Qt.AlignVCenter | Qt.AlignLeft
57               
58            painter.drawText(option.rect, align, text)
59        painter.restore()
60       
61       
62    def sizeHint(self, option, index):
63        size = QStyledItemDelegate.sizeHint(self, option, index)
64        metrics = QFontMetrics(option.font)
65        height = metrics.lineSpacing() + 2
66        return QSize(size.width(), height)
67   
68
69class OWGeneMania(OWWidget):
70    contextHandlers = {"": DomainContextHandler("", ["selectedOrganismIndex", "selectedGeneAttrIndex", "genesInColumns"])}
71    settingsList = ["serverAddress", "selectedOrganismIndex", "selectedGeneAttrIndex", "genesInColumns", "selectedMethodIndex", "resultCount"]
72    def __init__(self, parent=None, signalManager=None, name="GeneMANIA"):
73        OWWidget.__init__(self, parent, signalManager, name, wantMainArea=True)
74       
75        self.inputs = [("Input Genes", ExampleTable, self.setData)]
76        self.outputs = [("Network", Orange.network.Graph, Default), ("Items", ExampleTable)]
77       
78        self.serverAddress = obiGeneMania.DEFAULT_SERVER
79        self.selectedOrganismIndex = 0
80        self.selectedGeneAttrIndex = 0
81        self.genesInColumns = False
82        self.selectedMethodIndex = 1
83        self.resultCount = 10
84       
85        self.data = None
86       
87        self.loadSettings()
88       
89        #####
90        # GUI
91        #####
92       
93        self.organisms = [("H. sapiens", "9606"),
94                          ("A. thaliana", "3702"),
95                          ("C. elegans", "6239"),
96                          ("D. melanogaster", "7227"),
97                          ("M. musculus", "10090"),
98                          ("S. cerevisiae", "4932")]
99       
100        box = OWGUI.widgetBox(self.controlArea, "Info", addSpace=True)
101        self.info = OWGUI.widgetLabel(box, "No genes on input.")
102        self.infoState = OWGUI.widgetLabel(box, "")
103        self.infoState.setWordWrap(True)
104       
105        box = OWGUI.widgetBox(self.controlArea, "GeneMANIA server address", addSpace=True)
106        OWGUI.lineEdit(box, self, "serverAddress")
107       
108        self.organismCombo = OWGUI.comboBox(self.controlArea, self, "selectedOrganismIndex", "Organims",
109                                            items=[t[0] for t in self.organisms],
110                                            tooltip="Select the organism",
111                                            callback=self.updateInfo)
112       
113        box = OWGUI.widgetBox(self.controlArea, "Genes", addSpace=True)
114        self.geneAttrCombo = OWGUI.comboBox(box, self, "selectedGeneAttrIndex",
115                                            tooltip="Select the attribute with gene names",
116                                            callback=self.updateInfo)
117       
118        cb = OWGUI.checkBox(box, self, "genesInColumns", "Use attribute names",
119                            tooltip="Use attribute names as gene names instead.",
120                            callback=self.updateInfo,
121                            disables=[(-1, self.geneAttrCombo)])
122        cb.makeConsistent()
123        self.methodItems = [("Automatic relevance", "automatic_relevance"),
124                            ("Automatic", "automatic"),
125                            ("Biological process", "bp"),
126                            ("Molecular function", "mf"),
127                            ("Cellular component", "cc"),
128                            ("Average", "average"),
129                            ("Average category", "average_category")]
130       
131        toolTips = ["Assigned based on query genes",
132                    "Automatically selected weighting method",
133                    "Biological process based",
134                    "Molecular function based",
135                    "Cellular component based",
136                    "Equal by data type",
137                    "Equal by network"]
138       
139        OWGUI.comboBox(self.controlArea, self, "selectedMethodIndex", 
140                       box="Net combining method",
141                       items=[t[0] for t in self.methodItems],
142                       callback=self.updateInfo
143                       )
144       
145        OWGUI.spin(self.controlArea, self, "resultCount", 1, 100, 
146                   box="Number of gene results",
147                   callback=self.updateInfo
148                   )
149       
150        self.geneManiaLinkLabel = OWGUI.widgetLabel(self.controlArea, "")
151        self.geneManiaLinkLabel.setOpenExternalLinks(True)
152        OWGUI.button(self.controlArea, self, "Retrieve", callback=self.retrieve)
153        OWGUI.rubber(self.controlArea)
154       
155        self.networksReport = QTreeView()
156        self.networksReport.setEditTriggers(QTreeView.NoEditTriggers)
157        box = OWGUI.widgetBox(self.mainArea, "Networks")
158        box.layout().addWidget(self.networksReport)
159       
160        self.resize(100, 200)
161       
162        self.connect(self, SIGNAL("widgetStateChanged(QString, int, QString)"), self.updateInfo)
163
164
165    def setData(self, data=None):
166        self.error([0,1,2])
167        self.warning([0])
168        self.data = data
169        self.closeContext("")
170        self.geneAttrCombo.clear()
171        self.candidateGeneAttrs = []
172        self.selectedGeneAttrIndex = 0
173       
174        if data is not None:
175            self.candidateGeneAttrs = data.domain.variables + data.domain.getmetas().values()
176            self.candidateGeneAttrs = [attr for attr in self.candidateGeneAttrs if attr.varType != orange.VarTypes.Continuous]
177            self.geneAttrCombo.addItems([attr.name for attr in self.candidateGeneAttrs])
178            self.openContext("", data)
179        else:
180            self.send("Network", None)
181            self.send("Items", None)
182           
183        self.updateInfo()
184           
185    def onGeneSourceSelection(self):
186        genes = self.getSelectedGenes()
187        self.info.setText("")
188       
189    def updateInfo(self, *args):
190        if self.data is not None:
191            genes = self.getSelectedGenes()
192            htmlState = self.widgetStateToHtml()
193            self.info.setText("%i genes on input." % len(genes))
194            self.infoState.setText(htmlState)
195        else:
196            self.info.setText("No data on input.")
197            self.infoState.setText("")
198       
199        if self.data:
200            org = self.organisms[self.selectedOrganismIndex][1]
201            genes = self.getSelectedGenes()
202            method = self.methodItems[self.selectedMethodIndex][1]
203            conn = obiGeneMania.Connection(self.serverAddress)
204            self.geneManiaLinkLabel.setText('<a href="%s">View network in external browser</a>' % conn._queryPage(org, genes, method, self.resultCount))
205        else:
206            self.geneManiaLinkLabel.setText('')
207       
208    def getSelectedGenes(self):
209        if self.data is not None:
210            if self.genesInColumns:
211                names = [attr.name for attr in self.data.domain.attributes]
212            else:
213                attr = self.candidateGeneAttrs[self.selectedGeneAttrIndex]
214                names = set([str(ex[attr]) for ex in self.data if not ex[attr].isSpecial()])
215            return names
216        else:
217            return []
218       
219       
220    def retrieve(self):
221        org = self.organisms[self.selectedOrganismIndex][1]
222        genes = self.getSelectedGenes()
223        method = self.methodItems[self.selectedMethodIndex][1]
224        self.error([0, 1, 2])
225        self.warning([0])
226       
227        conn = obiGeneMania.Connection(self.serverAddress)
228        errorCode, invalid, genes = conn.validate(org, genes)
229        if not genes:
230            self.error(2, "No valid gene names!")
231            self.net, self.netTab = None, None
232            self.updateNetworksReport()
233            return
234        elif invalid:
235            self.warning(0, "There are invalid gene names on input:\n%s" % (",".join(invalid[:5])) + (" ..." if len(invalid) > 5 else ""))
236           
237#        print conn._queryPage(org, genes, method, self.resultCount)
238        call = self.asyncCall(conn.retrieveXML, (org, genes), {"m": method, "r": self.resultCount})
239        call()
240       
241        self.progressBarInit()
242        self.setEnabled(False)
243        try:
244#            net = conn.retrieve(org, genes, m=method, r=self.resultCount)
245            xml = call.get_result(processEvents=True)
246            # Parse the xml in the main thread (pyexpat frequently crashes in
247            # Qt's threading model)
248            dom = obiGeneMania.minidom.parseString(xml)
249            net = obiGeneMania.parse(dom)
250            items = net.items()
251        except Exception, ex:
252            self.error(0, "Failed to retrieve network from server!\n" + str(ex))
253            sys.excepthook(*sys.exc_info())
254            net = None
255            items = None
256       
257        if net:
258            try:
259                self.netTab = obiGeneMania.parsePage(conn._page)
260            except Exception:
261                self.error(1, "Failed to parse network tabs!\n" + str(ex))
262                self.netTab = None
263        else:
264            self.netTab = None
265        self.setEnabled(True)
266        self.progressBarFinished()
267       
268        self.net = net
269       
270        self.send("Network", net)
271        self.send("Items", items)
272       
273        self.updateNetworksReport()
274       
275    def updateNetworksReport(self):
276        model = QStandardItemModel(self)
277        model.setHorizontalHeaderLabels(["Networks", "Weight"])
278        root = model.invisibleRootItem()
279        def toFloat(s):
280            if s.strip().endswith("%"):
281                return float(s.strip()[:-1])
282            else:
283                return float(s)
284           
285        if self.netTab and self.net and self.net.links:
286            for group in self.netTab:
287                groupItem = QStandardItem(group.name)
288                groupWeightItem = QStandardItem("%.2f %%" % toFloat(group.weight))
289                groupWeightItem.setData(QVariant(toFloat(group.weight) / 100.0), BarItemDelegate.BarRole)
290                root.appendRow([groupItem, groupWeightItem])
291                for net in group.networks:
292                    netItem = QStandardItem(net.name)
293                    netItem.setData(QVariant(net.description), Qt.ToolTipRole)
294                   
295                    netWeightItem = QStandardItem("%.2f %%" % toFloat(net.weight))
296                    netWeightItem.setData(QVariant(toFloat(net.weight) / 100.0), BarItemDelegate.BarRole)
297                    netWeightItem.setData(QVariant(net.description), Qt.ToolTipRole)
298                    groupItem.appendRow([netItem, netWeightItem])
299               
300        self.networksReport.setModel(model)
301        self.networksReport.setItemDelegateForColumn(1, BarItemDelegate(self))
302        self.networksReport.resizeColumnToContents(0)
303           
304       
305if __name__ == "__main__":
306    app = QApplication(sys.argv)
307    w = OWGeneMania()
308    w.show()
309    data = orange.ExampleTable("../../../doc/datasets/brown-selected.tab")
310    w.setData(orange.ExampleTable(data[:3]))
311    app.exec_()
312    w.saveSettings()
313       
314       
Note: See TracBrowser for help on using the repository browser.