source: orange-bioinformatics/widgets/OWBioMart.py @ 1462:ee4cee02fb85

Revision 1462:ee4cee02fb85, 38.9 KB checked in by markotoplak, 3 years ago (diff)

Bioinformatics widgets name changes, new icon for GeneMANIA.

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