Changeset 1909:45044fae44b2 in orange-bioinformatics for orangecontrib/bio/widgets/OWSelectGenes.py


Ignore:
Timestamp:
11/18/13 14:39:51 (5 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Added "Import names from gene sets" dialog.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • orangecontrib/bio/widgets/OWSelectGenes.py

    r1884 r1909  
    11import re 
    22import unicodedata 
     3import operator 
    34from collections import defaultdict, namedtuple 
    45from xml.sax.saxutils import escape 
     
    1011    QTextCursor, QCompleter, QStringListModel, QStandardItemModel, 
    1112    QStandardItem, QListView, QStyle, QStyledItemDelegate, 
    12     QStyleOptionViewItemV4, QPalette, QColor, QApplication, 
    13     QAction, QToolButton, QSizePolicy, QItemSelectionModel, 
    14     QPlainTextDocumentLayout, QTextDocument, QRadioButton, 
    15     QButtonGroup, QStyleOptionButton 
     13    QStyleOptionViewItemV4, QPalette, QColor, QApplication, QAction, 
     14    QToolButton, QItemSelectionModel, QPlainTextDocumentLayout, QTextDocument, 
     15    QRadioButton, QButtonGroup, QStyleOptionButton, QMenu, QDialog 
    1616) 
    1717 
     
    2525from Orange.OrangeWidgets.OWItemModels import VariableListModel 
    2626from Orange.OrangeWidgets import OWGUI 
     27from Orange.orng.orngDataCaching import data_hints 
    2728 
    2829 
     
    5152 
    5253 
     54def toPyObject(variant): 
     55    if isinstance(variant, QVariant): 
     56        return variant.toPyObject() 
     57    else: 
     58        return variant 
     59 
     60 
    5361class SaveSlot(QStandardItem): 
    5462    ModifiedRole = next(OWGUI.OrangeUserRole) 
     
    110118    contextHandlers = { 
    111119        "": DomainContextHandler( 
    112             "", ["geneIndex"] 
     120            "", ["geneIndex", "taxid"] 
    113121        ), 
    114122        "subset": DomainContextHandler( 
     
    127135 
    128136        self.geneIndex = None 
     137        self.taxid = None 
    129138        self.autoCommit = False 
    130139        self.preserveOrder = True 
     
    253262 
    254263        self.actionRemove = QAction( 
    255             "-", self, 
     264            u"\u2212", self, 
    256265            toolTip="Delete the current saved selection") 
     266 
     267        self.actionMore = QAction("More", self) 
     268 
     269        optionsmenu = QMenu() 
     270        action = optionsmenu.addAction("Import names from gene sets...") 
     271        action.triggered.connect(self.importGeneSet) 
     272 
     273        self.actionMore.setMenu(optionsmenu) 
    257274 
    258275        toolbar = QFrame() 
     
    269286        layout.addWidget(b) 
    270287 
    271         b = button(self.actionSave) 
    272         b.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) 
    273         layout.addWidget(b, stretch=10) 
    274  
    275288        b = button(self.actionRemove) 
    276289        layout.addWidget(b) 
    277290 
     291        b = button(self.actionSave) 
     292        layout.addWidget(b) 
     293 
     294        b = button(self.actionMore) 
     295        b.setPopupMode(QToolButton.InstantPopup) 
     296        layout.addWidget(b) 
     297 
     298        layout.addStretch(100) 
    278299        toolbar.setLayout(layout) 
    279300 
     
    293314 
    294315        OWGUI.setStopper(self, button, cb, "_changedFlag", self.commit) 
     316 
     317        # Gene set import dialog (initialized when required) 
     318        self._genesetDialog = None 
    295319 
    296320        # restore saved selections model. 
     
    328352        self._changedFlag = True 
    329353        self._updateCompletionModel() 
    330  
     354        self.taxid = data_hints.get_hint(data, "taxid", None) 
    331355        self.openContext("", data) 
    332356 
     
    536560            self.selectionsModel.removeRow(item.row()) 
    537561 
     562    def importGeneSet(self): 
     563        if self._genesetDialog is None: 
     564            self._genesetDialog = GeneSetDialog( 
     565                self, windowTitle="Import Gene Set Names") 
     566 
     567        dialog = self._genesetDialog 
     568 
     569        if self.taxid is not None: 
     570            dialog.setCurrentOrganism(self.taxid) 
     571 
     572        result = dialog.exec_() 
     573        if result == QDialog.Accepted: 
     574            gsets = dialog.selectedGeneSets() 
     575            genes = reduce(operator.ior, (gs.genes for gs in gsets), set()) 
     576            text = " ".join(genes) 
     577            self.entryField.appendPlainText(text) 
     578            self.entryField.setFocus() 
     579            self.entryField.moveCursor(QTextCursor.End) 
     580            self.taxid = dialog.currentOrganism() 
     581 
    538582    def _onSelectedSaveSlotChanged(self): 
    539583        item = self._selectedSaveSlot() 
     
    9761020 
    9771021 
     1022import itertools 
     1023 
     1024from PyQt4.QtGui import QVBoxLayout, QComboBox, QLineEdit, QTreeView, \ 
     1025        QDialogButtonBox, QSortFilterProxyModel 
     1026 
     1027from PyQt4.QtCore import QSize 
     1028from Orange.bio import obiGeneSets as genesets 
     1029from Orange.bio import obiTaxonomy as taxonomy 
     1030from Orange.utils import serverfiles 
     1031 
     1032 
     1033class GeneSetView(QFrame): 
     1034    selectedOrganismChanged = Signal(str) 
     1035    selectionChanged = Signal() 
     1036 
     1037    def __init__(self, *args, **kwargs): 
     1038        super(GeneSetView, self).__init__(*args, **kwargs) 
     1039 
     1040        layout = QVBoxLayout() 
     1041        layout.setContentsMargins(0, 0, 0, 0) 
     1042 
     1043        self.orgcombo = QComboBox(minimumWidth=150) 
     1044        self.orgcombo.addItem("Organism") 
     1045        item = self.orgcombo.model().item(0) 
     1046        item.setEnabled(False) 
     1047        self.orgcombo.insertSeparator(1) 
     1048        self.orgcombo.activated[int].connect(self._on_organismSelected) 
     1049        layout.addWidget(self.orgcombo) 
     1050 
     1051        self.searchline = QLineEdit() 
     1052        self.searchline.setPlaceholderText("Filter...") 
     1053        completer = QCompleter() 
     1054        self.searchline.setCompleter(completer) 
     1055        layout.addWidget(self.searchline) 
     1056 
     1057        self.gsview = QTreeView() 
     1058        self.gsview.setAlternatingRowColors(True) 
     1059        self.gsview.setRootIsDecorated(False) 
     1060        self.gsview.setSelectionMode(QTreeView.ExtendedSelection) 
     1061        self.proxymodel = QSortFilterProxyModel( 
     1062            filterKeyColumn=1, sortCaseSensitivity=Qt.CaseInsensitive 
     1063        ) 
     1064 
     1065        self.gsview.setModel(self.proxymodel) 
     1066        self.gsview.selectionModel().selectionChanged.connect( 
     1067            self._on_selectionChanged) 
     1068 
     1069        self.searchline.textChanged.connect( 
     1070            self.proxymodel.setFilterFixedString) 
     1071 
     1072        layout.addWidget(self.gsview) 
     1073        self.setLayout(layout) 
     1074 
     1075        self.initialize() 
     1076 
     1077    def sizeHint(self): 
     1078        return QSize(500, 550) 
     1079 
     1080    def initialize(self): 
     1081        self.gs_hierarchy = gs = genesets.list_all() 
     1082        taxids = set(taxid for _, taxid, _ in gs) 
     1083        self.organisms = [(taxid, taxonomy.name(taxid)) for taxid in taxids] 
     1084        for taxid, name in self.organisms: 
     1085            self.orgcombo.addItem(name, taxid) 
     1086 
     1087    def setCurrentOrganism(self, taxid): 
     1088        taxids = [tid for tid, _ in self.organisms] 
     1089        if taxid is not None and taxid not in taxids: 
     1090            taxid = None 
     1091 
     1092        if taxid not in taxids: 
     1093            taxid = None 
     1094            index = 0 
     1095        else: 
     1096            index = taxid.index(taxid) + 2 
     1097 
     1098        if index != self.orgcombo.currentIndex(): 
     1099            if taxid is None: 
     1100                self.orgcombo.setCurrentIndex(index) 
     1101                self.gsmodel.clear() 
     1102                self.proxymodel.setSourceModel(None) 
     1103            else: 
     1104                self.orgcombo.setCurrentIndex(index) 
     1105 
     1106                currentsets = [(hier, tid) 
     1107                               for hier, tid, _ in self.gs_hierarchy 
     1108                               if tid == taxid] 
     1109 
     1110                gs_ensure_downloaded([(hier, tid, local) 
     1111                                      for hier, tid, local in self.gs_hierarchy 
     1112                                      if tid == taxid and not local]) 
     1113 
     1114                sets = [((hier, tid), genesets.load(hier, tid)) 
     1115                        for hier, tid in currentsets] 
     1116 
     1117                model = sets_to_model(sets) 
     1118                self.proxymodel.setSourceModel(model) 
     1119                self.gsview.resizeColumnToContents(0) 
     1120                self.selectedOrganismChanged.emit(taxid) 
     1121 
     1122    def currentOrganism(self): 
     1123        index = self.orgcombo.currentIndex() 
     1124        if index > 1: 
     1125            item = self.orgcombo.model().item(index) 
     1126            return toString(item.data(Qt.UserRole)) 
     1127        else: 
     1128            return None 
     1129 
     1130    def _on_organismSelected(self, index): 
     1131        if index != -1: 
     1132            item = self.orgcombo.model().item(index) 
     1133            taxid = toString(item.data(Qt.UserRole)) 
     1134            self.setCurrentOrganism(taxid) 
     1135 
     1136    def _on_selectionChanged(self, *args): 
     1137        self.selectionChanged.emit() 
     1138 
     1139    def selectedGeneSets(self): 
     1140        selmod = self.gsview.selectionModel() 
     1141        model = self.proxymodel.sourceModel() 
     1142        rows = [self.proxymodel.mapToSource(row) 
     1143                for row in selmod.selectedRows(1)] 
     1144        gsets = [model.data(row, Qt.UserRole) for row in rows] 
     1145        return map(toPyObject, gsets) 
     1146 
     1147 
     1148def sets_to_model(gsets): 
     1149    model = QStandardItemModel() 
     1150    model.setHorizontalHeaderLabels(["Category", "Name"]) 
     1151 
     1152    for (hier, tid), sets in gsets: 
     1153        for gset in sets: 
     1154            ngenes = len(gset.genes) 
     1155            names = [escape(name) for name in list(gset.genes)[:30]] 
     1156            names = ", ".join(names) 
     1157            tooltip = "<p>{0}</p>{1}".format(escape(gset.name), names) 
     1158            if ngenes > 30: 
     1159                tooltip += ", ... ({0} names not shown)".format(ngenes - 30) 
     1160 
     1161            category = QStandardItem(" ".join(hier)) 
     1162            category.setData((hier, tid), Qt.UserRole) 
     1163            category.setEditable(False) 
     1164            category.setToolTip(tooltip) 
     1165            name = QStandardItem(gset.name) 
     1166            name.setData(gset, Qt.UserRole) 
     1167            name.setEditable(False) 
     1168            name.setToolTip(tooltip) 
     1169            model.appendRow([category, name]) 
     1170 
     1171    return model 
     1172 
     1173 
     1174def gs_ensure_downloaded(gslist, progress_info=None): 
     1175    hierlist = [(hier, taxid) for hier, taxid, local in gslist 
     1176                if not local] 
     1177 
     1178    files = [(genesets.sfdomain, genesets.filename(hier, taxid)) 
     1179             for hier, taxid in hierlist] 
     1180 
     1181    download_list(files, progress_info) 
     1182 
     1183 
     1184def download_list(files_list, progress_callback=None): 
     1185    nfiles = len(files_list) 
     1186    count = 100 * nfiles 
     1187    counter = itertools.count() 
     1188 
     1189    def advance(): 
     1190        progress_callback(100.0 * next(counter) / count) 
     1191 
     1192    for domain, filename in files_list: 
     1193        serverfiles.download(domain, filename, 
     1194                             callback=advance if progress_callback else None) 
     1195 
     1196 
     1197class GeneSetDialog(QDialog): 
     1198    selectionChanged = Signal() 
     1199 
     1200    def __init__(self, *args, **kwargs): 
     1201        super(GeneSetDialog, self).__init__(*args, **kwargs) 
     1202        layout = QVBoxLayout() 
     1203        layout.setContentsMargins(4, 4, 4, 4) 
     1204        self.gsview = GeneSetView() 
     1205        self.gsview.selectionChanged.connect(self.selectionChanged) 
     1206 
     1207        layout.addWidget(self.gsview) 
     1208 
     1209        buttonbox = QDialogButtonBox( 
     1210            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, 
     1211            Qt.Horizontal 
     1212        ) 
     1213        buttonbox.accepted.connect(self.accept) 
     1214        buttonbox.rejected.connect(self.reject) 
     1215 
     1216        layout.addWidget(buttonbox) 
     1217 
     1218        self.setLayout(layout) 
     1219 
     1220    def selectedGeneSets(self): 
     1221        return self.gsview.selectedGeneSets() 
     1222 
     1223    def setCurrentOrganism(self, taxid): 
     1224        self.gsview.setCurrentOrganism(taxid) 
     1225 
     1226    def currentOrganism(self): 
     1227        return self.gsview.currentOrganism() 
     1228 
     1229 
     1230def test1(): 
     1231    app = QApplication([]) 
     1232    dlg = GeneSetDialog() 
     1233    dlg.exec_() 
     1234    del dlg 
     1235    app.processEvents() 
     1236 
     1237 
    9781238def test(): 
    9791239    app = QApplication([]) 
Note: See TracChangeset for help on using the changeset viewer.