source: orange-bioinformatics/_bioinformatics/widgets/OWBioMart.py @ 1726:6778e0225b86

Revision 1726:6778e0225b86, 39.0 KB checked in by Ales Erjavec <ales.erjavec@…>, 17 months ago (diff)

Added new icons by Peter Cuhalev and replaced existing ones with expanded paths.

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