source: orange-bioinformatics/orangecontrib/bio/widgets/OWBioMart.py @ 1874:b3e32cc5cf6f

Revision 1874:b3e32cc5cf6f, 39.2 KB checked in by Ales Erjavec <ales.erjavec@…>, 6 months ago (diff)

Added new style widget meta descriptions.

RevLine 
[1462]1"""<name>BioMart</name>
[1190]2<description>Query BioMart service</description>
3<contact>Ales Erjavec (ales.erjavec(@at@)fri.uni-lj.si</contact>
[1302]4<priority>2010</priority>
[1726]5<icon>icons/BioMart.svg</icon>
[1190]6"""
7
[1632]8from __future__ import absolute_import
[1190]9
10import sys, os
11import traceback
[1310]12import warnings
[1302]13import socket
[1190]14from collections import defaultdict
[1302]15import itertools
16
[1874]17import Orange
18
[1632]19from Orange.OrangeWidgets import OWConcurrent
20from Orange.OrangeWidgets.OWWidget import *
21
22from .. import obiBioMart
23from ..obiBioMart import *
24
[1874]25NAME = "BioMart"
26DESCRIPTION = "Query BioMart service"
27ICON = "icons/BioMart.svg"
28PRIORITY = 2010
29
30INPUTS = [("Input ids", Orange.data.Table, "setData")]
31OUTPUTS = [("Example Table", Orange.data.Table)]
32
33REPLACES = ["_bioinformatics.widgets.OWBioMart.OWBioMart"]
34
35
[1632]36socket.setdefaulttimeout(60)
[1874]37
38
[1190]39def is_hidden(tree):
40    return getattr(tree, "hidden", "false") != "false" or getattr(tree, "hideDisplay", "false") != "false"
41
[1302]42class Control(object):
43    """ Base mixin class for query GUI widgets
44    """
45    def __init__(self, tree, dataset, master):
46        """
47            :param tree: configuration element
48            :type tree: obiBioMart.ConfigurationNode
49            :param dataset: dataset
50            :type dataset: obiBioMart.BioMartDataset
51            :param master: main widget
52            :type master: OWBioMart
53           
54        """
55        self.tree = tree
56        self.dataset = dataset
57        self.master = master
58        self.subControls = []
59       
60        if isinstance(self, QObject):
61            self.setObjectName(tree.internalName)
62            if hasattr(tree, "description"):
63                self.setToolTip(tree.description)
64       
65    def addSubControl(self, tree, control):
66        self.subControls.append((tree, control))
67       
68    def registerDelayedCall(self, call):
69        self.master.registerDelayedCall(call)
70       
71    def pushAction(self, action):
72        self.master.pushAction(action)
73       
74    def query(self):
75        return itertools.chain(*[ctrl.query() for _, ctrl in self.subControls])
76   
77    def setControlValue(self, name, value):
78        if "." in name:
79            name, rest = name.split(".", 1)
80            controls = dict([(tree.internalName, control) for tree, control in self.subControls])
81            ctrl = controls.get("name", None)
82            if ctrl:
83                ctrl.setControlValue(rest, value)
84           
85       
[1310]86class UnknownFilter(QWidget, Control):
87    def __init__(self, tree, dataset, master, parent=None):
88        QWidget.__init__(self, parent)
89        Control.__init__(self, tree, dataset, master)
90   
[1302]91class TextFieldFilter(QLineEdit, Control):
92    """ A single edit line filter
93    """
94    def __init__(self, tree, dataset, master, parent=None):
95        QLineEdit.__init__(self, parent)
96        Control.__init__(self, tree, dataset, master)
97       
98        if hasattr(tree, "regexp"):
99            self.setValidator(QRegExpValidator(QRegExp(tree.regexp), self))
100           
101        if hasattr(tree, "defaultValue"):
102            self.setText(tree.defaultValue)
103       
104       
105    def get_filter(self):
106        return self.tree.internalName, str(self.text())
107   
108    def query(self):
109        return [("Filter", self.tree, str(self.text()))]
110   
111    def setControlValue(self, name, value):
112        self.setText(value)
113       
114       
115class IdListFilter(QWidget, Control):
116    """ Multiple ids filter
117    """
118    def __init__(self, tree, dataset, master, parent=None):
[1190]119        QWidget.__init__(self, parent)
[1302]120        Control.__init__(self, tree, dataset, master)
121        self.tree = tree
122        self.dataset = dataset
123        self.master = master
124        self.setObjectName(tree.internalName)
[1190]125       
[1302]126        self.setLayout(QGridLayout())
127        self.textWidget = QPlainTextEdit() #TODO: Subclass to recieve drop events from item model views
128        self.layout().addWidget(self.textWidget, 0, 0, 1, 1)
[1190]129       
[1302]130    def value(self):
131        """ Return filter value for use in a query
132        """
133        return str(self.textWidget.toPlainText()).split()
134   
135    def get_filter(self):
136        return self.tree.internalName, self.value()
137   
138    def query(self):
139        return [("Filter", self.tree, self.value())]
140   
141    def setControlValue(self, name, value):
142        if type(value) == list:
143            value = "\n".join(value)
144        self.textWidget.setPlainText(value)
145           
146   
147class RadioBooleanFilter(QWidget, Control):
148    """ Boolean filter (Only/Exclude)
149    """
150    def __init__(self, tree, dataset, master, parent=None):
151        QWidget.__init__(self, parent)
152        Control.__init__(self, tree, dataset, master)
[1190]153       
[1302]154        self.setLayout(QVBoxLayout())
155        self.buttonGroup = QButtonGroup(self)
156        self.values = []
157        for i, option in enumerate(tree.subelements_top("Option")):
158            rb = QRadioButton(option.displayName, self)
159            self.buttonGroup.addButton(rb)
160            self.buttonGroup.setId(rb, i)
161            self.layout().addWidget(rb)
162            self.values.append(option.value)
163        self.buttonGroup.button(0).setChecked(True)
164           
165    def value(self):
166        return {"excluded": "%i" % self.buttonGroup.checkedId()}
[1190]167   
[1302]168    def get_filter(self):
169        return self.tree.internalName, self.value()
[1190]170   
[1302]171    def query(self):
172        return [("Filter", self.tree, self.value())]
173   
174    def setControlValue(self, name, value):
175        for i, v in enumerate(self.values):
176            if v == value:
177                button = self.buttonGroup.button(i)
178                button.setChecked(True)
179                break
180               
181               
182class DropDownFilter(QComboBox, Control):
183    """ List menu filter
184    """
185    def __init__(self, tree, dataset, master, parent=None):
186        QComboBox.__init__(self, parent)
187        Control.__init__(self, tree, dataset, master)
188       
189        self.options = []           
190        self.selectedIndex = 0
191       
192        if getattr(tree, "graph", "0") == "1":
193            self.setOptions(tree.subelements("Option"))
194        else:
195            self.setOptions(tree.subelements_top("Option"))
196               
197        self.connect(self, SIGNAL("currentIndexChanged(int)"), self.onIndexChange)
[1190]198       
199    def setOptions(self, options):
[1302]200        self.options = []
201        self.blockSignals(True)
[1190]202        self.clear()
203        for option in options:
[1302]204            self.addItem(option.displayName)
205            self.options.append(option)
206        self.selectedIndex = 0
207        self.blockSignals(False)
208        self.registerDelayedCall(lambda: self.onIndexChange(0))
209       
210    def onIndexChange(self, index):
211        if self.options:
212            option = self.options[index]
213            self.selectedIndex = index
214            pushActions = option.subelements_top("PushAction")
215            for action in pushActions:
216                self.master.pushAction(action)
217           
218    def value(self):
219        option = self.options[self.selectedIndex]
220        return option.value
221   
222    def query(self):
223        return [("Filter", self.tree, self.value())]
224   
225    def setControlValue(self, name, value):
226        for i, option in enumerate(self.options):
227            if option.value == value:
228                self.setCurrentIndex(i)
[1190]229               
[1302]230   
231#class GraphDropDownFilter(QComboBox, Control):
232#    """ Tree menu filter
233#    """
234#    def __init__(self, tree, dataset, master, parent=None):
235#        QComboBox.__init__(self, parent)
236#        Control.__init__(self, tree, dataset, master)
237#       
238#        self.options = []
239#        self.selectedIndex = 0
240#
241#        self.installEventFilter(self)
242#       
243#        self.setOptions(tree.subelements_top("Option"))
244#               
245##        self.connect(self, SIGNAL("currentIndexChanged(int)"), self.onIndexChange)
246#       
247#    def setOptions(self, options):
248#        self.options = list(options)
249#        self.clear()
250#        self.addItem(self.options[0].displayName)
251#        self.value = self.options[0].value
252#       
253#    def eventFilter(self, obj, event):
254#        if event.type() == QEvent.MouseButtonPress:
255#            self.showMenu()
256#            return True
257#        elif event.type() == QEvent.MouseButtonRelease:
258#            return True
259#        return False
260#   
261#    def showPopup(self):
262#        return
263#   
264#    def closePopup(self):
265#        return
266#   
267#    def buildMenu(self):
268#        menu = QMenu(self)
269#       
270#        def addOption(menu, option):
271#            suboptions = list(option.subelements_top("Option"))
272#            if suboptions:
273#                submenu = menu.addMenu(option.displayName)
274#                self.connect(submenu, SIGNAL("hovered(QAction)"), self.updateLastHovered)
275#                for op in suboptions:
276#                    addOption(submenu, op)
277#            else:
278#                action = menu.addAction(option.displayName)
279#                action._value = option.value
280#               
281#        for option in self.options:
282#            addOption(menu, option)
283#       
284#        self.connect(menu, SIGNAL("hovered(QAction)"), self.updateLastHovered)
285#        self.connect(menu, SIGNAL("triggered(QAction)"), lambda action: menu.close())
286#        return menu
287#   
288#    def updateLastHovered(self, action):
289#        self.lastHovered = str(action.text())
290#        print self.lastHovered
291#    def showMenu(self):
292#        menu = self.buildMenu()
293#        action = menu.exec_(self.mapToGlobal(QPoint(0, 0)))
294#        name = str(action.text())
295#        self._value = value = action._value
296#        self.setItemText(0, name)
297#                   
298#    def query(self):
299#        return [("Filter", self.tree, self._value)]
300   
301   
302def rows(index_list):
303    return map(QModelIndex.row, index_list)
304
305
306class MultiSelectListFilter(QListView, Control):
307    """ Menu list filter with multiple selection
308    """
309    def __init__(self, tree, dataset, master, parent=None):
310        QComboBox.__init__(self, parent)
311        Control.__init__(self, tree, dataset, master)
[1190]312       
[1302]313        self.setSelectionMode(QListView.ExtendedSelection)
314        model = QStringListModel(self)
315        self.setModel(model)
316        self.setOptions(tree.subelements_top("Option"))
[1190]317       
318       
319    def setOptions(self, options):
[1302]320        self.options = []
321        for option in options:
322            self.options.append(option)
323        self.model().setStringList([option.displayName for option in self.options])
324               
325    def value(self):
326        value = []
327        for index in rows(self.selectedIndexes()):
328            value.append(self.options[index].value)
329        return ",".join(value)
330   
331    def query(self):
332        return [("Filter", self.tree, self.value())]
333   
334    def setControlValue(self, name, value):
335        if type(value) == str:
336            value = value.split(",")
337        selection = self.selectionModel()
338        for i, option in enumerate(self.options):
339            if option.value in values:
340                selection.select(self.model().index(i), QItemSelectionModel.Select)
341           
342   
343class DropDownRadioBooleanFilter(QWidget, Control):
344    """ Container for multiple boolean filters
345    """
346    def __init__(self, tree, dataset, master, parent=None):
347        QWidget.__init__(self, parent)
348        Control.__init__(self, tree, dataset, master)
[1190]349       
[1302]350        self.setLayout(QHBoxLayout())
351        self.cb = QComboBox(self)
352       
353        self.layout().addWidget(self.cb)
354       
355        rblayout = QVBoxLayout()
356        self.radioButtons = [QRadioButton("Only", self),
357                             QRadioButton("Excluded", self)
358                             ]
359       
360        for b in self.radioButtons:
361            rblayout.addWidget(b)
362           
363        self.radioButtons[0].setChecked(True)
364           
365        self.layout().addLayout(rblayout)
366       
367        self.options = []
368       
369        self.setOptions(tree.subelements_top("Option"))
370   
371    def setOptions(self, options):
372        self.cb.clear()
373        self.options = []
[1190]374        for option in options:
[1302]375            self.cb.addItem(option.displayName)
376            self.options.append(option)
[1190]377           
[1302]378        for op, rb in zip(self.options[0].subelements_top("Option"),
379                          self.radioButtons):
380            rb.setText(op.displayName)
381            rb.setChecked(getattr(op, "default", "false") == "true")
382           
383
384    def value(self):
385        return {"excluded": "0" if self.radioButtons[0].isChecked() else "1"}
386   
387    def query(self):
388        filter = self.options[self.cb.currentIndex()]
389        filter = FilterDescription(self.tree.registry, "FilterDescription", filter.attributes, filter.children)
390        return [("Filter", filter, self.value())] #"only" if self.radioButtons[0].isChecked() else "excluded")]
391   
392    def setControlValue(self, name, value):
393        for i, option in enumerate(self.options):
394            if option.internalName == name:
395                self.cb.setCurrentIndex(i)
396                if value == "Only":
397                    self.radioButtons[0].setChecked(True)
398
399
400class DropDownIdListFilter(QWidget, Control):
401    """ Container for multiple id list filters
402    """
403    def __init__(self, tree, dataset, master, parent=None):
404        QWidget.__init__(self, parent)
405        Control.__init__(self, tree, dataset, master)
[1190]406       
[1302]407        self.setLayout(QVBoxLayout())
408        self.setContentsMargins(0, 0, 0, 0)
409        self.cb = QComboBox()
410        self.idsEdit = QPlainTextEdit()
[1310]411#        self.browseButton = QPushButton("Browse ...")
[1190]412       
[1302]413        self.layout().addWidget(self.cb)
414        self.layout().addWidget(self.idsEdit)
[1310]415#        self.layout().addWidget(self.browseButton)
416#        self.layout().setAlignment(self.browseButton, Qt.AlignRight)
[1190]417       
[1302]418        self.options = []
419        self.setOptions(tree.subelements_top("Option"))
[1190]420       
421    def setOptions(self, options):
[1302]422        self.cb.clear()
423        self.options = []
[1190]424        for option in options:
[1302]425            self.cb.addItem(option.displayName)
426            self.options.append(option)
[1190]427           
428       
[1302]429    def value(self):
430        return str(self.idsEdit.toPlainText()).split()
[1190]431   
[1302]432    def query(self):
433        filter = self.options[self.cb.currentIndex()]
434        filter = FilterDescription(self.tree.registry, "FilterDescription", filter.attributes, filter.children)
435        return [("Filter", filter, self.value())]
436   
437    def setControlValue(self, name, value):
438        if type(value) == list:
439            value = "\n".join(value)
440           
441        for i, op in enumerate(self.options):
442            if name == op.internalName:
443                self.cb.setCurrentIndex(i)
444                self.idsEdit.setPlainText(value)
445   
[1190]446       
[1302]447class CollectionWidget(QGroupBox, Control):
448    NO_FLAGS = 0
449    FILTER_FLAG = 1
450    ATTRIBUTE_FLAG = 2
451    SINGLE_FILTER_FLAG = 4
452    def __init__(self, tree, dataset, master, parent=None):
453        QGroupBox.__init__(self, parent)
454        Control.__init__(self, tree, dataset, master)
455       
456        self.setFlat(True)
457#        self.setLayout(QFormLayout())
458#        self.enableCB = QCheckBox(getattr(tree, "displayName", ""), self)
459        self.attributes = []
460        self.filters = []
461       
462    def setCollection(self, tree, dataset, flags=0):
463        self.tree = tree
464        self.dataset = dataset
465        self.collectionFlags = flags
466
[1190]467   
[1302]468def isFilterCollection(tree):
469    """ In case all AttributeDescription nodes contain pointers to filters
470    (case of downstream/upstream_flank)
471    """
472    if tree.tag == "FilterCollection":
473        return True
474    return all(["pointerFilter" in desc.attributes  for desc in tree.elements("AttributeDescription")])
475
476
477class AttributeWidget(QCheckBox, Control):
478    """ Single attribute selection widget
479    """
480    def __init__(self, tree, dataset, master, parent=None):
481        QCheckBox.__init__(self, parent)
482        Control.__init__(self, tree, dataset, master)
483       
484        self.setText(getattr(tree, "displayName", ""))
485        self.setChecked(getattr(tree, "default", "false") == "true")
486       
487        if hasattr(tree, "description"):
488            self.setToolTip(tree.description)
489   
490       
491    def query(self):
492        if self.isChecked():
493            return [("Attribute", self.tree, self.isChecked())]
494        else:
495            return []
496   
497   
498    def setControlValue(self, name, value):
499        self.setChecked(value == "true")
500       
501   
502class AttributeCollectionWidget(CollectionWidget):
503    def __init__(self, tree, dataset, master, parent=None):
504        CollectionWidget.__init__(self, tree, dataset, master, parent)
505        self.setLayout(QGridLayout(self))
506        self.setCollection(tree, dataset)
507       
508    def setCollection(self, collection, dataset, flags=0):
509        CollectionWidget.setCollection(self, collection, dataset, flags)
510        self.setTitle(getattr(collection, "displayName", ""))
511       
512        if hasattr(collection, "description"):
513            self.setToolTip(collection.description)
[1190]514           
[1302]515        attributes = [attr for attr in collection.elements("AttributeDescription") if not is_hidden(attr)]
[1190]516       
[1302]517        numAttrs = max(len(attributes) / 2 + 1, 1)
518        i = 0
519        for attr in attributes:
520            if attr.is_pointer():
521                try:
522                    dataset, newattr = attr.get_pointed()
523                except ValueError, ex:
524                    newattr = None
525                   
526                if not newattr:
527                    continue
528                attr = newattr
529               
530            attr_widget = AttributeWidget(attr, self.dataset, self.master, self)
531            self.layout().addWidget(attr_widget, i % numAttrs, i / numAttrs)
532            self.addSubControl(attr, attr_widget)
533            i += 1
534           
[1190]535       
[1302]536def filterType(filter):
537    return getattr(filter, "displayType", ""), getattr(filter, "style", ""), getattr(filter, "multipleValues", "")
[1190]538
[1302]539 
540class FilterCollectionWidget(CollectionWidget):
541    def __init__(self, tree, dataset, master, parent=None):
542        CollectionWidget.__init__(self, tree, dataset, master, parent)
543        self.setLayout(QGridLayout())
544#        self.setLayout(QFormLayout())
545#        self.layout().setLabelAlignment(Qt.AlignLeft | Qt.AlignVCenter)
546#        self.layout().setFormAlignment(Qt.AlignHCenter | Qt.AlignTop)
547       
548        self.layout().setContentsMargins(5, 5, 5, 5)
549        self.layout().setColumnStretch(0, 10)
550        self.layout().setColumnStretch(1, 10)
551        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
552        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
553        self.setCollection(tree, dataset)
554       
555    def setCollection(self, collection, dataset, flags=0):
556        CollectionWidget.setCollection(self, collection, dataset, flags)
557        filters = [f for f in collection.elements("FilterDescription") if not is_hidden(f)] + \
558                  [f for f in collection.elements("AttributeDescription") if not is_hidden(f)] # in case of pointers to filters (upstream/downstream flank)
559        self.enableCB = QCheckBox(getattr(collection, "displayName", ""), self)
560       
561        if hasattr(collection, "description"):
562            self.setToolTip(collection.description)
563           
564        if len(filters) == 1 and (not hasattr(filters[0], "displayName") or \
565                getattr(filters[0], "displayName", "") == getattr(collection, "displayName", "")):
566            flags = flags | self.SINGLE_FILTER_FLAG
567           
568        i = 0
569        if not flags & self.SINGLE_FILTER_FLAG:
570            self.layout().addWidget(self.enableCB, 0, 0)
571            i += 1
572#            self.layout().addRow(self.enableCB, QWidget(self))
573           
574        for filter in filters:
575            fType = getattr(filter, "type", None)
576            if filter.is_pointer():
577                try:
578                    dataset, newfilter  = filter.get_pointed()
579                except ValueError, ex:
580                    newfilter = None
581                   
582                if not newfilter:
583                    continue
584                filter = newfilter
585                fType = getattr(filter, "type", None) if fType is None else fType
586            label, filter_widget = self.buildFilter(filter, flags, fTypeHint=fType)
587            if isinstance(label, basestring):
[1310]588                label = QLabel(label) 
589           
[1302]590            self.layout().addWidget(label,i, 0)
591            self.layout().addWidget(filter_widget, i, 1)
592            i += 1
593#            self.layout().addRow(label, filter_widget)
594            self.addSubControl(filter, filter_widget)
[1310]595        if self.layout().count() == 0:
596            self.layout().addWidget(self.enableCB, 0, 0)
[1302]597           
598           
599    def buildFilter(self, filter, flags, fTypeHint=None):
600        if flags & self.SINGLE_FILTER_FLAG:
601            label = self.enableCB
602        else:
603            label = getattr(filter, "displayName", "")
604           
605        fType = filterType(filter)
606        if fTypeHint == "drop_down_basic_filter":
607            fType = ("list", "menu", "")
608        filter_widget = None
609       
610        if fType == ("text", "", ""):
611            filter_widget = TextFieldFilter(filter, self.dataset, self.master, self)
612           
613        elif fType == ("text", "", "1"):
614            filter_widget = IdListFilter(filter, self.dataset, self.master, self)
615           
616        elif fType == ("list", "radio", ""):
617            filter_widget = RadioBooleanFilter(filter, self.dataset, self.master, self)
618           
619        elif fType == ("list", "menu", ""):
620#            if getattr(filter, "graph", "0") == "1":
621#                filter_widget = GraphDropDownFilter(filter, self.dataset, self.master, self)
622#            else:
623#                filter_widget = DropDownFilter(filter, self.dataset, self.master, self)
624            filter_widget = DropDownFilter(filter, self.dataset, self.master, self)
625           
626        elif fType == ("list", "menu", "1"):
627            filter_widget = MultiSelectListFilter(filter, self.dataset, self.master, self) 
628           
629        elif fType == ("container", "", ""):
630            fType = set(map(filterType, filter.elements_top("Option")))
631            if len(fType) != 1:
632                warnings.warn("Multiple filter types in a single container!" + str(fType))
633            fType = fType.pop()
634#            if fType == ("text", "", ""):
635#                filter_widget = DropDownTextFilter(filter, self.dataset, self.master, self)
636            if fType[0] == "text": #("text", "", "1"):
637                filter_widget = DropDownIdListFilter(filter, self.dataset, self.master, self)
638            elif fType == ("list", "radio", ""):
639                filter_widget = DropDownRadioBooleanFilter(filter, self.dataset, self.master, self)
640       
641        if filter_widget is None:
[1310]642            warnings.warn("Unknown filter type '%s' %s'" % (repr(fType), repr(filter)))
643            filter_widget = UnknownFilter(filter, self.dataset, self.master, self)
[1302]644       
645        filter_widget.setMaximumWidth(400)
646        return label, filter_widget
647   
648    def query(self):
649        if self.enableCB.isChecked():
650            return CollectionWidget.query(self)
651        else:
652            return []
653           
654       
655class GroupWidget(QGroupBox, Control):
656    def __init__(self, tree, dataset, master, parent=None):
657        QGroupBox.__init__(self, parent)
658        Control.__init__(self, tree, dataset, master)
659        self.setLayout(QVBoxLayout())
660       
661        if tree:
662            self.setGroup(tree)
663       
664    def setGroup(self, group):
665        self.setTitle(getattr(group, "displayName", ""))
666        if hasattr(group, "description"):
667            self.setToolTip(group.description)
668        self.setCheckable(True)
669        self.setChecked(True)
670       
671        if group.tag == "FilterGroup":
672            collections = group.elements("FilterCollection")
673        else:
674            collections = group.elements("AttributeCollection")
675        for collection in collections: 
676            if isFilterCollection(collection):
677                collection_widget = FilterCollectionWidget(collection, self.dataset, self.master, self)
[1190]678            else:
[1302]679                collection_widget = AttributeCollectionWidget(collection, self.dataset, self.master, self)
[1190]680               
[1302]681            self.layout().addWidget(collection_widget)
682            self.addSubControl(collection, collection_widget)
[1190]683           
[1302]684           
685       
686class PageWidget(QFrame, Control):
687    def __init__(self, tree, dataset, master, parent=None):
688        QFrame.__init__(self, parent)
689        Control.__init__(self, tree, dataset, master)
690        self.setLayout(QVBoxLayout())
691        self.outFormats = getattr(tree, "outFormats", "tsv")
692       
693        if tree:
694            self.setPage(tree)
695       
696    def setPage(self, tree):
697        if tree.tag == "FilterPage":
698            groups = tree.elements("FilterGroup")
699        else:
700            groups = tree.elements("AttributeGroup")
701           
702        for group in groups:
703            group_widget = GroupWidget(group, self.dataset, self.master, self)
704            self.layout().addWidget(group_widget)
705            self.addSubControl(group, group_widget) 
706           
707        self.layout().addStretch(10)
708       
709        if hasattr(tree, "description"):
710            self.setToolTip(tree.description)
711       
712
[1190]713   
714class OWBioMart(OWWidget):
[1302]715    SHOW_FILTERS = True
[1190]716   
[1250]717    settingsList = ["selectedDataset"]
[1462]718    def __init__(self, parent=None, signalManager=None, title="BioMart"):
[1190]719        OWWidget.__init__(self, parent, signalManager, title)
720       
[1302]721        self.inputs = [("Input ids", ExampleTable, self.setData)]
[1190]722        self.outputs = [("Example Table", ExampleTable)]
723       
724        self.selectedDatabase = None
725        self.selectedDataset = None
726        self.lastSelectedDatasets = (None, None)
727       
[1302]728        self.idAttr = 0
729        self.useAttrNames = False
730        self.uniqueRows = True
731       
732        self.loadSettings()
733       
734        OWGUI.button(OWGUI.widgetBox(self.controlArea, "Cache", addSpace=True),
735                     self, "Clear cache",
736                     tooltip="Clear saved query results",
737                     callback = self.clearCache)
738       
[1306]739       
[1302]740        self.martsCombo = OWGUI.comboBox(self.controlArea, self, "selectedDatabase", "Database",
741                                         callback=self.setSelectedMart,
742                                         addSpace=True)
[1190]743        self.martsCombo.setMaximumWidth(250)
[1302]744       
745        self.datasetsCombo = OWGUI.comboBox(self.controlArea, self, "selectedDataset", "Dataset",
746                                            callback=self.setSelectedDataset,
747                                            addSpace=True)
[1190]748        self.datasetsCombo.setMaximumWidth(250)
[1302]749       
750        box = OWGUI.widgetBox(self.controlArea, "Input Ids")
751       
752        cb = OWGUI.checkBox(box, self, "useAttrNames", "Use attribute names", 
753                            tooltip="Use attribute names for ids",
754                            callback=self.updateInputIds)
755       
756        self.idAttrCB = OWGUI.comboBox(box, self, "idAttr", 
757                                       tooltip="Use attribute values from ...",
758                                       callback=self.updateInputIds)
759       
760        cb.disables = [(-1, self.idAttrCB)]
761        cb.makeConsistent()
762       
763#        self.idListView = QListView()
764#        self.idListView.setSelectionMode(QListView.ExtendedSelection)
765#        self.idListView.setModel(QStringListModel(self))
766#        box.layout().addWidget(self.idListView)
767
768        self.idText = QPlainTextEdit()
769        self.idText.setReadOnly(True)
770#        self.idText.setTextInteractionFlags(Qt.TextSelectableByKeyboard)
771        box.layout().addWidget(self.idText)
772       
[1190]773        OWGUI.rubber(self.controlArea)
774       
[1302]775        box = OWGUI.widgetBox(self.controlArea, "Results")
776        OWGUI.checkBox(box, self, "uniqueRows", "Unique results only",
777                       tooltip="Return unique results only.",
778                       )
779        self.commitButton = OWGUI.button(box, self, "Get Results",
780                                         callback=self.commit,
[1378]781                                         tooltip="Query the BioMart server for results and output the results",
782                                         autoDefault=True)
[1302]783        self.commitButton.setEnabled(False)
[1190]784       
785        self.mainWidget = OWGUI.widgetBox(self.mainArea, orientation=QStackedLayout())
786       
787        self.mainTab = QTabWidget()
788       
789        self.mainWidget.layout().addWidget(self.mainTab)
790       
[1310]791        self.attributesConfigurationBox = OWGUI.createTabPage(self.mainTab, "Attributes")#, canScroll=True)
[1302]792        if self.SHOW_FILTERS:
[1310]793            self.filtersConfigurationBox = OWGUI.createTabPage(self.mainTab, "Filters")#, canScroll=True)
[1190]794
[1250]795        self.myThread = OWConcurrent.WorkerThread()
[1190]796        self.myThread.start()
797       
798        self.__thread = self.thread() # For assert(QThread.currentThread() is self.thread()) to work
799       
800        self.connect(self.myThread, SIGNAL("started()"), lambda :sys.stderr.write("Thread started\n"))
801        self.connect(self.myThread, SIGNAL("finished()"), lambda :sys.stderr.write("Thread finished\n"))
802       
[1306]803        self.error(0)
[1250]804        self.setEnabled(False)
805        self.get_registry_async = OWConcurrent.createTask(self._get_registry,
806                                      onResult=self.setBioMartRegistry,
807                                      onFinished=self.onFinished,
808                                      thread=self.myThread)
[1190]809       
810       
[1302]811        self.resize(800, 600)
812       
813        self.candidateIdAttrs = []
814        self._afterInitQueue = []
815        self.data = None
816       
817        try:
818            from Bio import SeqIO
819            self.hasBiopython = True
820        except Exception, ex:
821            self.warning(100, "Biopython package not found.\nTo retrieve FASTA sequence data from BioMart install Biopython.")
822            self.hasBiopython = False
823       
[1190]824       
825    @staticmethod
826    def _get_registry(url=None, precache=True):
827        con = obiBioMart.BioMartConnection(url)
[1302]828        reg = obiBioMart.BioMartRegistry(con)
[1190]829        if precache:
830            marts = reg.marts()
831        return reg
832       
833    @pyqtSignature("onFinished(QString)")
834    def onFinished(self, status):
835        assert(QThread.currentThread() is self.thread())
836        if str(status).lower() != "ok":
[1306]837            print >> sys.stderr, "AsyncCall failed with message:", status
[1308]838            self.error(0, str(status))
[1250]839        self.setEnabled(True)
[1190]840           
841    @pyqtSignature("setBioMartRegistry(PyQt_PyObject)")
842    def setBioMartRegistry(self, registry):
843        assert(QThread.currentThread() is self.thread())
844        self.registry = registry
845        self.marts = [mart for mart in self.registry.marts() if getattr(mart, "visible", "0") != "0"]
846        last, _ = self.lastSelectedDatasets
847        for mart in self.marts:
848            self.martsCombo.addItem(mart.displayName)
849           
850    def setSelectedMart(self):
851        self.mart = self.marts[self.selectedDatabase]
[1306]852        self.error(0)
[1250]853        self.setEnabled(False)
854        self.get_datasets_async = OWConcurrent.createTask(self.mart.datasets,
855                                    onResult=self.setBioMartDatasets,
856                                    onFinished=self.onFinished,
857                                    thread=self.myThread)
[1302]858       
[1190]859
860    @pyqtSignature("setBioMartDatasets(PyQt_PyObject)")
861    def setBioMartDatasets(self, datasets):
862        assert(QThread.currentThread() is self.thread())
863        self.datasets = [data for data in datasets if getattr(data,"visible", "0") != "0"]
864        self.datasetsCombo.clear()
865        self.datasetsCombo.addItems([data.displayName for data in self.datasets])
866           
867    def setSelectedDataset(self):
868        self.dataset = self.datasets[self.selectedDataset]
[1306]869        self.error(0)
[1302]870       
871        def get_configuration(dataset):
872            """ Only get the response, do not yet parse
873            """
874            connection = dataset.connection
875            stream = connection.configuration(dataset=dataset.internalName, virtualSchema=dataset.virtualSchema)
876            response = stream.read()
877            return response
878       
[1306]879        self.setEnabled(False)
880       
[1302]881        self.get_configuration_async = OWConcurrent.createTask(get_configuration, (self.dataset,),
[1250]882                                            onResult=self.setBioMartConfiguration,
883                                            onFinished=self.onFinished,
884                                            thread=self.myThread)
[1302]885       
[1190]886       
887    @pyqtSignature("setBioMartConfiguration(PyQt_PyObject)")
888    def setBioMartConfiguration(self, configuration):
889        assert(QThread.currentThread() is self.thread())
[1250]890       
[1302]891        doc = obiBioMart.parseXML(configuration)
892        config = list(doc.elements("DatasetConfig"))[0]
893        configuration = obiBioMart.DatasetConfig(self.registry, config.tag, config.attributes, config.children)
894       
[1190]895        self.clearConfiguration()
[1250]896       
[1190]897        self.configuration = configuration
898       
899        def hidden(tree):
900            return getattr(tree, "hidden", "false") != "false" or getattr(tree, "hideDisplay", "false") != "false"
901       
902        self.attributePagesTabWidget = tabs =  OWGUI.tabWidget(self.attributesConfigurationBox)
903       
[1302]904        for page in configuration.elements("AttributePage"):
[1190]905            if not hidden(page):
[1302]906                page_widget = PageWidget(page, self.dataset, self)
[1310]907                OWGUI.createTabPage(tabs, getattr(page, "displayName", ""), widgetToAdd=page_widget, canScroll=True)
[1190]908       
[1302]909        if self.SHOW_FILTERS:
[1190]910            self.filterPagesTabWidget = tabs = OWGUI.tabWidget(self.filtersConfigurationBox)
[1302]911            for page in configuration.elements("FilterPage"):
[1190]912                if not hidden(page):
[1302]913                    page_widget = PageWidget(page, self.dataset, self)
[1310]914                    OWGUI.createTabPage(tabs, getattr(page, "displayName", ""), widgetToAdd=page_widget, canScroll=True)
[1302]915                   
916        self.afterInit()
917       
918        self.commitButton.setEnabled(True)
[1190]919   
920    def clearConfiguration_(self):
921        while True:
922            w = self.attributesConfigurationBox.layout().takeAt(0)
923            if isinstance(w, QWidgetItem):
924                w = w.widget()
925            if not w:
926                break
927            if isinstance(w, QWidget):
928                w.setParent(None)
929       
930        while True:
931            w = self.filtersConfigurationBox.layout().takeAt(0)
932            if isinstance(w, QWidgetItem):
933                w = w.widget()
934            if not w:
935                break
936            if isinstance(w, QWidget):
937                w.setParent(None)
938            pass
939       
940    def clearConfiguration(self):
941        self.mainTab = QTabWidget()
942        self.mainWidget.layout().addWidget(self.mainTab)
943        self.mainWidget.layout().setCurrentWidget(self.mainTab)
944       
[1310]945        self.attributesConfigurationBox = OWGUI.createTabPage(self.mainTab, "Attributes")#, canScroll=True)
[1190]946        if self.SHOW_FILTERS:
[1310]947            self.filtersConfigurationBox = OWGUI.createTabPage(self.mainTab, "Filters")#, canScroll=True)
[1302]948           
[1190]949           
950    def count(self):
951        filters = []
952        count = self.dataset.get_count(filters = filters)
953       
[1302]954       
[1190]955    def commit(self):
[1310]956        pageconf = self.attributePagesTabWidget.currentWidget().widget()
[1302]957        format = pageconf.outFormats
958       
959        self.error(100)
960        if not self.hasBiopython and format.lower() == "fasta":
961            self.error(100, "Cannot parse FASTA format")
962            return
963       
964        query = pageconf.query()
[1190]965        bydatasets = defaultdict(lambda : ([], []))
966
967        version = getattr(self.configuration, "softwareVersion", "0.4")
[1302]968        for conftype, tree, val in query:
969            dataset = self.dataset
970#            if version > "0.4":
971#                dataset = self.dataset
972#            else:
973#                widget = self.findChild(QWidget, tree.internalName)
974#                if widget:
975#                    dataset = widget.dataset
976               
977            if conftype == "Attribute":
978                bydatasets[dataset][0].append(tree.internalName)
979            elif conftype == "Filter":
980                bydatasets[dataset][1].append((tree.internalName, val))
[1190]981               
982        if self.SHOW_FILTERS:
[1310]983            pageconf = self.filterPagesTabWidget.currentWidget().widget()
[1302]984#            configuration =  pageconf.get_configuration()
985            query = pageconf.query()
[1190]986   
[1302]987            for conftype, tree, val in query:
988                dataset = self.dataset
989#                if version > "0.4":
990#                    dataset = self.dataset
991#                else:
992#                    widget = self.findChild(QWidget, tree.internalName)
993#                    if widget:
994#                        dataset = widget.dataset
995                   
996                if conftype == "Attribute":
997                    bydatasets[dataset][0].append(tree.internalName)
998                elif conftype == "Filter":
999                    bydatasets[dataset][1].append((tree.internalName, val))
[1190]1000               
[1302]1001        query = self.registry.query(format="TSV" if "tsv" in format.lower() else format.upper(), uniqueRows=self.uniqueRows)
[1190]1002       
1003        for dataset, (attributes, filters) in bydatasets.items():
1004            query.set_dataset(dataset if dataset else self.dataset)
1005            for attr in attributes:
1006                query.add_attribute(attr)
1007            for filter, value in filters:
1008                query.add_filter(filter, value)
1009       
[1306]1010        self.error(0)
[1250]1011        self.setEnabled(False)
1012        self.run_query_async = OWConcurrent.createTask(query.get_example_table,
1013                                            onResult=self.dataReady,
1014                                            onFinished=self.onFinished,
1015                                            thread=self.myThread)
[1190]1016
[1302]1017   
[1190]1018    def dataReady(self, data):
[1250]1019        self.setEnabled(True)
[1190]1020        self.send("Example Table", data)
1021       
[1302]1022    def pushAction(self, action):
1023        ref = action.ref
1024        ref_widget = self.findChild(QWidget, ref)
1025        if hasattr(ref_widget, "setOptions"):
1026            ref_widget.setOptions(action.subelements_top("Option"))
1027           
1028    def registerDelayedCall(self, call):
1029        self._afterInitQueue.append(call)
[1190]1030       
[1302]1031    def afterInit(self):
1032        while self._afterInitQueue:
1033            call = self._afterInitQueue.pop(0)
1034            call()
1035           
1036    def setData(self, data =None):
1037        self.data = data
1038        self.idAttrCB.clear()
1039        attrs = data.domain.variables + data.domain.getmetas().values()
1040        attrs = [attr for attr in attrs if isinstance(attr, orange.StringVariable)]
1041        self.candidateIdAttrs = attrs
1042        self.idAttrCB.addItems([attr.name for attr in attrs])
1043       
1044        self.idAttr = min(self.candidateIdAttrs, len(self.candidateIdAttrs) - 1)
1045       
1046        self.updateInputIds()
1047   
1048    def updateInputIds(self):
1049        if self.data:
1050            if self.useAttrNames:
1051                names = [attr.name for attr in self.data.domain.attributes]
[1310]1052            elif self.candidateIdAttrs:
[1302]1053                attr = self.candidateIdAttrs[self.idAttr]
1054                names = [str(ex[attr]) for ex in self.data if not ex[attr].isSpecial()]
[1310]1055            else:
1056                names = []
[1302]1057        else:
1058            names = []
1059           
1060#        self.idListView.model().setStringList(names)
1061        self.idText.setPlainText("\n".join(names))
1062       
1063       
1064    def clearCache(self):
[1310]1065        self.registry.connection.clearCache()
[1302]1066   
[1190]1067if __name__ == "__main__":
1068    app = QApplication(sys.argv)
1069    ow = OWBioMart()
1070    ow.show()
[1302]1071   
1072    data = orange.ExampleTable("../../../doc/datasets/brown-selected")
1073    ow.setData(data)
[1190]1074    app.exec_()
[1462]1075    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.