source: orange-bioinformatics/orangecontrib/bio/widgets/OWPIPAx.py @ 2053:c25fb8a4dbbb

Revision 2053:c25fb8a4dbbb, 32.2 KB checked in by markotoplak, 8 days ago (diff)

Renamed BufferSQLite -> CacheSQLite. dicty documentation updates.

Line 
1"""
2<name>PIPAx</name>
3<description>Access data from PIPA RNA-Seq database.</description>
4<icon>icons/PIPA.svg</icon>
5<priority>35</priority>
6"""
7
8from __future__ import absolute_import
9
10import sys, os
11from collections import defaultdict
12import math
13from datetime import date
14
15from Orange.orng import orngEnviron
16from Orange.OrangeWidgets import OWGUI
17from Orange.OrangeWidgets.OWWidget import *
18
19from .. import obiDicty
20
21NAME = "PIPAx"
22DESCRIPTION = "Access data from PIPA RNA-Seq database."
23ICON = "icons/PIPA.svg"
24PRIORITY = 35
25
26INPUTS = []
27OUTPUTS = [("Example table", Orange.data.Table)]
28
29REPLACES = ["_bioinformatics.widgets.OWPIPAx.OWPIPAx"]
30
31try:
32    from ast import literal_eval
33except ImportError:
34    #avoid eval on older pythons: dates are of lower importance than safety
35    literal_eval = lambda x: None
36
37
38def tfloat(s):
39    try:
40        return float(s)
41    except:
42        return None
43
44
45class MyTreeWidgetItem(QTreeWidgetItem):
46
47    def __init__(self, parent, *args):
48        QTreeWidgetItem.__init__(self, parent, *args)
49        self.par = parent
50
51    def __contains__(self, text):
52        return any(text.upper() in str(self.text(i)).upper() \
53                   for i in range(self.columnCount()))
54
55    def __lt__(self, o1):
56        col = self.par.sortColumn()
57        if col in [8, 9]:  # WARNING: hardcoded column numbers
58            return tfloat(self.text(col)) < tfloat(o1.text(col))
59        else:
60            return QTreeWidgetItem.__lt__(self, o1)
61
62
63# set buffer file
64bufferpath = os.path.join(orngEnviron.directoryNames["bufferDir"], "pipax")
65
66try:
67    os.makedirs(bufferpath)
68except:
69    pass
70
71bufferfile = os.path.join(bufferpath, "database.sq3")
72
73
74class SelectionByKey(object):
75    """An object stores item selection by unique key values
76    (works only for row selections in list and table models)
77    Example::
78
79        ## Save selection by unique tuple pairs (DisplayRole of column 1 and 2)
80        selection = SelectionsByKey(itemView.selectionModel().selection(),
81                                    key = (1,2))
82        ## restore selection (Possibly omitting rows not present in the model)
83        selection.select(itemView.selectionModel())
84
85    """
86
87    def __init__(self, itemSelection, name="", key=(0,)):
88        self._key = key
89        self.name = name
90        self._selected_keys = []
91        if itemSelection:
92            self.setSelection(itemSelection)
93
94    def _row_key(self, model, row):
95        def key(row, col):
96            return str(model.data(model.index(row, col),
97                                  Qt.DisplayRole).toString())
98
99        return tuple(key(row, col) for col in self._key)
100
101    def setSelection(self, itemSelection):
102        self._selected_keys = [self._row_key(ind.model(), ind.row()) \
103                               for ind in itemSelection.indexes() \
104                               if ind.column() == 0]
105
106    def select(self, selectionModel):
107        model = selectionModel.model()
108        selectionModel.clear()
109        for i in range(model.rowCount()):
110            if self._row_key(model, i) in self._selected_keys:
111                selectionModel.select(model.index(i, 0),
112                    QItemSelectionModel.Select | QItemSelectionModel.Rows)
113
114    def __len__(self):
115        return len(self._selected_keys)
116
117
118
119class ListItemDelegate(QStyledItemDelegate):
120    def sizeHint(self, option, index):
121        size = QStyledItemDelegate.sizeHint(self, option, index)
122        size = QSize(size.width(), size.height() + 4)
123        return size
124
125    def createEditor(self, parent, option, index):
126        return QLineEdit(parent)
127   
128    def setEditorData(self, editor, index):
129        editor.setText(index.data(Qt.DisplayRole).toString())
130       
131    def setModelData(self, editor, model, index):
132#        print index
133        model.setData(index, QVariant(editor.text()), Qt.EditRole)
134
135class SelectionSetsWidget(QFrame):
136    """ Widget for managing multiple stored item selections
137    """
138    def __init__(self, parent):
139        QFrame.__init__(self, parent)
140        self.setContentsMargins(0, 0, 0, 0)
141        layout = QVBoxLayout()
142        layout.setContentsMargins(0, 0, 0, 0)
143        layout.setSpacing(1)
144#        self._titleLabel = QLabel(self)
145#        self._titleLabel
146#        layout.addWidget(self._titleLabel)
147        self._setNameLineEdit = QLineEdit(self)
148        layout.addWidget(self._setNameLineEdit)
149       
150        self._setListView = QListView(self)
151        self._listModel = QStandardItemModel(self)
152        self._proxyModel = QSortFilterProxyModel(self)
153        self._proxyModel.setSourceModel(self._listModel)
154       
155        self._setListView.setModel(self._proxyModel)
156        self._setListView.setItemDelegate(ListItemDelegate(self))
157       
158        self.connect(self._setNameLineEdit, SIGNAL("textChanged(QString)"), self._proxyModel.setFilterFixedString)
159       
160        self._completer = QCompleter(self._listModel, self)
161       
162        self._setNameLineEdit.setCompleter(self._completer)
163       
164        self.connect(self._listModel, SIGNAL("itemChanged(QStandardItem *)"), self._onSetNameChange)
165        layout.addWidget(self._setListView)
166        buttonLayout = QHBoxLayout()
167       
168        self._addAction = QAction("+", self)
169        self._updateAction = QAction("Update", self)
170        self._removeAction = QAction("-", self)
171       
172        self._addToolButton = QToolButton(self)
173        self._updateToolButton = QToolButton(self)
174        self._removeToolButton = QToolButton(self)
175        self._updateToolButton.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
176       
177        self._addToolButton.setDefaultAction(self._addAction)
178        self._updateToolButton.setDefaultAction(self._updateAction)
179        self._removeToolButton.setDefaultAction(self._removeAction)
180         
181        buttonLayout.addWidget(self._addToolButton)
182        buttonLayout.addWidget(self._updateToolButton)
183        buttonLayout.addWidget(self._removeToolButton)
184       
185        layout.addLayout(buttonLayout)
186        self.setLayout(layout)
187       
188        self.connect(self._addAction, SIGNAL("triggered()"), self.addCurrentSelection)
189        self.connect(self._updateAction, SIGNAL("triggered()"), self.updateSelectedSelection)
190        self.connect(self._removeAction, SIGNAL("triggered()"), self.removeSelectedSelection)
191       
192        self.connect(self._setListView.selectionModel(), SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), self._onListViewSelectionChanged)
193        self.selectionModel = None
194        self._selections = []
195       
196    def sizeHint(self):
197        size = QFrame.sizeHint(self)
198        return QSize(size.width(), 200)
199       
200    def _onSelectionChanged(self, selected, deselected):
201        self.setSelectionModified(True)
202       
203    def _onListViewSelectionChanged(self, selected, deselected):
204        try:
205            index= self._setListView.selectedIndexes()[0]
206        except IndexError:
207            return 
208        self.commitSelection(self._proxyModel.mapToSource(index).row())
209
210    def _onSetNameChange(self, item):
211        self.selections[item.row()].name = str(item.text())
212               
213    def _setButtonStates(self, val):
214        self._updateToolButton.setEnabled(val)
215       
216    def setSelectionModel(self, selectionModel):
217        if self.selectionModel:
218            self.disconnect(self.selectionModel, SIGNAL("selectionChanged(QItemSelection, QItemSelection)", self._onSelectionChanged))
219        self.selectionModel = selectionModel
220        self.connect(self.selectionModel, SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), self._onSelectionChanged)
221       
222    def addCurrentSelection(self):
223        item = self.addSelection(SelectionByKey(self.selectionModel.selection(), name="New selection", key=(1, 2, 3 ,10)))
224        index = self._proxyModel.mapFromSource(item.index())
225        self._setListView.setCurrentIndex(index)
226        self._setListView.edit(index)
227        self.setSelectionModified(False)
228   
229    def removeSelectedSelection(self):
230        i = self._proxyModel.mapToSource(self._setListView.currentIndex()).row()
231        self._listModel.takeRow(i)
232        del self.selections[i]
233   
234    def updateCurentSelection(self):
235        i = self._proxyModel.mapToSource(self._setListView.selectedIndex()).row()
236        self.selections[i].setSelection(self.selectionModel.selection())
237        self.setSelectionModified(False)
238       
239    def addSelection(self, selection, name=""):
240        self._selections.append(selection)
241        item = QStandardItem(selection.name)
242        item.setFlags(item.flags() ^ Qt.ItemIsDropEnabled)
243        self._listModel.appendRow(item)
244        self.setSelectionModified(False)
245        return item
246       
247    def updateSelectedSelection(self):
248        i = self._proxyModel.mapToSource(self._setListView.currentIndex()).row()
249        self.selections[i].setSelection(self.selectionModel.selection())
250        self.setSelectionModified(False)
251       
252    def setSelectionModified(self, val):
253        self._selectionModified = val
254        self._setButtonStates(val)
255        self.emit(SIGNAL("selectionModified(bool)"), bool(val))
256       
257    def commitSelection(self, index):
258        selection = self.selections[index]
259        selection.select(self.selectionModel)
260       
261    def setSelections(self, selections):
262        self._listModel.clear()
263#        print selections
264        for selection in selections:
265            self.addSelection(selection)
266           
267    def selections(self):
268        return self._selections
269   
270    selections = property(selections, setSelections)
271   
272               
273class SortedListWidget(QWidget):
274    class _MyItemDelegate(QStyledItemDelegate):
275        def __init__(self, sortingModel, parent):
276            QStyledItemDelegate.__init__(self, parent)
277            self.sortingModel = sortingModel
278           
279        def sizeHint(self, option, index):
280            size = QStyledItemDelegate.sizeHint(self, option, index)
281            return QSize(size.width(), size.height() + 4)
282           
283        def createEditor(self, parent, option, index):
284            cb = QComboBox(parent)
285            cb.setModel(self.sortingModel)
286            cb.showPopup()
287            return cb
288       
289        def setEditorData(self, editor, index):
290            pass # TODO: sensible default
291       
292        def setModelData(self, editor, model, index):
293            text = editor.currentText()
294            model.setData(index, QVariant(text))
295   
296    def __init__(self, *args):
297        QWidget.__init__(self, *args)
298        self.setContentsMargins(0, 0, 0, 0)
299        gridLayout = QGridLayout()
300        gridLayout.setContentsMargins(0, 0, 0, 0)
301        gridLayout.setSpacing(1)
302        self._listView = QListView(self)
303        self._listView.setModel(QStandardItemModel(self))
304#        self._listView.setDragEnabled(True)
305        self._listView.setDropIndicatorShown(True)
306        self._listView.viewport().setAcceptDrops(True)
307        self._listView.setDragDropMode(QAbstractItemView.InternalMove)
308        self._listView.setMinimumHeight(100)
309       
310        gridLayout.addWidget(self._listView, 0, 0, 2, 2)
311       
312        vButtonLayout = QVBoxLayout()
313       
314        self._upAction = QAction(QIcon(os.path.join(orngEnviron.widgetDir, "icons/Dlg_up3.png")), "Up", self)
315       
316        self._upButton = QToolButton(self)
317        self._upButton.setDefaultAction(self._upAction)
318        self._upButton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
319
320        self._downAction = QAction(QIcon(os.path.join(orngEnviron.widgetDir, "icons/Dlg_down3.png")), "Down", self)
321        self._downButton = QToolButton(self)
322        self._downButton.setDefaultAction(self._downAction)
323        self._downButton.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
324       
325        vButtonLayout.addWidget(self._upButton)
326        vButtonLayout.addWidget(self._downButton)
327       
328        gridLayout.addLayout(vButtonLayout, 0, 2, 2, 1)
329       
330        hButtonLayout = QHBoxLayout()
331       
332        self._addAction = QAction("+", self)
333        self._addButton = QToolButton(self)
334        self._addButton.setDefaultAction(self._addAction)
335       
336        self._removeAction = QAction("-", self)
337        self._removeButton = QToolButton(self)
338        self._removeButton.setDefaultAction(self._removeAction)
339        hButtonLayout.addWidget(self._addButton)
340        hButtonLayout.addWidget(self._removeButton)
341        hButtonLayout.addStretch(10)
342        gridLayout.addLayout(hButtonLayout, 2, 0, 1, 2)
343       
344        self.setLayout(gridLayout)
345       
346        self.connect(self._addAction, SIGNAL("triggered()"), self._onAddAction)
347        self.connect(self._removeAction, SIGNAL("triggered()"), self._onRemoveAction)
348        self.connect(self._upAction, SIGNAL("triggered()"), self._onUpAction)
349        self.connect(self._downAction, SIGNAL("triggered()"), self._onDownAction)
350       
351    def sizeHint(self):
352        size = QWidget.sizeHint(self)
353        return QSize(size.width(), 100)
354       
355    def _onAddAction(self):
356        item = QStandardItem("")
357        item.setFlags(item.flags() ^ Qt.ItemIsDropEnabled)
358        self._listView.model().appendRow(item)
359        self._listView.setCurrentIndex(item.index())
360        self._listView.edit(item.index()) 
361   
362    def _onRemoveAction(self):
363        current = self._listView.currentIndex()
364        self._listView.model().takeRow(current.row())
365   
366    def _onUpAction(self):
367        row = self._listView.currentIndex().row()
368        model = self._listView.model()
369        if row > 0:
370            items = model.takeRow(row)
371            model.insertRow(row - 1, items)
372            self._listView.setCurrentIndex(model.index(row - 1, 0))
373   
374    def _onDownAction(self):
375        row = self._listView.currentIndex().row()
376        model = self._listView.model()
377        if row < model.rowCount() and row >= 0:
378            items = model.takeRow(row)
379            if row == model.rowCount():
380                model.appendRow(items)
381            else:
382                model.insertRow(row + 1, items)
383            self._listView.setCurrentIndex(model.index(row + 1, 0))
384   
385    def setModel(self, model):
386        """ Set a model to select items from
387        """
388        self._model  = model
389        self._listView.setItemDelegate(self._MyItemDelegate(self._model, self))
390       
391    def addItem(self, *args):
392        """ Add a new entry in the list
393        """
394        item = QStandardItem(*args)
395        item.setFlags(item.flags() ^ Qt.ItemIsDropEnabled)
396        self._listView.model().appendRow(item)
397       
398    def setItems(self, items):
399        self._listView.model().clear()
400        for item in items:
401            self.addItem(item)
402         
403    def items(self):
404        order = []
405        for row in range(self._listView.model().rowCount()):
406             order.append(str(self._listView.model().item(row ,0).text()))
407        return order
408   
409    sortingOrder = property(items, setItems)
410       
411   
412
413# Mapping from PIPAx.results_list annotation keys to Header names.
414HEADER = [("_cached", ""),
415          ("data_name", "Name"),
416          ("species_name", "Species"),
417          ("strain", "Strain"),
418          ("Experiment", "Experiment"),
419          ("genotype", "Genotype"),
420          ("treatment", "Treatment"),
421          ("growth", "Growth"),
422          ("tp", "Timepoint"),
423          ("replicate", "Replicate"),
424          ("unique_id", "ID"),
425          ("date_rnaseq", "Date RNAseq"),
426          ("adapter_type", "Adapter"),
427          ("experimenter", "Experimenter"),
428          ("band", "Band"),
429          ("polya", "Polya"),
430          ("primer", "Primer"),
431          ("shearing", "Shearing")
432          ]
433
434# Index of unique_id
435ID_INDEX = 10
436
437# Index of 'date_rnaseq'
438DATE_INDEX = 11
439
440SORTING_MODEL_LIST = \
441    ["Strain", "Experiment", "Genotype",
442     "Timepoint", "Growth", "Species",
443     "ID", "Name", "Replicate"]
444
445
446class OWPIPAx(OWWidget):
447    settingsList = ["server", "excludeconstant", "username", "password",
448                    "joinreplicates", "selectionSetsWidget.selections",
449                    "columnsSortingWidget.sortingOrder", "currentSelection",
450                    "log2", "experimentsHeaderState", "rtypei" ]
451
452    def __init__(self, parent=None, signalManager=None, name="PIPAx"):
453        OWWidget.__init__(self, parent, signalManager, name)
454        self.outputs = [("Example table", ExampleTable)]
455
456        self.username = ""
457        self.password = ""
458        self.log2 = False
459        self.rtypei = 5 #hardcoded rpkm mapability polya
460
461        self.selectedExperiments = []
462        self.buffer = obiDicty.CacheSQLite(bufferfile)
463
464        self.searchString = ""
465        self.excludeconstant = False
466        self.joinreplicates = False
467        self.currentSelection = None
468
469        self.experimentsHeaderState = \
470                dict(((name, False) for _, name in HEADER[:ID_INDEX + 1]))
471
472        self.result_types = []
473        self.mappings = {}
474
475        self.controlArea.setMaximumWidth(250)
476        self.controlArea.setMinimumWidth(250)
477
478        OWGUI.button(self.controlArea, self, "Reload",
479                     callback=self.Reload)
480        OWGUI.button(self.controlArea, self, "Clear cache",
481                     callback=self.clear_cache)
482
483        b = OWGUI.widgetBox(self.controlArea, "Experiment Sets")
484        self.selectionSetsWidget = SelectionSetsWidget(self)
485        self.selectionSetsWidget.setSizePolicy(QSizePolicy.Preferred,
486                                               QSizePolicy.Maximum)
487        b.layout().addWidget(self.selectionSetsWidget)
488
489        OWGUI.separator(self.controlArea)
490
491        b = OWGUI.widgetBox(self.controlArea, "Sort output columns")
492        self.columnsSortingWidget = SortedListWidget(self)
493        self.columnsSortingWidget.setSizePolicy(QSizePolicy.Preferred,
494                                                QSizePolicy.Maximum)
495        b.layout().addWidget(self.columnsSortingWidget)
496        sorting_model = QStringListModel(SORTING_MODEL_LIST)
497        self.columnsSortingWidget.setModel(sorting_model)
498
499        self.columnsSortingWidget.sortingOrder = \
500                ["Strain", "Experiment", "Genotype", "Timepoint"]
501
502        OWGUI.separator(self.controlArea)
503
504        box = OWGUI.widgetBox(self.controlArea, 'Expression Type')
505        self.expressionTypesCB = OWGUI.comboBox(box, self, "rtypei",
506                items=[],
507                callback=self.UpdateResultsList)
508
509        OWGUI.checkBox(self.controlArea, self, "excludeconstant",
510                       "Exclude labels with constant values"
511                       )
512
513        OWGUI.checkBox(self.controlArea, self, "joinreplicates",
514                       "Average replicates (use median)"
515                       )
516
517        OWGUI.checkBox(self.controlArea, self, "log2",
518                       "Logarithmic (base 2) transformation"
519                       )
520
521        self.commit_button = OWGUI.button(self.controlArea, self, "&Commit",
522                                          callback=self.Commit)
523        self.commit_button.setDisabled(True)
524
525        OWGUI.rubber(self.controlArea)
526
527        box = OWGUI.widgetBox(self.controlArea, "Authentication")
528
529        OWGUI.lineEdit(box, self, "username", "Username:",
530                       labelWidth=100,
531                       orientation='horizontal',
532                       callback=self.AuthChanged)
533
534        self.passf = OWGUI.lineEdit(box, self, "password", "Password:",
535                                    labelWidth=100,
536                                    orientation='horizontal',
537                                    callback=self.AuthChanged)
538
539        self.passf.setEchoMode(QLineEdit.Password)
540
541        OWGUI.lineEdit(self.mainArea, self, "searchString", "Search",
542                       callbackOnType=True,
543                       callback=self.SearchUpdate)
544
545        self.headerLabels = [t[1] for t in HEADER]
546
547        self.experimentsWidget = QTreeWidget()
548        self.experimentsWidget.setHeaderLabels(self.headerLabels)
549        self.experimentsWidget.setSelectionMode(QTreeWidget.ExtendedSelection)
550        self.experimentsWidget.setRootIsDecorated(False)
551        self.experimentsWidget.setSortingEnabled(True)
552
553        contextEventFilter = OWGUI.VisibleHeaderSectionContextEventFilter(
554                            self.experimentsWidget, self.experimentsWidget
555                            )
556
557        self.experimentsWidget.header().installEventFilter(contextEventFilter)
558        self.experimentsWidget.setItemDelegateForColumn(0,
559                    OWGUI.IndicatorItemDelegate(self, role=Qt.DisplayRole)
560                    )
561
562        self.experimentsWidget.setAlternatingRowColors(True)
563
564        self.connect(self.experimentsWidget.selectionModel(),
565                 SIGNAL("selectionChanged(QItemSelection, QItemSelection)"),
566                 self.onSelectionChanged)
567
568        self.selectionSetsWidget.setSelectionModel(
569                            self.experimentsWidget.selectionModel()
570                            )
571
572        self.mainArea.layout().addWidget(self.experimentsWidget)
573
574        self.loadSettings()
575
576        self.restoreHeaderState()
577
578        self.connect(self.experimentsWidget.header(),
579                     SIGNAL("geometriesChanged()"),
580                     self.saveHeaderState)
581
582        self.dbc = None
583
584        self.AuthSet()
585
586        QTimer.singleShot(100, self.UpdateExperiments)
587
588        self.resize(800, 600)
589
590    def AuthSet(self):
591        if len(self.username):
592            self.passf.setDisabled(False)
593        else:
594            self.passf.setDisabled(True)
595
596    def AuthChanged(self):
597        self.AuthSet()
598        self.ConnectAndUpdate()
599
600    def ConnectAndUpdate(self):
601        self.Connect()
602        self.UpdateExperiments(reload=True)
603
604    def Connect(self):
605        self.error(1)
606        self.warning(1)
607
608        def en(x):
609            return x if len(x) else None
610
611        self.dbc = obiDicty.PIPAx(cache=self.buffer,
612                                  username=en(self.username),
613                                  password=self.password)
614
615        #check password
616        if en(self.username) != None:
617            try:
618                self.dbc.mappings(reload=True)
619            except obiDicty.AuthenticationError:
620                self.error(1, "Wrong username or password")
621                self.dbc = None
622            except Exception, ex:
623                print "Error when contacting the PIPA database", ex
624                import traceback
625                print traceback.format_exc()
626                try:  # maybe cached?
627                    self.dbc.mappings()
628                    self.warning(1, "Can not access database - using cached data.")
629                except Exception, ex:
630                    self.dbc = None
631                    self.error(1, "Can not access database.")
632
633    def Reload(self):
634        self.UpdateExperiments(reload=True)
635
636    def clear_cache(self):
637        self.buffer.clear()
638        self.Reload()
639
640    def rtype(self):
641        """Return selected result template type """
642        if self.result_types:
643            return self.result_types[self.rtypei][0]
644        else:
645            return "-1"
646
647    def UpdateExperimentTypes(self):
648        self.expressionTypesCB.clear()
649        items = [desc for _, desc  in self.result_types]
650        self.expressionTypesCB.addItems(items)
651        self.rtypei = max(0, min(self.rtypei, len(self.result_types) - 1))
652
653    def UpdateExperiments(self, reload=False):
654        self.experimentsWidget.clear()
655        self.items = []
656
657        self.progressBarInit()
658
659        if not self.dbc:
660            self.Connect()
661
662        mappings = {}
663        result_types = []
664        sucind = False  # success indicator for database index
665
666        try:
667            mappings = self.dbc.mappings(reload=reload)
668            result_types = self.dbc.result_types(reload=reload)
669            sucind = True
670        except Exception, ex:
671            try:
672                mappings = self.dbc.mappings()
673                result_types = self.dbc.result_types()
674                self.warning(0, "Can not access database - using cached data.")
675                sucind = True
676            except Exception, ex:
677                self.error(0, "Can not access database.")
678
679        if sucind:
680            self.warning(0)
681            self.error(0)
682
683        self.mappings = mappings
684        self.result_types = result_types
685
686        self.UpdateExperimentTypes()
687        self.UpdateResultsList(reload=reload)
688
689        self.progressBarFinished()
690
691        if self.currentSelection:
692            self.currentSelection.select(self.experimentsWidget.selectionModel())
693
694        self.handle_commit_button()
695
696    def UpdateResultsList(self, reload=False):
697
698        results_list = {}
699        try:
700            results_list = self.dbc.results_list(self.rtype(), reload=reload)
701        except Exception, ex:
702            try:
703                results_list = self.dbc.results_list(self.rtype())
704            except Exception, ex:
705                self.error(0, "Can not access database.")
706
707        self.results_list = results_list
708        mappings_key_dict = dict(((m["data_id"], m["id"]), key) \
709                                 for key, m in self.mappings.items())
710
711        def mapping_unique_id(annot):
712            """Map annotations dict from results_list to unique
713            `mappings` ids.
714            """
715            data_id, mappings_id = annot["data_id"], annot["mappings_id"]
716            return mappings_key_dict[data_id, mappings_id]
717
718        elements = []
719
720        #softly change the view so that the selection stays the same
721
722        items_shown = {}
723        for i,item in enumerate(self.items):
724            c = str(item.text(10))
725            items_shown[c] = i
726
727        items_to_show = dict( (mapping_unique_id(annot), annot) for annot in self.results_list.values() )
728
729        add_items = set(items_to_show) - set(items_shown)
730        delete_items = set(items_shown) - set(items_to_show)
731
732        i = 0
733        while i < self.experimentsWidget.topLevelItemCount():
734            it = self.experimentsWidget.topLevelItem(i)
735            if str(it.text(10)) in delete_items:
736                self.experimentsWidget.takeTopLevelItem(i)
737            else:
738                i += 1
739
740        delete_ind = set([ items_shown[i] for i in delete_items ])
741        self.items = [ it for i, it in enumerate(self.items) if i not in delete_ind ]
742
743        for r_annot in [ items_to_show[i] for i in add_items ]:
744            d = defaultdict(lambda: "?", r_annot)
745            row_items = [""] + [d.get(key, "?") for key, _ in HEADER[1:]]
746            try:
747                time_dict = literal_eval(row_items[DATE_INDEX])
748                date_rna = date(time_dict["fullYearUTC"],
749                                time_dict["monthUTC"] + 1,  # Why is month 0 based?
750                                time_dict["dateUTC"])
751                row_items[DATE_INDEX] = date_rna.strftime("%x")
752            except Exception:
753                row_items[DATE_INDEX] = ''
754
755            row_items[ID_INDEX] = mapping_unique_id(r_annot)
756            elements.append(row_items)
757
758            ci = MyTreeWidgetItem(self.experimentsWidget, row_items)
759
760            self.items.append(ci)
761
762        for i in range(len(self.headerLabels)):
763            self.experimentsWidget.resizeColumnToContents(i)
764
765        # which is the ok buffer version
766        # FIXME: what attribute to use for version?
767        self.wantbufver = \
768            lambda x, ad=self.results_list: \
769                defaultdict(lambda: "?", ad[x])["date"]
770
771        self.wantbufver = lambda x: "0"
772
773        self.UpdateCached()
774
775
776    def UpdateCached(self):
777        if self.wantbufver and self.dbc:
778            fn = self.dbc.download_key_function()
779            result_id_key = dict(((m["data_id"], m["mappings_id"]), key) \
780                                 for key, m in self.results_list.items())
781
782            for item in self.items:
783                c = str(item.text(10))
784                mapping = self.mappings[c]
785                data_id, mappings_id = mapping["data_id"], mapping["id"]
786                r_id = result_id_key[data_id, mappings_id]
787                # Get the buffered version
788                buffered = self.dbc.inBuffer(fn(r_id))
789                value = " " if buffered == self.wantbufver(r_id) else ""
790                item.setData(0, Qt.DisplayRole, QVariant(value))
791
792    def SearchUpdate(self, string=""):
793        for item in self.items:
794            item.setHidden(not all(s in item \
795                                   for s in self.searchString.split())
796                           )
797
798    def Commit(self):
799        if not self.dbc:
800            self.Connect()
801
802        pb = OWGUI.ProgressBar(self, iterations=100)
803
804        table = None
805
806        ids = []
807        for item in self.experimentsWidget.selectedItems():
808            unique_id = str(item.text(10))
809            annots = self.mappings[unique_id]
810            ids.append((annots["data_id"], annots["id"]))
811
812        transfn = None
813        if self.log2:
814            transfn = lambda x: math.log(x + 1.0, 2)
815
816        reverse_header_dict = dict((name, key) for key, name in HEADER)
817
818        hview = self.experimentsWidget.header()
819        shownHeaders = [label for i, label in \
820                        list(enumerate(self.headerLabels))[1:] \
821                        if not hview.isSectionHidden(i)
822                        ]
823
824        allowed_labels = [reverse_header_dict.get(label, label) \
825                          for label in shownHeaders]
826
827        if self.joinreplicates and "id" not in allowed_labels:
828            # need 'id' labels in join_replicates for attribute names
829            allowed_labels.append("id")
830
831        if len(ids):
832            table = self.dbc.get_data(ids=ids, result_type=self.rtype(),
833                          callback=pb.advance,
834                          exclude_constant_labels=self.excludeconstant,
835#                          bufver=self.wantbufver,
836                          transform=transfn,
837                          allowed_labels=allowed_labels)
838
839            if self.joinreplicates:
840                table = obiDicty.join_replicates(table,
841                    ignorenames=["replicate", "data_id", "mappings_id",
842                                 "data_name", "id", "unique_id"],
843                    namefn=None,
844                    avg=obiDicty.median
845                    )
846
847            # Sort attributes
848            sortOrder = self.columnsSortingWidget.sortingOrder
849
850            all_values = defaultdict(set)
851            for at in table.domain.attributes:
852                atts = at.attributes
853                for name in sortOrder:
854                    all_values[name].add(atts.get(reverse_header_dict[name], ""))
855
856            isnum = {}
857            for at, vals in all_values.items():
858                vals = filter(None, vals)
859                try:
860                    for a in vals:
861                        float(a)
862                    isnum[at] = True
863                except:
864                    isnum[at] = False
865
866            def optfloat(x, at):
867                if x == "":
868                    return ""
869                else:
870                    return float(x) if isnum[at] else x
871
872            def sorting_key(attr):
873                atts = attr.attributes
874                return tuple([optfloat(atts.get(reverse_header_dict[name], ""), name) \
875                              for name in sortOrder])
876
877            attributes = sorted(table.domain.attributes,
878                                key=sorting_key)
879
880            domain = orange.Domain(attributes, table.domain.classVar)
881            domain.addmetas(table.domain.getmetas())
882            table = orange.ExampleTable(domain, table)
883
884            from Orange.orng.orngDataCaching import data_hints
885            data_hints.set_hint(table, "taxid", "352472")
886            data_hints.set_hint(table, "genesinrows", False)
887
888            self.send("Example table", table)
889
890            self.UpdateCached()
891
892        pb.finish()
893
894    def onSelectionChanged(self, selected, deselected):
895        self.handle_commit_button()
896
897    def handle_commit_button(self):
898        self.currentSelection = \
899            SelectionByKey(self.experimentsWidget.selectionModel().selection(),
900                           key=(1, 2, 3, 10))
901        self.commit_button.setDisabled(not len(self.currentSelection))
902
903    def saveHeaderState(self):
904        hview = self.experimentsWidget.header()
905        for i, label in enumerate(self.headerLabels):
906            self.experimentsHeaderState[label] = hview.isSectionHidden(i)
907
908    def restoreHeaderState(self):
909        hview = self.experimentsWidget.header()
910        state = self.experimentsHeaderState
911        for i, label in enumerate(self.headerLabels):
912            hview.setSectionHidden(i, state.get(label, True))
913            self.experimentsWidget.resizeColumnToContents(i)
914
915if __name__ == "__main__":
916    app = QApplication(sys.argv)
917    obiDicty.verbose = True
918    w = OWPIPAx()
919    w.show()
920    app.exec_()
921    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.