class OWKEGGPathwayBrowser(widget.OWWidget): name = "KEGG Pathways" description = "Browse KEGG pathways that include an input set of genes." icon = "../widgets/icons/KEGGPathways.svg" priority = 2030 inputs = [("Examples", Orange.data.Table, "SetData", widget.Default), ("Reference", Orange.data.Table, "SetRefData")] outputs = [("Selected Examples", Orange.data.Table, widget.Default), ("Unselected Examples", Orange.data.Table)] settingsHandler = settings.DomainContextHandler() organismIndex = settings.ContextSetting(0) geneAttrIndex = settings.ContextSetting(0) useAttrNames = settings.ContextSetting(False) autoCommit = settings.Setting(False) autoResize = settings.Setting(True) useReference = settings.Setting(False) showOrthology = settings.Setting(True) Ready, Initializing, Running = 0, 1, 2 def __init__(self, parent=None): super().__init__(parent) self.organismCodes = [] self._changedFlag = False self.__invalidated = False self.__runstate = OWKEGGPathwayBrowser.Initializing self.__in_setProgress = False self.controlArea.setMaximumWidth(250) box = gui.widgetBox(self.controlArea, "Info") self.infoLabel = gui.widgetLabel(box, "No data on input\n") # Organism selection. box = gui.widgetBox(self.controlArea, "Organism") self.organismComboBox = gui.comboBox( box, self, "organismIndex", items=[], callback=self.Update, addSpace=True, tooltip="Select the organism of the input genes") # Selection of genes attribute box = gui.widgetBox(self.controlArea, "Gene attribute") self.geneAttrCandidates = itemmodels.VariableListModel(parent=self) self.geneAttrCombo = gui.comboBox( box, self, "geneAttrIndex", callback=self.Update) self.geneAttrCombo.setModel(self.geneAttrCandidates) gui.checkBox(box, self, "useAttrNames", "Use variable names", disables=[(-1, self.geneAttrCombo)], callback=self.Update) self.geneAttrCombo.setDisabled(bool(self.useAttrNames)) gui.separator(self.controlArea) gui.checkBox(self.controlArea, self, "useReference", "From signal", box="Reference", callback=self.Update) gui.separator(self.controlArea) gui.checkBox(self.controlArea, self, "showOrthology", "Show pathways in full orthology", box="Orthology", callback=self.UpdateListView) gui.checkBox(self.controlArea, self, "autoResize", "Resize to fit", box="Image", callback=self.UpdatePathwayViewTransform) box = gui.widgetBox(self.controlArea, "Cache Control") gui.button(box, self, "Clear cache", callback=self.ClearCache, tooltip="Clear all locally cached KEGG data.") gui.separator(self.controlArea) gui.auto_commit(self.controlArea, self, "autoCommit", "Commit") gui.rubber(self.controlArea) spliter = QSplitter(Qt.Vertical, self.mainArea) self.pathwayView = PathwayView(self, spliter) self.pathwayView.scene().selectionChanged.connect( self._onSelectionChanged ) self.mainArea.layout().addWidget(spliter) self.listView = QTreeWidget( allColumnsShowFocus=True, selectionMode=QTreeWidget.SingleSelection, sortingEnabled=True, maximumHeight=200) spliter.addWidget(self.listView) self.listView.setColumnCount(4) self.listView.setHeaderLabels( ["Pathway", "P value", "Genes", "Reference"]) self.listView.itemSelectionChanged.connect(self.UpdatePathwayView) select = QAction( "Select All", self, shortcut=QKeySequence.SelectAll ) select.triggered.connect(self.selectAll) self.addAction(select) self.data = None self.refData = None self._executor = concurrent.ThreadExecutor() self.setEnabled(False) self.setBlocking(True) progress = concurrent.methodinvoke(self, "setProgress", (float,)) def get_genome(): """Return a KEGGGenome with the common org entries precached.""" genome = kegg.KEGGGenome() essential = genome.essential_organisms() common = genome.common_organisms() # Remove duplicates of essential from common. # (essential + common list as defined here will be used in the # GUI.) common = [c for c in common if c not in essential] # TODO: Add option to specify additional organisms not # in the common list. keys = list(map(genome.org_code_to_entry_key, essential + common)) genome.pre_cache(keys, progress_callback=progress) return (keys, genome) self._genomeTask = task = concurrent.Task(function=get_genome) task.finished.connect(self.__initialize_finish) self.progressBarInit() self.infoLabel.setText("Fetching organism definitions\n") self._executor.submit(task) def __initialize_finish(self): if self.__runstate != OWKEGGPathwayBrowser.Initializing: return try: keys, genome = self._genomeTask.result() except Exception as err: self.error(0, str(err)) raise self.progressBarFinished() self.setEnabled(True) self.setBlocking(False) entries = [genome[key] for key in keys] items = [entry.definition for entry in entries] codes = [entry.organism_code for entry in entries] self.organismCodes = codes self.organismComboBox.clear() self.organismComboBox.addItems(items) self.organismComboBox.setCurrentIndex(self.organismIndex) self.infoLabel.setText("No data on input\n") def Clear(self): """ Clear the widget state. """ self.queryGenes = [] self.referenceGenes = [] self.genes = {} self.uniqueGenesDict = {} self.revUniqueGenesDict = {} self.pathways = {} self.org = None self.geneAttrCandidates[:] = [] self.infoLabel.setText("No data on input\n") self.listView.clear() self.pathwayView.SetPathway(None) self.send("Selected Examples", None) self.send("Unselected Examples", None) def SetData(self, data=None): if self.__runstate == OWKEGGPathwayBrowser.Initializing: self.__initialize_finish() self.closeContext() self.data = data self.warning(0) self.error(0) self.information(0) if data is not None: vars = data.domain.variables + data.domain.metas vars = [var for var in vars if isinstance(var, Orange.data.StringVariable)] self.geneAttrCandidates[:] = vars # Try to guess the gene name variable names_lower = [v.name.lower() for v in vars] scores = [(name == "gene", "gene" in name) for name in names_lower] imax, _ = max(enumerate(scores), key=itemgetter(1)) self.geneAttrIndex = imax taxid = data_hints.get_hint(data, "taxid", None) if taxid: try: code = kegg.from_taxid(taxid) self.organismIndex = self.organismCodes.index(code) except Exception as ex: print(ex, taxid) self.useAttrNames = data_hints.get_hint(data, "genesinrows", self.useAttrNames) self.openContext(data) else: self.Clear() self.__invalidated = True def SetRefData(self, data=None): self.refData = data self.information(1) if data is not None and self.useReference: self.__invalidated = True def handleNewSignals(self): if self.__invalidated: self.Update() self.__invalidated = False def UpdateListView(self): self.bestPValueItem = None self.listView.clear() if not self.data: return allPathways = self.org.pathways() allRefPathways = kegg.pathways("map") items = [] kegg_pathways = kegg.KEGGPathways() org_code = self.organismCodes[min(self.organismIndex, len(self.organismCodes) - 1)] if self.showOrthology: self.koOrthology = kegg.KEGGBrite("ko00001") self.listView.setRootIsDecorated(True) path_ids = set([s[-5:] for s in self.pathways.keys()]) def _walkCollect(koEntry): num = koEntry.title[:5] if koEntry.title else None if num in path_ids: return ([koEntry] + reduce(lambda li, c: li + _walkCollect(c), [child for child in koEntry.entries], [])) else: c = reduce(lambda li, c: li + _walkCollect(c), [child for child in koEntry.entries], []) return c + (c and [koEntry] or []) allClasses = reduce(lambda li1, li2: li1 + li2, [_walkCollect(c) for c in self.koOrthology], []) def _walkCreate(koEntry, lvItem): item = QTreeWidgetItem(lvItem) id = "path:" + org_code + koEntry.title[:5] if koEntry.title[:5] in path_ids: p = kegg_pathways.get_entry(id) if p is None: # In case the genesets still have obsolete entries name = koEntry.title else: name = p.name genes, p_value, ref = self.pathways[id] item.setText(0, name) item.setText(1, "%.5f" % p_value) item.setText(2, "%i of %i" % (len(genes), len(self.genes))) item.setText(3, "%i of %i" % (ref, len(self.referenceGenes))) item.pathway_id = id if p is not None else None else: if id in allPathways: text = kegg_pathways.get_entry(id).name else: text = koEntry.title item.setText(0, text) if id in allPathways: item.pathway_id = id elif "path:map" + koEntry.title[:5] in allRefPathways: item.pathway_id = "path:map" + koEntry.title[:5] else: item.pathway_id = None for child in koEntry.entries: if child in allClasses: _walkCreate(child, item) for koEntry in self.koOrthology: if koEntry in allClasses: _walkCreate(koEntry, self.listView) self.listView.update() else: self.listView.setRootIsDecorated(False) pathways = self.pathways.items() pathways = sorted(pathways, key=lambda item: item[1][1]) for id, (genes, p_value, ref) in pathways: item = QTreeWidgetItem(self.listView) item.setText(0, kegg_pathways.get_entry(id).name) item.setText(1, "%.5f" % p_value) item.setText(2, "%i of %i" % (len(genes), len(self.genes))) item.setText(3, "%i of %i" % (ref, len(self.referenceGenes))) item.pathway_id = id items.append(item) self.bestPValueItem = items and items[0] or None self.listView.expandAll() for i in range(4): self.listView.resizeColumnToContents(i) if self.bestPValueItem: index = self.listView.indexFromItem(self.bestPValueItem) self.listView.selectionModel().select( index, QItemSelectionModel.ClearAndSelect ) def UpdatePathwayView(self): items = self.listView.selectedItems() if len(items) > 0: item = items[0] else: item = None self.commit() item = item or self.bestPValueItem if not item or not item.pathway_id: self.pathwayView.SetPathway(None) return def get_kgml_and_image(pathway_id): """Return an initialized KEGGPathway with pre-cached data""" p = kegg.KEGGPathway(pathway_id) p._get_kgml() # makes sure the kgml file is downloaded p._get_image_filename() # makes sure the image is downloaded return (pathway_id, p) self.setEnabled(False) self._pathwayTask = concurrent.Task( function=lambda: get_kgml_and_image(item.pathway_id) ) self._pathwayTask.finished.connect(self._onPathwayTaskFinshed) self._executor.submit(self._pathwayTask) def _onPathwayTaskFinshed(self): self.setEnabled(True) pathway_id, self.pathway = self._pathwayTask.result() self.pathwayView.SetPathway( self.pathway, self.pathways.get(pathway_id, [[]])[0] ) def UpdatePathwayViewTransform(self): self.pathwayView.updateTransform() def Update(self): """ Update (recompute enriched pathways) the widget state. """ if not self.data: return self.error(0) self.information(0) # XXX: Check data in setData, do not even alow this to be executed if # data has no genes try: genes = self.GeneNamesFromData(self.data) except ValueError: self.error(0, "Cannot extract gene names from input.") genes = [] if not self.useAttrNames and any("," in gene for gene in genes): genes = reduce(add, (split_and_strip(gene, ",") for gene in genes), []) self.information(0, "Separators detected in input gene names. " "Assuming multiple genes per instance.") self.queryGenes = genes self.information(1) reference = None if self.useReference and self.refData: reference = self.GeneNamesFromData(self.refData) if not self.useAttrNames \ and any("," in gene for gene in reference): reference = reduce(add, (split_and_strip(gene, ",") for gene in reference), []) self.information(1, "Separators detected in reference gene " "names. Assuming multiple genes per " "instance.") org_code = self.SelectedOrganismCode() def run_enrichment(org_code, genes, reference=None, progress=None): org = kegg.KEGGOrganism(org_code) if reference is None: reference = org.get_genes() # Map 'genes' and 'reference' sets to unique KEGG identifiers unique_genes, _, _ = org.get_unique_gene_ids(set(genes)) unique_ref_genes, _, _ = org.get_unique_gene_ids(set(reference)) taxid = kegg.to_taxid(org.org_code) # Map the taxid back to standard 'common' taxids # (as used by 'geneset') if applicable r_tax_map = dict((v, k) for k, v in kegg.KEGGGenome.TAXID_MAP.items()) if taxid in r_tax_map: taxid = r_tax_map[taxid] # We use the kegg pathway gene sets provided by 'geneset' for # the enrichment calculation. # Ensure we are using the latest genesets # TODO: ?? Is updating the index enough? serverfiles.update(geneset.sfdomain, "index.pck") kegg_gs_collections = geneset.collections( (("KEGG", "pathways"), taxid) ) pathways = pathway_enrichment( kegg_gs_collections, unique_genes.keys(), unique_ref_genes.keys(), callback=progress ) # Ensure that pathway entries are pre-cached for later use in the # list/tree view kegg_pathways = kegg.KEGGPathways() kegg_pathways.pre_cache( pathways.keys(), progress_callback=progress ) return pathways, org, unique_genes, unique_ref_genes self.progressBarInit() self.setEnabled(False) self.infoLabel.setText("Retrieving...\n") progress = concurrent.methodinvoke(self, "setProgress", (float,)) self._enrichTask = concurrent.Task( function=lambda: run_enrichment(org_code, genes, reference, progress) ) self._enrichTask.finished.connect(self._onEnrichTaskFinished) self._executor.submit(self._enrichTask) def _onEnrichTaskFinished(self): self.setEnabled(True) self.setBlocking(False) try: pathways, org, unique_genes, unique_ref_genes = \ self._enrichTask.result() except Exception: raise self.progressBarFinished() self.org = org self.genes = unique_genes.keys() self.uniqueGenesDict = unique_genes self.revUniqueGenesDict = dict([(val, key) for key, val in self.uniqueGenesDict.items()]) self.referenceGenes = unique_ref_genes.keys() self.pathways = pathways if not self.pathways: self.warning(0, "No enriched pathways found.") else: self.warning(0) count = len(set(self.queryGenes)) self.infoLabel.setText( "%i unique gene names on input\n" "%i (%.1f%%) genes names matched" % (count, len(unique_genes), 100.0 * len(unique_genes) / count if count else 0.0) ) self.UpdateListView() @Slot(float) def setProgress(self, value): if self.__in_setProgress: return self.__in_setProgress = True self.progressBarSet(value) self.__in_setProgress = False def GeneNamesFromData(self, data): """ Extract and return gene names from `data`. """ if self.useAttrNames: genes = [str(v.name).strip() for v in data.domain.attributes] elif self.geneAttrCandidates: index = min(self.geneAttrIndex, len(self.geneAttrCandidates) - 1) geneAttr = self.geneAttrCandidates[index] genes = [str(e[geneAttr]) for e in data if not numpy.isnan(e[geneAttr])] else: raise ValueError("No gene names in data.") return genes def SelectedOrganismCode(self): """ Return the selected organism code. """ return self.organismCodes[min(self.organismIndex, len(self.organismCodes) - 1)] def selectAll(self): """ Select all items in the pathway view. """ changed = False scene = self.pathwayView.scene() with disconnected(scene.selectionChanged, self._onSelectionChanged): for item in scene.items(): if item.flags() & QGraphicsItem.ItemIsSelectable and \ not item.isSelected(): item.setSelected(True) changed = True if changed: self._onSelectionChanged() def _onSelectionChanged(self): # Item selection in the pathwayView/scene has changed self.commit() def commit(self): if self.data: selectedItems = self.pathwayView.scene().selectedItems() selectedGenes = reduce(set.union, [item.marked_objects for item in selectedItems], set()) if self.useAttrNames: selected = [self.data.domain[self.uniqueGenesDict[gene]] for gene in selectedGenes] # newDomain = Orange.data.Domain(selectedVars, 0) data = self.data[:, selected] # data = Orange.data.Table(newDomain, self.data) self.send("Selected Examples", data) elif self.geneAttrCandidates: geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates) - 1)] selectedIndices = [] otherIndices = [] for i, ex in enumerate(self.data): names = [self.revUniqueGenesDict.get(name, None) for name in split_and_strip(str(ex[geneAttr]), ",")] if any(name and name in selectedGenes for name in names): selectedIndices.append(i) else: otherIndices.append(i) if selectedIndices: selected = self.data[selectedIndices] else: selected = None if otherIndices: other = self.data[otherIndices] else: other = None self.send("Selected Examples", selected) self.send("Unselected Examples", other) else: self.send("Selected Examples", None) self.send("Unselected Examples", None) def ClearCache(self): kegg.caching.clear_cache() def onDeleteWidget(self): """ Called before the widget is removed from the canvas. """ super().onDeleteWidget() self.org = None self._executor.shutdown(wait=False) gc.collect() # Force collection (WHY?) def sizeHint(self): return QSize(1024, 720)
class OWItemsets(widget.OWWidget): name = 'Frequent Itemsets' description = 'Explore sets of items that frequently appear together.' icon = 'icons/FrequentItemsets.svg' priority = 10 inputs = [("Data", Table, 'set_data')] outputs = [(Output.DATA, Table)] minSupport = settings.Setting(30) maxItemsets = settings.Setting(10000) filterSearch = settings.Setting(True) autoFind = settings.Setting(False) autoSend = settings.Setting(True) filterKeywords = settings.Setting('') filterMinItems = settings.Setting(1) filterMaxItems = settings.Setting(10000) UserAdviceMessages = [ widget.Message('Itemset are listed in item-sorted order, i.e. ' 'an itemset containing A and B is only listed once, as ' 'A > B (and not also B > A).', 'itemsets-order', widget.Message.Warning), widget.Message('To select all the itemsets that are descendants of ' '(include) some item X (i.e. the whole subtree), you ' 'can fold the subtree at that item and then select it.', 'itemsets-order', widget.Message.Information) ] def __init__(self): self.tree = QTreeWidget(self.mainArea, columnCount=2, allColumnsShowFocus=True, alternatingRowColors=True, selectionMode=QTreeWidget.ExtendedSelection, uniformRowHeights=True) self.tree.setHeaderLabels(["Itemsets", "Support", "%"]) self.tree.header().setStretchLastSection(True) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.mainArea.layout().addWidget(self.tree) box = gui.widgetBox(self.controlArea, "Info") self.nItemsets = self.nSelectedExamples = self.nSelectedItemsets = '' gui.label(box, self, "Number of itemsets: %(nItemsets)s") gui.label(box, self, "Selected itemsets: %(nSelectedItemsets)s") gui.label(box, self, "Selected examples: %(nSelectedExamples)s") hbox = gui.widgetBox(box, orientation='horizontal') gui.button(hbox, self, "Expand all", callback=self.tree.expandAll) gui.button(hbox, self, "Collapse all", callback=self.tree.collapseAll) box = gui.widgetBox(self.controlArea, 'Find itemsets') gui.hSlider(box, self, 'minSupport', minValue=1, maxValue=100, label='Minimal support:', labelFormat="%d%%", callback=lambda: self.find_itemsets()) gui.hSlider(box, self, 'maxItemsets', minValue=10000, maxValue=100000, step=10000, label='Max. number of itemsets:', labelFormat="%d", callback=lambda: self.find_itemsets()) gui.checkBox(box, self, 'filterSearch', label='Apply below filters in search', tooltip='If checked, the itemsets are filtered according ' 'to below filter conditions already in the search ' 'phase. \nIf unchecked, the only filters applied ' 'during search are the ones above, ' 'and the itemsets are \nfiltered afterwards only for ' 'display, i.e. only the matching itemsets are shown.') self.button = gui.auto_commit( box, self, 'autoFind', 'Find itemsets', commit=self.find_itemsets) box = gui.widgetBox(self.controlArea, 'Filter itemsets') gui.lineEdit(box, self, 'filterKeywords', 'Contains:', callback=self.filter_change, orientation='horizontal', tooltip='A comma or space-separated list of regular ' 'expressions.') hbox = gui.widgetBox(box, orientation='horizontal') gui.spin(hbox, self, 'filterMinItems', 1, 998, label='Min. items:', callback=self.filter_change) gui.spin(hbox, self, 'filterMaxItems', 2, 999, label='Max. items:', callback=self.filter_change) gui.rubber(hbox) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, 'autoSend', 'Send selection') self.filter_change() def sendReport(self): self.reportSettings("Itemset statistics", [("Number of itemsets", self.nItemsets), ("Selected itemsets", self.nSelectedItemsets), ("Covered examples", self.nSelectedExamples), ]) self.reportSection("Itemsets") self.reportRaw(OWReport.reportTree(self.tree)) ITEM_DATA_ROLE = Qt.UserRole + 1 def selectionChanged(self): X = self.data.X mapping = self.onehot_mapping instances = set() where = np.where def whole_subtree(node): yield node for i in range(node.childCount()): yield from whole_subtree(node.child(i)) def itemset(node): while node: yield node.data(0, self.ITEM_DATA_ROLE) node = node.parent() def selection_ranges(node): n_children = node.childCount() if n_children: yield (self.tree.indexFromItem(node.child(0)), self.tree.indexFromItem(node.child(n_children - 1))) for i in range(n_children): yield from selection_ranges(node.child(i)) nSelectedItemsets = 0 item_selection = QItemSelection() for node in self.tree.selectedItems(): nodes = (node,) if node.isExpanded() else whole_subtree(node) if not node.isExpanded(): for srange in selection_ranges(node): item_selection.select(*srange) for node in nodes: nSelectedItemsets += 1 cols, vals = zip(*(mapping[i] for i in itemset(node))) instances.update(where((X[:, cols] == vals).all(axis=1))[0]) self.tree.itemSelectionChanged.disconnect(self.selectionChanged) self.tree.selectionModel().select(item_selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.nSelectedExamples = len(instances) self.nSelectedItemsets = nSelectedItemsets self.output = self.data[sorted(instances)] or None self.commit() def commit(self): self.send(Output.DATA, self.output) def filter_change(self): isRegexMatch = self.isRegexMatch = re.compile( '|'.join(i.strip() for i in re.split('(,|\s)+', self.filterKeywords.strip()) if i.strip())).search def hide(node, depth, has_kw): if not has_kw: has_kw = isRegexMatch(node.text(0)) hidden = (sum(hide(node.child(i), depth + 1, has_kw) for i in range(node.childCount())) == node.childCount() if node.childCount() else (not has_kw or not self.filterMinItems <= depth <= self.filterMaxItems)) node.setHidden(hidden) return hidden hide(self.tree.invisibleRootItem(), 0, False) class TreeWidgetItem(QTreeWidgetItem): def data(self, column, role): """Construct lazy tooltips""" if role != Qt.ToolTipRole: return super().data(column, role) tooltip = [] while self: tooltip.append(self.text(0)) self = self.parent() return ' '.join(reversed(tooltip)) def find_itemsets(self): if self.data is None: return data = self.data self.tree.clear() self.tree.setUpdatesEnabled(False) self.tree.blockSignals(True) class ItemDict(dict): def __init__(self, item): self.item = item top = ItemDict(self.tree.invisibleRootItem()) X, mapping = OneHot.encode(data) self.onehot_mapping = mapping names = {item: '{}={}'.format(var.name, val) for item, var, val in OneHot.decode(mapping.keys(), data, mapping)} nItemsets = 0 filterSearch = self.filterSearch filterMinItems, filterMaxItems = self.filterMinItems, self.filterMaxItems isRegexMatch = self.isRegexMatch # Find itemsets and populate the TreeView progress = gui.ProgressBar(self, self.maxItemsets + 1) for itemset, support in frequent_itemsets(X, self.minSupport / 100): if filterSearch and not filterMinItems <= len(itemset) <= filterMaxItems: continue parent = top first_new_item = None itemset_matches_filter = False for item in sorted(itemset): name = names[item] if filterSearch and not itemset_matches_filter: itemset_matches_filter = isRegexMatch(name) child = parent.get(name) if child is None: wi = self.TreeWidgetItem(parent.item, [name, str(support), '{:.1f}'.format(100 * support / len(data))]) wi.setData(0, self.ITEM_DATA_ROLE, item) child = parent[name] = ItemDict(wi) if first_new_item is None: first_new_item = (parent, name) parent = child if filterSearch and not itemset_matches_filter: parent, name = first_new_item parent.item.removeChild(parent[name].item) del parent[name].item del parent[name] else: nItemsets += 1 progress.advance() if nItemsets >= self.maxItemsets: break if not filterSearch: self.filter_change() self.nItemsets = nItemsets self.nSelectedItemsets = 0 self.nSelectedExamples = 0 self.tree.expandAll() for i in range(self.tree.columnCount()): self.tree.resizeColumnToContents(i) self.tree.setUpdatesEnabled(True) self.tree.blockSignals(False) progress.finish() def set_data(self, data): self.data = data if data is not None: self.warning(0, 'Data has continuous attributes which will be skipped.' if data.domain.has_continuous_attributes() else None) self.error(1, 'Discrete features required but data has none.' if not data.domain.has_discrete_attributes() else None) self.button.setDisabled(not data.domain.has_discrete_attributes()) if self.autoFind: self.find_itemsets()
class Shortcuts(preferences.Page): def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton( icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager( win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = list(allactions.keys()) def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelerator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0) def items(self): """Yield all the items in the actions tree.""" def children(item): for i in range(item.childCount()): c = item.child(i) if c.childCount(): for c1 in children(c): yield c1 else: yield c for c in children(self.tree.invisibleRootItem()): yield c def item(self, collection, name): for item in self.items(): if item.collection.name == collection and item.name == name: return item def saveSettings(self): self.scheme.saveSettings("shortcut_scheme", "shortcut_schemes", "shortcuts") for item in self.items(): for scheme in self.scheme.schemes(): item.save(scheme) item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def loadSettings(self): self.scheme.loadSettings("shortcut_scheme", "shortcut_schemes") # clear the settings in all the items for item in self.items(): item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def slotSchemeChanged(self): """Called when the Scheme combobox is changed by the user.""" for item in self.items(): item.switchScheme(self.scheme.currentScheme()) def slotCurrentItemChanged(self, item): if isinstance(item, ShortcutItem): self.edit.setText( _("&Edit Shortcut for \"{name}\"").format(name=item.text(0))) self.edit.setEnabled(True) global _lastaction _lastaction = item.name else: self.edit.setText(_("(no shortcut)")) self.edit.setEnabled(False) def import_(self, filename): from . import import_export import_export.importShortcut(filename, self, self.scheme) def export(self, name, filename): from . import import_export try: import_export.exportShortcut(self, self.scheme.currentScheme(), name, filename) except (IOError, OSError) as e: QMessageBox.critical( self, _("Error"), _("Can't write to destination:\n\n{url}\n\n{error}").format( url=filename, error=e.strerror)) def findShortcutConflict(self, shortcut): """Find the possible shortcut conflict and return the conflict name.""" if shortcut: item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return None scheme = self.scheme.currentScheme() for i in self.items(): a = i.action(scheme) if i != item and a.shortcuts(): for s1 in a.shortcuts(): if s1.matches(shortcut) or shortcut.matches(s1): return qutil.removeAccelerator(a.text()) return None def editCurrentItem(self): item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return dlg = ShortcutEditDialog(self, self.findShortcutConflict) scheme = self.scheme.currentScheme() action = item.action(scheme) default = item.defaultShortcuts() or None if dlg.editAction(action, default): shortcuts = action.shortcuts() # check for conflicts conflicting = [] for i in self.items(): if i is not item: for s1, s2 in itertools.product(i.shortcuts(scheme), shortcuts): if s1.matches(s2) or s2.matches(s1): conflicting.append(i) if conflicting: for i in conflicting: l = i.shortcuts(scheme) for s1 in list(l): # copy for s2 in shortcuts: if s1.matches(s2) or s2.matches(s1): l.remove(s1) i.setShortcuts(l, scheme) # store the shortcut item.setShortcuts(shortcuts, scheme) self.changed.emit()
class Shortcuts(preferences.Page): def __init__(self, dialog): super(Shortcuts, self).__init__(dialog) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.scheme = SchemeSelector(self) layout.addWidget(self.scheme) self.tree = QTreeWidget(self) self.tree.setHeaderLabels([_("Command"), _("Shortcut")]) self.tree.setRootIsDecorated(False) self.tree.setColumnCount(2) self.tree.setAllColumnsShowFocus(True) self.tree.setAnimated(True) layout.addWidget(self.tree) self.edit = QPushButton(icons.get("preferences-desktop-keyboard-shortcuts"), '') layout.addWidget(self.edit) # signals self.scheme.currentChanged.connect(self.slotSchemeChanged) self.scheme.changed.connect(self.changed) self.tree.currentItemChanged.connect(self.slotCurrentItemChanged) self.tree.itemDoubleClicked.connect(self.editCurrentItem) self.edit.clicked.connect(self.editCurrentItem) # make a dict of all actions with the actions as key and the names as # value, with the collection prepended (for loading/saving) win = dialog.parent() allactions = {} for collection in actioncollectionmanager.manager(win).actionCollections(): for name, action in collection.actions().items(): allactions[action] = (collection, name) # keep a list of actions not in the menu structure left = allactions.keys() def add_actions(menuitem, actions): """Add actions to a QTreeWidgetItem.""" for a in actions: if a.menu(): item = build_menu_item(a) if item.childCount(): menuitem.addChild(item) elif a in left: left.remove(a) menuitem.addChild(ShortcutItem(a, *allactions[a])) menuitem.setFlags(Qt.ItemIsEnabled) # disable selection def build_menu_item(action): """Return a QTreeWidgetItem with children for all the actions in the submenu.""" menuitem = QTreeWidgetItem() text = qutil.removeAccelelator(action.text()) menuitem.setText(0, _("Menu {name}").format(name=text)) add_actions(menuitem, action.menu().actions()) return menuitem # present the actions nicely ordered as in the menus for a in win.menuBar().actions(): menuitem = build_menu_item(a) if menuitem.childCount(): self.tree.addTopLevelItem(menuitem) # sort leftover actions left.sort(key=lambda i: i.text()) # show actions that are left, grouped by collection titlegroups = {} for a in left[:]: # copy collection, name = allactions[a] if collection.title(): titlegroups.setdefault(collection.title(), []).append(a) left.remove(a) for title in sorted(titlegroups): item = QTreeWidgetItem(["{0}:".format(title)]) for a in titlegroups[title]: item.addChild(ShortcutItem(a, *allactions[a])) self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection # show other actions that were not in the menus item = QTreeWidgetItem([_("Other commands:")]) for a in left: if a.text() and not a.menu(): item.addChild(ShortcutItem(a, *allactions[a])) if item.childCount(): self.tree.addTopLevelItem(item) item.setFlags(Qt.ItemIsEnabled) # disable selection self.tree.expandAll() item = self.tree.topLevelItem(0).child(0) if _lastaction: # find the previously selected item for i in self.items(): if i.name == _lastaction: item = i break self.tree.setCurrentItem(item) self.tree.resizeColumnToContents(0) def items(self): """Yield all the items in the actions tree.""" def children(item): for i in range(item.childCount()): c = item.child(i) if c.childCount(): for c1 in children(c): yield c1 else: yield c for c in children(self.tree.invisibleRootItem()): yield c def saveSettings(self): self.scheme.saveSettings("shortcut_scheme", "shortcut_schemes", "shortcuts") for item in self.items(): for scheme in self.scheme.schemes(): item.save(scheme) item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def loadSettings(self): self.scheme.loadSettings("shortcut_scheme", "shortcut_schemes") # clear the settings in all the items for item in self.items(): item.clearSettings() item.switchScheme(self.scheme.currentScheme()) def slotSchemeChanged(self): """Called when the Scheme combobox is changed by the user.""" for item in self.items(): item.switchScheme(self.scheme.currentScheme()) def slotCurrentItemChanged(self, item): if isinstance(item, ShortcutItem): self.edit.setText( _("&Edit Shortcut for \"{name}\"").format(name=item.text(0))) self.edit.setEnabled(True) global _lastaction _lastaction = item.name else: self.edit.setText(_("(no shortcut)")) self.edit.setEnabled(False) def editCurrentItem(self): item = self.tree.currentItem() if not isinstance(item, ShortcutItem): return try: dlg = self._editdialog except AttributeError: dlg = self._editdialog = ShortcutEditDialog(self) scheme = self.scheme.currentScheme() action = item.action(scheme) default = item.defaultShortcuts() if dlg.editAction(action, default): shortcuts = action.shortcuts() # check for conflicts conflicting = [] for i in self.items(): if i is not item: for s1, s2 in itertools.product(i.shortcuts(scheme), shortcuts): if s1.matches(s2) or s2.matches(s1): conflicting.append(i) if conflicting: # show a question dialog msg = [_("This shortcut conflicts with the following command:", "This shortcut conflicts with the following commands:", len(conflicting))] msg.append('<br/>'.join(i.text(0) for i in conflicting)) msg.append(_("Remove the shortcut from that command?", "Remove the shortcut from those commands?", len(conflicting))) msg = '<p>{0}</p>'.format('</p><p>'.join(msg)) res = QMessageBox.warning(self, _("Shortcut Conflict"), msg, QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if res == QMessageBox.Yes: # remove from conflicting for i in conflicting: l = i.shortcuts(scheme) for s1 in list(l): # copy for s2 in shortcuts: if s1.matches(s2) or s2.matches(s1): l.remove(s1) i.setShortcuts(l, scheme) elif res == QMessageBox.No: # remove from ourselves for i in conflicting: for s1 in list(shortcuts): # copy for s2 in i.shortcuts(scheme): if s1.matches(s2) or s2.matches(s1): shortcuts.remove(s1) else: return # cancelled # store the shortcut item.setShortcuts(shortcuts, scheme) self.changed.emit()
def expandAll(self): self._treeDepth = 10000 QTreeWidget.expandAll(self)
def __init__(self, term, parent=None): super(FeeDialog, self).__init__(parent) self.term = term self.sid = term terms = self.pullOnes('terms', self.term) session = self.pullOnes('session', terms['sessionID']) self.termname = str(session['name'])+' '+terms['name']+' Term Report' self.pagetitle = self.termname ko = 0 Form1 = QFormLayout() Form2 = QFormLayout() #title self.title = QLabel("Set Fees") self.titleData = QComboBox() self.titleData.setObjectName("name") #self.titleData.setPlaceHolderText("e.g. 2019 FIRST TERM RESULT") tree = QTreeWidget() tree.setItemDelegate(Delegate()) tree.setHeaderLabel("Which grading system will you be using?") tree1 = QTreeWidget() tree1.setHeaderLabel("Choose Assessments and Classes") tree2 = QTreeWidget() tree2.setHeaderLabel("Report Card Settings") self.ass_arr = {} parent = QTreeWidgetItem(tree1) parent.setText(0, "Select Assessments") parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) arr = self.pullCas() if arr and len(arr) > 0: for val in arr: dt = self.pullOne(val['name']) child = QTreeWidgetItem(parent) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(dt['name']).upper()) self.ass_arr[val['name']] = child if (val['active'] == 0): child.setCheckState(0, Qt.Unchecked) else: child.setCheckState(0, Qt.Unchecked) ko += 1 self.cla_arr ={} parent1 = QTreeWidgetItem(tree1) parent1.setText(0, "Select Class") parent1.setFlags(parent1.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) arr = self.pullClass() if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(parent1) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) self.cla_arr[val['id']] = child if (val['active'] == 0): child.setCheckState(0, Qt.Unchecked) else: child.setCheckState(0, Qt.Unchecked) ko += 1 self.gra_arr = {} parent2 = QTreeWidgetItem(tree) parent2.setText(0, "Select Grade") arr = self.pullGrade() if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(parent2) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) self.gra_arr[val['id']] = child if (val['active'] == 0): child.setCheckState(0, Qt.Unchecked) else: child.setCheckState(0, Qt.Unchecked) ko += 1 self.set_arr= {} parent3 = QTreeWidgetItem(tree2) parent3.setText(0, "Include ...") parent3.setFlags(parent3.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) arr ={ 1:'School Number', 2:'Class Position', 3:'Class Unit Position', 4:'Total (100%)', 5:'Total', 6:'Grading', 7:'Subject Average', 8:'Ranking', 9:'Ranking and Student Population', 10:'Student Passport', 11:'School Logo', 12:'School Address', 13:'Students Address', 14:'Attendance', 15:'Fees Owed', 16:'Test/Assesments' } if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(parent3) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(arr[val]).upper()) self.set_arr[val] = child child.setCheckState(0, Qt.Unchecked) child1 = QTreeWidgetItem(parent3) child1.setFlags(child1.flags() | Qt.ItemIsUserCheckable) child1.setText(0, 'AFFECTIVE DOMAIN REPORT') self.set_arr['aff'] = child1 child1.setCheckState(0, Qt.Unchecked) child2 = QTreeWidgetItem(child1) child2.setFlags(child2.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) child2.setText(0, 'TABLE') self.set_arr['afftable'] = child2 child2.setCheckState(0, Qt.Unchecked) child3 = QTreeWidgetItem(child1) child3.setFlags(child3.flags() | Qt.ItemIsUserCheckable) child3.setText(0, 'GRAPH') self.set_arr['affgraph'] = child3 child3.setCheckState(0, Qt.Unchecked) child4 = QTreeWidgetItem(parent3) child4.setFlags(child4.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) child4.setText(0, 'PYSCHOMOTOR DOMAIN REPORT') self.set_arr['psy'] = child4 child4.setCheckState(0, Qt.Unchecked) child5 = QTreeWidgetItem(child4) child5.setFlags(child5.flags() | Qt.ItemIsUserCheckable) child5.setText(0, 'TABLE') self.set_arr['psytable'] = child5 child5.setCheckState(0, Qt.Unchecked) child6 = QTreeWidgetItem(child4) child6.setFlags(child6.flags() | Qt.ItemIsUserCheckable) child6.setText(0, 'GRAPH') self.set_arr['psygraph'] = child6 child6.setCheckState(0, Qt.Unchecked) tree.expandAll() tree1.expandAll() tree2.expandAll() #tree.show() self.l5 = QLabel("Theme Color") self.pbc = QPushButton() self.pbc.setObjectName("Pickcolor") self.pbc.setText("Click to change") self.le5 = QLineEdit() self.le5.setObjectName("Showcolor") self.le5.setText("#000000") self.pbc.setStyleSheet("background-color: black; color: white") self.connect(self.pbc, SIGNAL("clicked()"), lambda: self.color_picker()) self.l6 = QLabel("Pick Theme Font") self.pbf = QPushButton() self.pbf.setObjectName("Pickfont") self.pbf.setText("Click to Change") self.le6 = QLineEdit() self.le6.setObjectName("Showcolor") self.le6.setText("#000000") self.pbf.setStyleSheet("background-color: black; color: white") self.connect(self.pbf, SIGNAL("clicked()"), lambda: self.font_picker()) self.lv_box = QHBoxLayout() self.lv_box.addWidget(self.pbc) self.lv_box.addWidget(self.le5) self.lv_box1 = QHBoxLayout() self.lv_box1.addWidget(self.pbf) self.lv_box1.addWidget(self.le6) Form1.addRow(self.title, self.titleData) Form2.addRow(self.l5, self.lv_box) Form2.addRow(self.l6, self.lv_box1) Gbo = QGridLayout() Gbo.addLayout(Form1, 0, 0, 1, 2) Gbo.addWidget(tree, 1, 0) Gbo.addWidget(tree1, 1, 1) Gbo.addWidget(tree2, 2, 0) Gbo.addLayout(Form2, 2, 1) groupBox1 = QGroupBox('Academic Report Setup') groupBox1.setLayout(Gbo) self.pb = QPushButton() self.pb.setObjectName("Add") self.pb.setText("Save") self.pb1 = QPushButton() self.pb1.setObjectName("Cancel") self.pb1.setText("Cancel") self.pb2 = QPushButton() self.pb2.setObjectName("Save") self.pb2.setText("Save and Keep Template") self.lTemplate = QLineEdit() self.lTemplate.setPlaceholderText('Template Name') self.rTemplate = QLabel() self.rTemplate.setText('') hbo = QHBoxLayout() hbo.addWidget(self.pb1) hbo.addStretch() hbo.addWidget(self.lTemplate) hbo.addWidget(self.pb2) hbo.addWidget(self.rTemplate) hbo.addStretch() hbo.addWidget(self.pb) groupBox2 = QGroupBox('') groupBox2.setLayout(hbo) grid = QGridLayout() grid.addWidget(groupBox1, 0, 0) grid.addWidget(groupBox2, 1, 0) self.setLayout(grid) self.connect(self.pb, SIGNAL("clicked()"), lambda: self.button_click(self)) self.connect(self.pb2, SIGNAL("clicked()"), lambda: self.button_template(self)) self.connect(self.pb1, SIGNAL("clicked()"), lambda: self.button_close(self)) self.setWindowTitle(self.pagetitle)
class TreeSymbolsWidget(QDialog): """Class of Dialog for Tree Symbols""" def __init__(self, parent=None): super(TreeSymbolsWidget, self).__init__(parent, Qt.WindowStaysOnTopHint) vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.tree = QTreeWidget() vbox.addWidget(self.tree) self.tree.header().setHidden(True) self.tree.setSelectionMode(self.tree.SingleSelection) self.tree.setAnimated(True) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self.tree.header().setStretchLastSection(False) self.actualSymbols = ('', {}) self.docstrings = {} self.collapsedItems = {} self.connect(self, SIGNAL("itemClicked(QTreeWidgetItem *, int)"), self._go_to_definition) self.connect(self, SIGNAL("itemActivated(QTreeWidgetItem *, int)"), self._go_to_definition) self.tree.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self, SIGNAL("customContextMenuRequested(const QPoint &)"), self._menu_context_tree) self.connect(self, SIGNAL("itemCollapsed(QTreeWidgetItem *)"), self._item_collapsed) self.connect(self, SIGNAL("itemExpanded(QTreeWidgetItem *)"), self._item_expanded) IDE.register_service('symbols_explorer', self) ExplorerContainer.register_tab(translations.TR_TAB_SYMBOLS, self) def install_tab(self): """Connect signals for goingdown""" ide = IDE.get_service('ide') self.connect(ide, SIGNAL("goingDown()"), self.close) def _menu_context_tree(self, point): """Context menu""" index = self.tree.indexAt(point) if not index.isValid(): return menu = QMenu(self) f_all = menu.addAction(translations.TR_FOLD_ALL) u_all = menu.addAction(translations.TR_UNFOLD_ALL) menu.addSeparator() u_class = menu.addAction(translations.TR_UNFOLD_CLASSES) u_class_method = menu.addAction( translations.TR_UNFOLD_CLASSES_AND_METHODS) u_class_attr = menu.addAction( translations.TR_UNFOLD_CLASSES_AND_ATTRIBUTES) menu.addSeparator() #save_state = menu.addAction(self.tr("Save State")) self.connect(f_all, SIGNAL("triggered()"), lambda: self.tree.collapseAll()) self.connect(u_all, SIGNAL("triggered()"), lambda: self.tree.expandAll()) self.connect(u_class, SIGNAL("triggered()"), self._unfold_class) self.connect(u_class_method, SIGNAL("triggered()"), self._unfold_class_method) self.connect(u_class_attr, SIGNAL("triggered()"), self._unfold_class_attribute) #self.connect(save_state, SIGNAL("triggered()"), #self._save_symbols_state) menu.exec_(QCursor.pos()) def _get_classes_root(self): """Return the root of classes""" class_root = None for i in range(self.tree.topLevelItemCount()): item = self.tree.topLevelItem(i) if item.isClass and not item.isClickable: class_root = item break return class_root def _unfold_class(self): """Method to Unfold Classes""" self.tree.collapseAll() classes_root = self._get_classes_root() if not classes_root: return classes_root.setExpanded(True) def _unfold_class_method(self): """Method to Unfold Methods""" self.tree.expandAll() classes_root = self._get_classes_root() if not classes_root: return #for each class! for i in range(classes_root.childCount()): class_item = classes_root.child(i) #for each attribute or functions for j in range(class_item.childCount()): item = class_item.child(j) #METHODS ROOT!! if not item.isMethod and not item.isClickable: item.setExpanded(False) break def _unfold_class_attribute(self): """Method to Unfold Attributes""" self.tree.expandAll() classes_root = self._get_classes_root() if not classes_root: return #for each class! for i in range(classes_root.childCount()): class_item = classes_root.child(i) #for each attribute or functions for j in range(class_item.childCount()): item = class_item.child(j) #ATTRIBUTES ROOT!! if not item.isAttribute and not item.isClickable: item.setExpanded(False) break def _save_symbols_state(self): """Method to Save a persistent Symbols state""" #filename = self.actualSymbols[0] #TODO: persist self.collapsedItems[filename] in QSettings pass def _get_expand(self, item): """ Returns True or False to be used as setExpanded() with the items It method is based on the click that the user made in the tree """ name = self._get_unique_name(item) filename = self.actualSymbols[0] collapsed_items = self.collapsedItems.get(filename, []) can_check = (not item.isClickable) or item.isClass or item.isMethod if can_check and name in collapsed_items: return False return True @staticmethod def _get_unique_name(item): """ Returns a string used as unique name """ # className_Attributes/className_Functions parent = item.parent() if parent: return "%s_%s" % (parent.text(0), item.text(0)) return "_%s" % item.text(0) def update_symbols_tree(self, symbols, filename='', parent=None): """Method to Update the symbols on the Tree""" if not parent: if filename == self.actualSymbols[0] and \ self.actualSymbols[1] and not symbols: return if symbols == self.actualSymbols[1]: # Nothing new then return return # we have new symbols refresh it self.tree.clear() self.actualSymbols = (filename, symbols) self.docstrings = symbols.get('docstrings', {}) parent = self.tree if 'attributes' in symbols: globalAttribute = ItemTree(parent, [translations.TR_ATTRIBUTES]) globalAttribute.isClickable = False globalAttribute.isAttribute = True globalAttribute.setExpanded(self._get_expand(globalAttribute)) for glob in sorted(symbols['attributes']): globItem = ItemTree(globalAttribute, [glob], lineno=symbols['attributes'][glob]) globItem.isAttribute = True globItem.setIcon(0, QIcon(":img/attribute")) globItem.setExpanded(self._get_expand(globItem)) if 'functions' in symbols and symbols['functions']: functionsItem = ItemTree(parent, [translations.TR_FUNCTIONS]) functionsItem.isClickable = False functionsItem.isMethod = True functionsItem.setExpanded(self._get_expand(functionsItem)) for func in sorted(symbols['functions']): item = ItemTree(functionsItem, [func], lineno=symbols['functions'][func]['lineno']) tooltip = self.create_tooltip( func, symbols['functions'][func]['lineno']) item.isMethod = True item.setIcon(0, QIcon(":img/function")) item.setToolTip(0, tooltip) item.setExpanded(self._get_expand(item)) self.update_symbols_tree( symbols['functions'][func]['functions'], parent=item) if 'classes' in symbols and symbols['classes']: classItem = ItemTree(parent, [translations.TR_CLASSES]) classItem.isClickable = False classItem.isClass = True classItem.setExpanded(self._get_expand(classItem)) for claz in sorted(symbols['classes']): line_number = symbols['classes'][claz]['lineno'] item = ItemTree(classItem, [claz], lineno=line_number) item.isClass = True tooltip = self.create_tooltip(claz, line_number) item.setToolTip(0, tooltip) item.setIcon(0, QIcon(":img/class")) item.setExpanded(self._get_expand(item)) self.update_symbols_tree(symbols['classes'][claz]['members'], parent=item) def _go_to_definition(self, item): """Takes and item object and goes to definition on the editor""" main_container = IDE.get_service('main_container') if item.isClickable and main_container: main_container.editor_go_to_line(item.lineno - 1) def create_tooltip(self, name, lineno): """Takes a name and line number and returns a tooltip""" doc = self.docstrings.get(lineno, None) if doc is None: doc = '' else: doc = '\n' + doc tooltip = name + doc return tooltip def _item_collapsed(self, item): """When item collapsed""" super(TreeSymbolsWidget, self).collapseItem(item) can_check = (not item.isClickable) or item.isClass or item.isMethod if can_check: n = self._get_unique_name(item) filename = self.actualSymbols[0] self.collapsedItems.setdefault(filename, []) if not n in self.collapsedItems[filename]: self.collapsedItems[filename].append(n) def _item_expanded(self, item): """When item expanded""" super(TreeSymbolsWidget, self).expandItem(item) n = self._get_unique_name(item) filename = self.actualSymbols[0] if n in self.collapsedItems.get(filename, []): self.collapsedItems[filename].remove(n) if not len(self.collapsedItems[filename]): # no more items, free space del self.collapsedItems[filename] def clean(self): """ Reset the tree and reset attributes """ self.tree.clear() self.collapsedItems = {} def reject(self): if self.parent() is None: self.emit(SIGNAL("dockWidget(PyQt_PyObject)"), self) def closeEvent(self, event): """On Close event handling""" self.emit(SIGNAL("dockWidget(PyQt_PyObject)"), self) event.ignore()
class BookmarksWindow(QDialog): """ A simple UI for showing bookmarks and navigating to them. FIXME: For now, this window is tied to a particular lane. If your project has more than one lane, then each one will have it's own bookmark window, which is kinda dumb. """ def __init__(self, parent, topLevelOperatorView): super(BookmarksWindow, self).__init__(parent) self.setWindowTitle("Bookmarks") self.topLevelOperatorView = topLevelOperatorView self.bookmark_tree = QTreeWidget(self) self.bookmark_tree.setHeaderLabels(["Location", "Notes"]) self.bookmark_tree.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.bookmark_tree.setColumnWidth(0, 200) self.bookmark_tree.setColumnWidth(1, 300) self.note_edit = QLineEdit(self) self.add_bookmark_button = QPushButton("Add Bookmark", self, clicked=self.add_bookmark) geometry = self.geometry() geometry.setSize(QSize(520, 520)) self.setGeometry(geometry) layout = QVBoxLayout() layout.addWidget(self.bookmark_tree) layout.addWidget(self.note_edit) layout.addWidget(self.add_bookmark_button) self.setLayout(layout) self._load_bookmarks() self.bookmark_tree.setContextMenuPolicy(Qt.CustomContextMenu) self.bookmark_tree.customContextMenuRequested.connect( self.showContextMenu) self.bookmark_tree.itemDoubleClicked.connect(self._handle_doubleclick) def _handle_doubleclick(self, item, col): """ Navigate to the bookmark """ data = item.data(0, Qt.UserRole).toPyObject() if data is None: return (coord, notes) = data axes = self.topLevelOperatorView.InputImages.meta.getAxisKeys() axes = axes[:-1] # drop channel axes = sorted(axes) assert len(axes) == len(coord) tagged_coord = dict(zip(axes, coord)) tagged_location = OrderedDict(zip('txyzc', (0, 0, 0, 0, 0))) tagged_location.update(tagged_coord) t = tagged_location.values()[0] coord3d = tagged_location.values()[1:4] self.parent().editor.posModel.time = t self.parent().editor.navCtrl.panSlicingViews(coord3d, [0, 1, 2]) self.parent().editor.posModel.slicingPos = coord3d def showContextMenu(self, pos): item = self.bookmark_tree.itemAt(pos) data = item.data(0, Qt.UserRole).toPyObject() if data is None: return def delete_bookmark(): (coord, notes) = data bookmarks = list(self.topLevelOperatorView.Bookmarks.value) i = bookmarks.index((coord, notes)) bookmarks.pop(i) self.topLevelOperatorView.Bookmarks.setValue(bookmarks) self._load_bookmarks() menu = QMenu(parent=self) menu.addAction(QAction("Delete", menu, triggered=delete_bookmark)) globalPos = self.bookmark_tree.viewport().mapToGlobal(pos) menu.exec_(globalPos) #selection = menu.exec_( globalPos ) #if selection is removeLanesAction: # self.removeLanesRequested.emit( self._selectedLanes ) def add_bookmark(self): coord_txyzc = self.parent().editor.posModel.slicingPos5D tagged_coord_txyzc = dict(zip('txyzc', coord_txyzc)) axes = self.topLevelOperatorView.InputImages.meta.getAxisKeys() axes = axes[:-1] # drop channel axes = sorted(axes) coord = tuple(tagged_coord_txyzc[c] for c in axes) notes = str(self.note_edit.text()) bookmarks = list(self.topLevelOperatorView.Bookmarks.value) bookmarks.append((coord, notes)) self.topLevelOperatorView.Bookmarks.setValue(bookmarks) self._load_bookmarks() def _load_bookmarks(self): self.bookmark_tree.clear() lane_index = self.topLevelOperatorView.current_view_index() lane_nickname = self.topLevelOperatorView.InputImages.meta.nickname or "Lane {}".format( lane_index) bookmarks = self.topLevelOperatorView.Bookmarks.value group_item = QTreeWidgetItem(self.bookmark_tree, QStringList(lane_nickname)) for coord, notes in bookmarks: item = QTreeWidgetItem(group_item, QStringList()) item.setText(0, str(coord)) item.setData(0, Qt.UserRole, (coord, notes)) item.setText(1, notes) self.bookmark_tree.expandAll()
class Preferences(QDialog): configuration = {} weight = 0 def __init__(self, parent=None): super(Preferences, self).__init__(parent, Qt.Dialog) self.setWindowTitle(translations.TR_PREFERENCES_TITLE) self.setMinimumSize(QSize(800, 600)) self.setMaximumSize(QSize(0, 0)) vbox = QVBoxLayout(self) hbox = QHBoxLayout() vbox.setContentsMargins(0, 0, 5, 5) hbox.setContentsMargins(0, 0, 0, 0) self.tree = QTreeWidget() self.tree.header().setHidden(True) self.tree.setSelectionMode(QTreeWidget.SingleSelection) self.tree.setAnimated(True) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self.tree.header().setStretchLastSection(False) self.tree.setFixedWidth(200) self.stacked = QStackedLayout() hbox.addWidget(self.tree) hbox.addLayout(self.stacked) vbox.addLayout(hbox) hbox_footer = QHBoxLayout() self._btnSave = QPushButton(translations.TR_SAVE) self._btnCancel = QPushButton(translations.TR_CANCEL) hbox_footer.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding)) hbox_footer.addWidget(self._btnCancel) hbox_footer.addWidget(self._btnSave) vbox.addLayout(hbox_footer) self.connect(self.tree, SIGNAL("itemSelectionChanged()"), self._change_current) self.connect(self._btnCancel, SIGNAL("clicked()"), self.close) self.connect(self._btnSave, SIGNAL("clicked()"), self._save_preferences) self.load_ui() self.tree.setCurrentItem(self.tree.topLevelItem(0)) def _save_preferences(self): self.emit(SIGNAL("savePreferences()")) self.close() def load_ui(self): sections = sorted( list(Preferences.configuration.keys()), key=lambda item: Preferences.configuration[item]['weight']) for section in sections: text = Preferences.configuration[section]['text'] Widget = Preferences.configuration[section]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) item = QTreeWidgetItem([text]) item.setData(0, Qt.UserRole, index) self.tree.addTopLevelItem(item) #Sort Item Children subcontent = Preferences.configuration[section].get( 'subsections', {}) subsections = sorted(list(subcontent.keys()), key=lambda item: subcontent[item]['weight']) for sub in subsections: text = subcontent[sub]['text'] Widget = subcontent[sub]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) subitem = QTreeWidgetItem([text]) subitem.setData(0, Qt.UserRole, index) item.addChild(subitem) self.tree.expandAll() def _change_current(self): item = self.tree.currentItem() index = item.data(0, Qt.UserRole) self.stacked.setCurrentIndex(index) @classmethod def register_configuration(cls, section, widget, text, weight=None, subsection=None): if weight is None: Preferences.weight += 1 weight = Preferences.weight if not subsection: Preferences.configuration[section] = { 'widget': widget, 'weight': weight, 'text': text } else: config = Preferences.configuration.get(section, {}) if not config: config[section] = {'widget': None, 'weight': 100} subconfig = config.get('subsections', {}) subconfig[subsection] = { 'widget': widget, 'weight': weight, 'text': text } config['subsections'] = subconfig Preferences.configuration[section] = config
class BookmarksWindow(QDialog): """ A simple UI for showing bookmarks and navigating to them. FIXME: For now, this window is tied to a particular lane. If your project has more than one lane, then each one will have it's own bookmark window, which is kinda dumb. """ def __init__(self, parent, topLevelOperatorView): super(BookmarksWindow, self).__init__(parent) self.setWindowTitle("Bookmarks") self.topLevelOperatorView = topLevelOperatorView self.bookmark_tree = QTreeWidget(self) self.bookmark_tree.setHeaderLabels( ["Location", "Notes"] ) self.bookmark_tree.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Preferred ) self.bookmark_tree.setColumnWidth(0, 200) self.bookmark_tree.setColumnWidth(1, 300) self.note_edit = QLineEdit(self) self.add_bookmark_button = QPushButton("Add Bookmark", self, clicked=self.add_bookmark) geometry = self.geometry() geometry.setSize( QSize(520, 520) ) self.setGeometry(geometry) layout = QVBoxLayout() layout.addWidget(self.bookmark_tree) layout.addWidget(self.note_edit) layout.addWidget(self.add_bookmark_button) self.setLayout(layout) self._load_bookmarks() self.bookmark_tree.setContextMenuPolicy( Qt.CustomContextMenu ) self.bookmark_tree.customContextMenuRequested.connect( self.showContextMenu ) self.bookmark_tree.itemDoubleClicked.connect(self._handle_doubleclick) def _handle_doubleclick(self, item, col): """ Navigate to the bookmark """ data = item.data(0, Qt.UserRole).toPyObject() if data is None: return (coord, notes) = data axes = self.topLevelOperatorView.InputImages.meta.getAxisKeys() axes = axes[:-1] # drop channel axes = sorted(axes) assert len(axes) == len(coord) tagged_coord = dict(zip(axes, coord)) tagged_location = OrderedDict(zip('txyzc', (0,0,0,0,0))) tagged_location.update(tagged_coord) t = tagged_location.values()[0] coord3d = tagged_location.values()[1:4] self.parent().editor.posModel.time = t self.parent().editor.navCtrl.panSlicingViews( coord3d, [0,1,2] ) self.parent().editor.posModel.slicingPos = coord3d def showContextMenu(self, pos): item = self.bookmark_tree.itemAt(pos) data = item.data(0, Qt.UserRole).toPyObject() if data is None: return def delete_bookmark(): (coord, notes) = data bookmarks = list(self.topLevelOperatorView.Bookmarks.value) i = bookmarks.index((coord, notes)) bookmarks.pop(i) self.topLevelOperatorView.Bookmarks.setValue(bookmarks) self._load_bookmarks() menu = QMenu(parent=self) menu.addAction( QAction("Delete", menu, triggered=delete_bookmark) ) globalPos = self.bookmark_tree.viewport().mapToGlobal( pos ) menu.exec_( globalPos ) #selection = menu.exec_( globalPos ) #if selection is removeLanesAction: # self.removeLanesRequested.emit( self._selectedLanes ) def add_bookmark(self): coord_txyzc = self.parent().editor.posModel.slicingPos5D tagged_coord_txyzc = dict( zip('txyzc', coord_txyzc) ) axes = self.topLevelOperatorView.InputImages.meta.getAxisKeys() axes = axes[:-1] # drop channel axes = sorted(axes) coord = tuple(tagged_coord_txyzc[c] for c in axes) notes = str(self.note_edit.text()) bookmarks = list(self.topLevelOperatorView.Bookmarks.value) bookmarks.append((coord, notes)) self.topLevelOperatorView.Bookmarks.setValue(bookmarks) self._load_bookmarks() def _load_bookmarks(self): self.bookmark_tree.clear() lane_index = self.topLevelOperatorView.current_view_index() lane_nickname = self.topLevelOperatorView.InputImages.meta.nickname or "Lane {}".format(lane_index) bookmarks = self.topLevelOperatorView.Bookmarks.value group_item = QTreeWidgetItem( self.bookmark_tree, QStringList(lane_nickname) ) for coord, notes in bookmarks: item = QTreeWidgetItem( group_item, QStringList() ) item.setText(0, str(coord)) item.setData(0, Qt.UserRole, (coord, notes)) item.setText(1, notes) self.bookmark_tree.expandAll()
class OWKEGGPathwayBrowser(widget.OWWidget): name = "KEGG Pathways" description = "Browse KEGG pathways that include an input set of genes." icon = "../widgets/icons/KEGGPathways.svg" priority = 2030 inputs = [("Data", Orange.data.Table, "SetData", widget.Default), ("Reference", Orange.data.Table, "SetRefData")] outputs = [("Selected Data", Orange.data.Table, widget.Default), ("Unselected Data", Orange.data.Table)] settingsHandler = settings.DomainContextHandler() organismIndex = settings.ContextSetting(0) geneAttrIndex = settings.ContextSetting(0) useAttrNames = settings.ContextSetting(False) autoCommit = settings.Setting(False) autoResize = settings.Setting(True) useReference = settings.Setting(False) showOrthology = settings.Setting(True) Ready, Initializing, Running = 0, 1, 2 def __init__(self, parent=None): super().__init__(parent) self.organismCodes = [] self._changedFlag = False self.__invalidated = False self.__runstate = OWKEGGPathwayBrowser.Initializing self.__in_setProgress = False self.controlArea.setMaximumWidth(250) box = gui.widgetBox(self.controlArea, "Info") self.infoLabel = gui.widgetLabel(box, "No data on input\n") # Organism selection. box = gui.widgetBox(self.controlArea, "Organism") self.organismComboBox = gui.comboBox( box, self, "organismIndex", items=[], callback=self.Update, addSpace=True, tooltip="Select the organism of the input genes") # Selection of genes attribute box = gui.widgetBox(self.controlArea, "Gene attribute") self.geneAttrCandidates = itemmodels.VariableListModel(parent=self) self.geneAttrCombo = gui.comboBox(box, self, "geneAttrIndex", callback=self.Update) self.geneAttrCombo.setModel(self.geneAttrCandidates) gui.checkBox(box, self, "useAttrNames", "Use variable names", disables=[(-1, self.geneAttrCombo)], callback=self.Update) self.geneAttrCombo.setDisabled(bool(self.useAttrNames)) gui.separator(self.controlArea) gui.checkBox(self.controlArea, self, "useReference", "From signal", box="Reference", callback=self.Update) gui.separator(self.controlArea) gui.checkBox(self.controlArea, self, "showOrthology", "Show pathways in full orthology", box="Orthology", callback=self.UpdateListView) gui.checkBox(self.controlArea, self, "autoResize", "Resize to fit", box="Image", callback=self.UpdatePathwayViewTransform) box = gui.widgetBox(self.controlArea, "Cache Control") gui.button(box, self, "Clear cache", callback=self.ClearCache, tooltip="Clear all locally cached KEGG data.", default=False, autoDefault=False) gui.separator(self.controlArea) gui.auto_commit(self.controlArea, self, "autoCommit", "Commit") gui.rubber(self.controlArea) spliter = QSplitter(Qt.Vertical, self.mainArea) self.pathwayView = PathwayView(self, spliter) self.pathwayView.scene().selectionChanged.connect( self._onSelectionChanged) self.mainArea.layout().addWidget(spliter) self.listView = QTreeWidget(allColumnsShowFocus=True, selectionMode=QTreeWidget.SingleSelection, sortingEnabled=True, maximumHeight=200) spliter.addWidget(self.listView) self.listView.setColumnCount(4) self.listView.setHeaderLabels( ["Pathway", "P value", "Genes", "Reference"]) self.listView.itemSelectionChanged.connect(self.UpdatePathwayView) select = QAction("Select All", self, shortcut=QKeySequence.SelectAll) select.triggered.connect(self.selectAll) self.addAction(select) self.data = None self.refData = None self._executor = concurrent.ThreadExecutor() self.setEnabled(False) self.setBlocking(True) progress = concurrent.methodinvoke(self, "setProgress", (float, )) def get_genome(): """Return a KEGGGenome with the common org entries precached.""" genome = kegg.KEGGGenome() essential = genome.essential_organisms() common = genome.common_organisms() # Remove duplicates of essential from common. # (essential + common list as defined here will be used in the # GUI.) common = [c for c in common if c not in essential] # TODO: Add option to specify additional organisms not # in the common list. keys = list(map(genome.org_code_to_entry_key, essential + common)) genome.pre_cache(keys, progress_callback=progress) return (keys, genome) self._genomeTask = task = concurrent.Task(function=get_genome) task.finished.connect(self.__initialize_finish) self.progressBarInit() self.infoLabel.setText("Fetching organism definitions\n") self._executor.submit(task) def __initialize_finish(self): if self.__runstate != OWKEGGPathwayBrowser.Initializing: return try: keys, genome = self._genomeTask.result() except Exception as err: self.error(0, str(err)) raise self.progressBarFinished() self.setEnabled(True) self.setBlocking(False) entries = [genome[key] for key in keys] items = [entry.definition for entry in entries] codes = [entry.organism_code for entry in entries] self.organismCodes = codes self.organismComboBox.clear() self.organismComboBox.addItems(items) self.organismComboBox.setCurrentIndex(self.organismIndex) self.infoLabel.setText("No data on input\n") def Clear(self): """ Clear the widget state. """ self.queryGenes = [] self.referenceGenes = [] self.genes = {} self.uniqueGenesDict = {} self.revUniqueGenesDict = {} self.pathways = {} self.org = None self.geneAttrCandidates[:] = [] self.infoLabel.setText("No data on input\n") self.listView.clear() self.pathwayView.SetPathway(None) self.send("Selected Data", None) self.send("Unselected Data", None) def SetData(self, data=None): if self.__runstate == OWKEGGPathwayBrowser.Initializing: self.__initialize_finish() self.closeContext() self.data = data self.warning(0) self.error(0) self.information(0) if data is not None: vars = data.domain.variables + data.domain.metas vars = [ var for var in vars if isinstance(var, Orange.data.StringVariable) ] self.geneAttrCandidates[:] = vars # Try to guess the gene name variable if vars: names_lower = [v.name.lower() for v in vars] scores = [(name == "gene", "gene" in name) for name in names_lower] imax, _ = max(enumerate(scores), key=itemgetter(1)) else: imax = -1 self.geneAttrIndex = imax taxid = data_hints.get_hint(data, "taxid", None) if taxid: try: code = kegg.from_taxid(taxid) self.organismIndex = self.organismCodes.index(code) except Exception as ex: print(ex, taxid) self.useAttrNames = data_hints.get_hint(data, "genesinrows", self.useAttrNames) self.openContext(data) if len(self.geneAttrCandidates) == 0: self.useAttrNames = True self.geneAttrIndex = -1 else: self.geneAttrIndex = min(self.geneAttrIndex, len(self.geneAttrCandidates) - 1) else: self.Clear() self.__invalidated = True def SetRefData(self, data=None): self.refData = data self.information(1) if data is not None and self.useReference: self.__invalidated = True def handleNewSignals(self): if self.__invalidated: self.Update() self.__invalidated = False def UpdateListView(self): self.bestPValueItem = None self.listView.clear() if not self.data: return allPathways = self.org.pathways() allRefPathways = kegg.pathways("map") items = [] kegg_pathways = kegg.KEGGPathways() org_code = self.organismCodes[min(self.organismIndex, len(self.organismCodes) - 1)] if self.showOrthology: self.koOrthology = kegg.KEGGBrite("ko00001") self.listView.setRootIsDecorated(True) path_ids = set([s[-5:] for s in self.pathways.keys()]) def _walkCollect(koEntry): num = koEntry.title[:5] if koEntry.title else None if num in path_ids: return ([koEntry] + reduce(lambda li, c: li + _walkCollect(c), [child for child in koEntry.entries], [])) else: c = reduce(lambda li, c: li + _walkCollect(c), [child for child in koEntry.entries], []) return c + (c and [koEntry] or []) allClasses = reduce(lambda li1, li2: li1 + li2, [_walkCollect(c) for c in self.koOrthology], []) def _walkCreate(koEntry, lvItem): item = QTreeWidgetItem(lvItem) id = "path:" + org_code + koEntry.title[:5] if koEntry.title[:5] in path_ids: p = kegg_pathways.get_entry(id) if p is None: # In case the genesets still have obsolete entries name = koEntry.title else: name = p.name genes, p_value, ref = self.pathways[id] item.setText(0, name) item.setText(1, "%.5f" % p_value) item.setText(2, "%i of %i" % (len(genes), len(self.genes))) item.setText(3, "%i of %i" % (ref, len(self.referenceGenes))) item.pathway_id = id if p is not None else None else: if id in allPathways: text = kegg_pathways.get_entry(id).name else: text = koEntry.title item.setText(0, text) if id in allPathways: item.pathway_id = id elif "path:map" + koEntry.title[:5] in allRefPathways: item.pathway_id = "path:map" + koEntry.title[:5] else: item.pathway_id = None for child in koEntry.entries: if child in allClasses: _walkCreate(child, item) for koEntry in self.koOrthology: if koEntry in allClasses: _walkCreate(koEntry, self.listView) self.listView.update() else: self.listView.setRootIsDecorated(False) pathways = self.pathways.items() pathways = sorted(pathways, key=lambda item: item[1][1]) for id, (genes, p_value, ref) in pathways: item = QTreeWidgetItem(self.listView) item.setText(0, kegg_pathways.get_entry(id).name) item.setText(1, "%.5f" % p_value) item.setText(2, "%i of %i" % (len(genes), len(self.genes))) item.setText(3, "%i of %i" % (ref, len(self.referenceGenes))) item.pathway_id = id items.append(item) self.bestPValueItem = items and items[0] or None self.listView.expandAll() for i in range(4): self.listView.resizeColumnToContents(i) if self.bestPValueItem: index = self.listView.indexFromItem(self.bestPValueItem) self.listView.selectionModel().select( index, QItemSelectionModel.ClearAndSelect) def UpdatePathwayView(self): items = self.listView.selectedItems() if len(items) > 0: item = items[0] else: item = None self.commit() item = item or self.bestPValueItem if not item or not item.pathway_id: self.pathwayView.SetPathway(None) return def get_kgml_and_image(pathway_id): """Return an initialized KEGGPathway with pre-cached data""" p = kegg.KEGGPathway(pathway_id) p._get_kgml() # makes sure the kgml file is downloaded p._get_image_filename() # makes sure the image is downloaded return (pathway_id, p) self.setEnabled(False) self._pathwayTask = concurrent.Task( function=lambda: get_kgml_and_image(item.pathway_id)) self._pathwayTask.finished.connect(self._onPathwayTaskFinshed) self._executor.submit(self._pathwayTask) def _onPathwayTaskFinshed(self): self.setEnabled(True) pathway_id, self.pathway = self._pathwayTask.result() self.pathwayView.SetPathway(self.pathway, self.pathways.get(pathway_id, [[]])[0]) def UpdatePathwayViewTransform(self): self.pathwayView.updateTransform() def Update(self): """ Update (recompute enriched pathways) the widget state. """ if not self.data: return self.error(0) self.information(0) # XXX: Check data in setData, do not even alow this to be executed if # data has no genes try: genes = self.GeneNamesFromData(self.data) except ValueError: self.error(0, "Cannot extract gene names from input.") genes = [] if not self.useAttrNames and any("," in gene for gene in genes): genes = reduce(add, (split_and_strip(gene, ",") for gene in genes), []) self.information( 0, "Separators detected in input gene names. " "Assuming multiple genes per instance.") self.queryGenes = genes self.information(1) reference = None if self.useReference and self.refData: reference = self.GeneNamesFromData(self.refData) if not self.useAttrNames \ and any("," in gene for gene in reference): reference = reduce(add, (split_and_strip(gene, ",") for gene in reference), []) self.information( 1, "Separators detected in reference gene " "names. Assuming multiple genes per " "instance.") org_code = self.SelectedOrganismCode() def run_enrichment(org_code, genes, reference=None, progress=None): org = kegg.KEGGOrganism(org_code) if reference is None: reference = org.get_genes() # Map 'genes' and 'reference' sets to unique KEGG identifiers unique_genes, _, _ = org.get_unique_gene_ids(set(genes)) unique_ref_genes, _, _ = org.get_unique_gene_ids(set(reference)) taxid = kegg.to_taxid(org.org_code) # Map the taxid back to standard 'common' taxids # (as used by 'geneset') if applicable r_tax_map = dict( (v, k) for k, v in kegg.KEGGGenome.TAXID_MAP.items()) if taxid in r_tax_map: taxid = r_tax_map[taxid] # We use the kegg pathway gene sets provided by 'geneset' for # the enrichment calculation. # Ensure we are using the latest genesets # TODO: ?? Is updating the index enough? serverfiles.update(geneset.sfdomain, "index.pck") kegg_gs_collections = geneset.collections( (("KEGG", "pathways"), taxid)) pathways = pathway_enrichment(kegg_gs_collections, unique_genes.keys(), unique_ref_genes.keys(), callback=progress) # Ensure that pathway entries are pre-cached for later use in the # list/tree view kegg_pathways = kegg.KEGGPathways() kegg_pathways.pre_cache(pathways.keys(), progress_callback=progress) return pathways, org, unique_genes, unique_ref_genes self.progressBarInit() self.setEnabled(False) self.infoLabel.setText("Retrieving...\n") progress = concurrent.methodinvoke(self, "setProgress", (float, )) self._enrichTask = concurrent.Task(function=lambda: run_enrichment( org_code, genes, reference, progress)) self._enrichTask.finished.connect(self._onEnrichTaskFinished) self._executor.submit(self._enrichTask) def _onEnrichTaskFinished(self): self.setEnabled(True) self.setBlocking(False) try: pathways, org, unique_genes, unique_ref_genes = \ self._enrichTask.result() except Exception: raise self.progressBarFinished() self.org = org self.genes = unique_genes.keys() self.uniqueGenesDict = unique_genes self.revUniqueGenesDict = dict([ (val, key) for key, val in self.uniqueGenesDict.items() ]) self.referenceGenes = unique_ref_genes.keys() self.pathways = pathways if not self.pathways: self.warning(0, "No enriched pathways found.") else: self.warning(0) count = len(set(self.queryGenes)) self.infoLabel.setText("%i unique gene names on input\n" "%i (%.1f%%) genes names matched" % (count, len(unique_genes), 100.0 * len(unique_genes) / count if count else 0.0)) self.UpdateListView() @Slot(float) def setProgress(self, value): if self.__in_setProgress: return self.__in_setProgress = True self.progressBarSet(value) self.__in_setProgress = False def GeneNamesFromData(self, data): """ Extract and return gene names from `data`. """ if self.useAttrNames: genes = [str(v.name).strip() for v in data.domain.attributes] elif self.geneAttrCandidates: assert 0 <= self.geneAttrIndex < len(self.geneAttrCandidates) geneAttr = self.geneAttrCandidates[self.geneAttrIndex] genes = [ str(e[geneAttr]) for e in data if not numpy.isnan(e[geneAttr]) ] else: raise ValueError("No gene names in data.") return genes def SelectedOrganismCode(self): """ Return the selected organism code. """ return self.organismCodes[min(self.organismIndex, len(self.organismCodes) - 1)] def selectAll(self): """ Select all items in the pathway view. """ changed = False scene = self.pathwayView.scene() with disconnected(scene.selectionChanged, self._onSelectionChanged): for item in scene.items(): if item.flags() & QGraphicsItem.ItemIsSelectable and \ not item.isSelected(): item.setSelected(True) changed = True if changed: self._onSelectionChanged() def _onSelectionChanged(self): # Item selection in the pathwayView/scene has changed self.commit() def commit(self): if self.data: selectedItems = self.pathwayView.scene().selectedItems() selectedGenes = reduce( set.union, [item.marked_objects for item in selectedItems], set()) if self.useAttrNames: selected = [ self.data.domain[self.uniqueGenesDict[gene]] for gene in selectedGenes ] # newDomain = Orange.data.Domain(selectedVars, 0) data = self.data[:, selected] # data = Orange.data.Table(newDomain, self.data) self.send("Selected Data", data) elif self.geneAttrCandidates: assert 0 <= self.geneAttrIndex < len(self.geneAttrCandidates) geneAttr = self.geneAttrCandidates[self.geneAttrIndex] selectedIndices = [] otherIndices = [] for i, ex in enumerate(self.data): names = [ self.revUniqueGenesDict.get(name, None) for name in split_and_strip(str(ex[geneAttr]), ",") ] if any(name and name in selectedGenes for name in names): selectedIndices.append(i) else: otherIndices.append(i) if selectedIndices: selected = self.data[selectedIndices] else: selected = None if otherIndices: other = self.data[otherIndices] else: other = None self.send("Selected Data", selected) self.send("Unselected Data", other) else: self.send("Selected Data", None) self.send("Unselected Data", None) def ClearCache(self): kegg.caching.clear_cache() def onDeleteWidget(self): """ Called before the widget is removed from the canvas. """ super().onDeleteWidget() self.org = None self._executor.shutdown(wait=False) gc.collect() # Force collection (WHY?) def sizeHint(self): return QSize(1024, 720)
class OWKEGGPathwayBrowser(OWWidget): settingsList = ["organismIndex", "geneAttrIndex", "autoCommit", "autoResize", "useReference", "useAttrNames", "showOrthology"] contextHandlers = { "": DomainContextHandler( "", [ContextField("organismIndex", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes), ContextField("geneAttrIndex", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes), ContextField("useAttrNames", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes)] ) } def __init__(self, parent=None, signalManager=None, name="KEGG Pathways"): OWWidget.__init__(self, parent, signalManager, name, wantGraph=True) self.inputs = [("Examples", Orange.data.Table, self.SetData), ("Reference", Orange.data.Table, self.SetRefData)] self.outputs = [("Selected Examples", Orange.data.Table), ("Unselected Examples", Orange.data.Table)] self.organismIndex = 0 self.geneAttrIndex = 0 self.autoCommit = False self.autoResize = True self.useReference = False self.useAttrNames = 0 self.showOrthology = True self.loadSettings() self.organismCodes = [] self._changedFlag = False self.controlArea.setMaximumWidth(250) box = OWGUI.widgetBox(self.controlArea, "Info") self.infoLabel = OWGUI.widgetLabel(box, "No data on input\n") # Organism selection. box = OWGUI.widgetBox(self.controlArea, "Organism") self.organismComboBox = OWGUI.comboBox( box, self, "organismIndex", items=[], callback=self.Update, addSpace=True, debuggingEnabled=0, tooltip="Select the organism of the input genes") # Selection of genes attribute box = OWGUI.widgetBox(self.controlArea, "Gene attribute") self.geneAttrCandidates = VariableListModel(parent=self) self.geneAttrCombo = OWGUI.comboBox( box, self, "geneAttrIndex", callback=self.Update) self.geneAttrCombo.setModel(self.geneAttrCandidates) OWGUI.checkBox(box, self, "useAttrNames", "Use variable names", disables=[(-1, self.geneAttrCombo)], callback=self.Update) self.geneAttrCombo.setDisabled(bool(self.useAttrNames)) OWGUI.separator(self.controlArea) OWGUI.checkBox(self.controlArea, self, "useReference", "From signal", box="Reference", callback=self.Update) OWGUI.separator(self.controlArea) OWGUI.checkBox(self.controlArea, self, "showOrthology", "Show pathways in full orthology", box="Orthology", callback=self.UpdateListView) OWGUI.checkBox(self.controlArea, self, "autoResize", "Resize to fit", box="Image", callback=self.UpdatePathwayViewTransform) box = OWGUI.widgetBox(self.controlArea, "Cache Control") OWGUI.button(box, self, "Clear cache", callback=self.ClearCache, tooltip="Clear all locally cached KEGG data.") OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Selection") cb = OWGUI.checkBox(box, self, "autoCommit", "Commit on update") button = OWGUI.button(box, self, "Commit", callback=self.Commit, default=True) OWGUI.setStopper(self, button, cb, "_changedFlag", self.Commit) OWGUI.rubber(self.controlArea) spliter = QSplitter(Qt.Vertical, self.mainArea) self.pathwayView = PathwayView(self, spliter) self.pathwayView.scene().selectionChanged.connect( self._onSelectionChanged ) self.mainArea.layout().addWidget(spliter) self.listView = QTreeWidget(spliter) spliter.addWidget(self.listView) self.listView.setAllColumnsShowFocus(1) self.listView.setColumnCount(4) self.listView.setHeaderLabels(["Pathway", "P value", "Genes", "Reference"]) self.listView.setSelectionMode(QTreeWidget.SingleSelection) self.listView.setSortingEnabled(True) self.listView.setMaximumHeight(200) self.connect(self.listView, SIGNAL("itemSelectionChanged()"), self.UpdatePathwayView) self.connect(self.graphButton, SIGNAL("clicked()"), self.saveGraph) select = QAction( "Select All", self, shortcut=QKeySequence.SelectAll ) select.triggered.connect(self.selectAll) self.addAction(select) self.data = None self.refData = None self.resize(800, 600) self.connect(self, SIGNAL("widgetStateChanged(QString, int, QString)"), self.onStateChange) self.has_new_data = False self.has_new_reference_set = False self._executor = ThreadExecutor() self.setEnabled(False) self.setBlocking(True) QTimer.singleShot(0, self._initialize) self.infoLabel.setText("Fetching organism definitions\n") def _initialize(self): # First try to import slumber to see if we can even use the # kegg module. try: import slumber except ImportError: QMessageBox.warning(self, "'slumber' library required.", '<p>Please install ' '<a href="http://pypi.python.org/pypi/slumber">slumber</a> ' 'library to use KEGG Pathways widget.</p>' ) self.infoLabel.setText( '<p>Please install ' '<a href="http://pypi.python.org/pypi/slumber">slumber</a> ' 'library to use KEGG Pathways widget.</p>' ) self.error(0, "Missing slumber/requests library") return progress = methodinvoke(self, "setProgress", (float,)) def get_genome(): """Return a KEGGGenome with the common org entries precached.""" genome = kegg.KEGGGenome() essential = genome.essential_organisms() common = genome.common_organisms() # Remove duplicates of essential from common. # (essential + common list as defined here will be used in the # GUI.) common = [c for c in common if c not in essential] # TODO: Add option to specify additional organisms not # in the common list. keys = map(genome.org_code_to_entry_key, essential + common) genome.pre_cache(keys, progress_callback=progress) return (keys, genome) self._genomeTask = task = Task(function=get_genome) task.finished.connect(self._initializeOrganisms) self.progressBarInit() self._executor.submit(task) def _initializeOrganisms(self): self.progressBarFinished() try: keys, genome = self._genomeTask.result() except Exception as err: self.error(0, str(err)) return entries = [genome[key] for key in keys] items = [entry.definition for entry in entries] codes = [entry.organism_code for entry in entries] self.organismCodes = codes self.organismComboBox.clear() self.organismComboBox.addItems(items) self.organismComboBox.setCurrentIndex(self.organismIndex) self.setEnabled(True) self.setBlocking(False) self.infoLabel.setText("No data on input\n") def Clear(self): """ Clear the widget state. """ self.queryGenes = [] self.referenceGenes = [] self.genes = {} self.uniqueGenesDict = {} self.revUniqueGenesDict = {} self.pathways = {} self.org = None self.geneAttrCandidates[:] = [] self.infoLabel.setText("No data on input\n") self.listView.clear() self.pathwayView.SetPathway(None) self.send("Selected Examples", None) self.send("Unselected Examples", None) def SetData(self, data=None): self.closeContext() self.data = data self.warning(0) self.error(0) self.information(0) if data is not None: vars = data.domain.variables + data.domain.getmetas().values() vars = [var for var in vars if isinstance(var, (Orange.feature.String, Orange.feature.Discrete))] self.geneAttrCandidates[:] = vars # Try to guess the gene name variable names_lower = [v.name.lower() for v in vars] scores = [(name == "gene", "gene" in name) for name in names_lower] imax, _ = max(enumerate(scores), key=itemgetter(1)) self.geneAttrIndex = imax taxid = data_hints.get_hint(data, "taxid", None) if taxid: try: code = kegg.from_taxid(taxid) self.organismIndex = self.organismCodes.index(code) except Exception as ex: print ex, taxid self.useAttrNames = data_hints.get_hint(data, "genesinrows", self.useAttrNames) self.openContext("", data) else: self.Clear() self.has_new_data = True def SetRefData(self, data=None): self.refData = data self.information(1) self.has_new_reference_set = True def handleNewSignals(self): if self.has_new_data or (self.has_new_reference_set and \ self.useReference): self.Update() self.has_new_data = False self.has_new_reference_set = False def UpdateListView(self): self.bestPValueItem = None self.listView.clear() if not self.data: return allPathways = self.org.pathways() allRefPathways = kegg.pathways("map") items = [] kegg_pathways = kegg.KEGGPathways() org_code = self.organismCodes[min(self.organismIndex, len(self.organismCodes) - 1)] if self.showOrthology: self.koOrthology = kegg.KEGGBrite("ko00001") self.listView.setRootIsDecorated(True) path_ids = set([s[-5:] for s in self.pathways.keys()]) def _walkCollect(koEntry): num = koEntry.title[:5] if koEntry.title else None if num in path_ids: return ([koEntry] + reduce(lambda li, c: li + _walkCollect(c), [child for child in koEntry.entries], [])) else: c = reduce(lambda li, c: li + _walkCollect(c), [child for child in koEntry.entries], []) return c + (c and [koEntry] or []) allClasses = reduce(lambda li1, li2: li1 + li2, [_walkCollect(c) for c in self.koOrthology], []) def _walkCreate(koEntry, lvItem): item = QTreeWidgetItem(lvItem) id = "path:" + org_code + koEntry.title[:5] if koEntry.title[:5] in path_ids: p = kegg_pathways.get_entry(id) if p is None: # In case the genesets still have obsolete entries name = koEntry.title else: name = p.name genes, p_value, ref = self.pathways[id] item.setText(0, name) item.setText(1, "%.5f" % p_value) item.setText(2, "%i of %i" % (len(genes), len(self.genes))) item.setText(3, "%i of %i" % (ref, len(self.referenceGenes))) item.pathway_id = id if p is not None else None else: if id in allPathways: text = kegg_pathways.get_entry(id).name else: text = koEntry.title item.setText(0, text) if id in allPathways: item.pathway_id = id elif "path:map" + koEntry.title[:5] in allRefPathways: item.pathway_id = "path:map" + koEntry.title[:5] else: item.pathway_id = None for child in koEntry.entries: if child in allClasses: _walkCreate(child, item) for koEntry in self.koOrthology: if koEntry in allClasses: _walkCreate(koEntry, self.listView) self.listView.update() else: self.listView.setRootIsDecorated(False) pathways = self.pathways.items() pathways.sort(lambda a, b: cmp(a[1][1], b[1][1])) for id, (genes, p_value, ref) in pathways: item = QTreeWidgetItem(self.listView) item.setText(0, kegg_pathways.get_entry(id).name) item.setText(1, "%.5f" % p_value) item.setText(2, "%i of %i" % (len(genes), len(self.genes))) item.setText(3, "%i of %i" % (ref, len(self.referenceGenes))) item.pathway_id = id items.append(item) self.bestPValueItem = items and items[0] or None self.listView.expandAll() for i in range(4): self.listView.resizeColumnToContents(i) if self.bestPValueItem: index = self.listView.indexFromItem(self.bestPValueItem) self.listView.selectionModel().select( index, QItemSelectionModel.ClearAndSelect ) def UpdatePathwayView(self): items = self.listView.selectedItems() if len(items) > 0: item = items[0] else: item = None self.Commit() item = item or self.bestPValueItem if not item or not item.pathway_id: self.pathwayView.SetPathway(None) return def get_kgml_and_image(pathway_id): """Return an initialized KEGGPathway with pre-cached data""" p = kegg.KEGGPathway(pathway_id) p._get_kgml() # makes sure the kgml file is downloaded p._get_image_filename() # makes sure the image is downloaded return (pathway_id, p) self.setEnabled(False) self._pathwayTask = Task( function=lambda: get_kgml_and_image(item.pathway_id) ) self._pathwayTask.finished.connect(self._onPathwayTaskFinshed) self._executor.submit(self._pathwayTask) def _onPathwayTaskFinshed(self): self.setEnabled(True) pathway_id, self.pathway = self._pathwayTask.result() self.pathwayView.SetPathway( self.pathway, self.pathways.get(pathway_id, [[]])[0] ) def UpdatePathwayViewTransform(self): self.pathwayView.updateTransform() def Update(self): """ Update (recompute enriched pathways) the widget state. """ if not self.data: return self.error(0) self.information(0) # XXX: Check data in setData, do not even alow this to be executed if # data has no genes try: genes = self.GeneNamesFromData(self.data) except ValueError: self.error(0, "Cannot extract gene names from input.") genes = [] if not self.useAttrNames and any("," in gene for gene in genes): genes = reduce(add, (split_and_strip(gene, ",") for gene in genes), []) self.information(0, "Separators detected in input gene names. " "Assuming multiple genes per instance.") self.queryGenes = genes self.information(1) reference = None if self.useReference and self.refData: reference = self.GeneNamesFromData(self.refData) if not self.useAttrNames \ and any("," in gene for gene in reference): reference = reduce(add, (split_and_strip(gene, ",") for gene in reference), []) self.information(1, "Separators detected in reference gene " "names. Assuming multiple genes per " "instance.") org_code = self.SelectedOrganismCode() def run_enrichment(org_code, genes, reference=None, progress=None): org = kegg.KEGGOrganism(org_code) if reference is None: reference = org.get_genes() # Map 'genes' and 'reference' sets to unique KEGG identifiers unique_genes, _, _ = org.get_unique_gene_ids(set(genes)) unique_ref_genes, _, _ = org.get_unique_gene_ids(set(reference)) taxid = kegg.to_taxid(org.org_code) # Map the taxid back to standard 'common' taxids # (as used by 'geneset') if applicable r_tax_map = dict((v, k) for k, v in kegg.KEGGGenome.TAXID_MAP.items()) if taxid in r_tax_map: taxid = r_tax_map[taxid] # We use the kegg pathway gene sets provided by 'geneset' for # the enrichment calculation. # Ensure we are using the latest genesets # TODO: ?? Is updating the index enough? serverfiles.update(geneset.sfdomain, "index.pck") kegg_gs_collections = geneset.collections( (("KEGG", "pathways"), taxid) ) pathways = pathway_enrichment( kegg_gs_collections, unique_genes.keys(), unique_ref_genes.keys(), callback=progress ) # Ensure that pathway entries are pre-cached for later use in the # list/tree view kegg_pathways = kegg.KEGGPathways() kegg_pathways.pre_cache( pathways.keys(), progress_callback=progress ) return pathways, org, unique_genes, unique_ref_genes self.progressBarInit() self.setEnabled(False) self.infoLabel.setText("Retrieving...\n") progress = methodinvoke(self, "setProgress", (float,)) self._enrichTask = Task( function=lambda: run_enrichment(org_code, genes, reference, progress) ) self._enrichTask.finished.connect(self._onEnrichTaskFinished) self._executor.submit(self._enrichTask) def _onEnrichTaskFinished(self): self.setEnabled(True) self.setBlocking(False) self.progressBarFinished() try: pathways, org, unique_genes, unique_ref_genes = \ self._enrichTask.result() except Exception: raise self.org = org self.genes = unique_genes.keys() self.uniqueGenesDict = unique_genes self.revUniqueGenesDict = dict([(val, key) for key, val in self.uniqueGenesDict.items()]) self.referenceGenes = unique_ref_genes.keys() self.pathways = pathways if not self.pathways: self.warning(0, "No enriched pathways found.") else: self.warning(0) count = len(set(self.queryGenes)) self.infoLabel.setText( "%i unique gene names on input\n" "%i (%.1f%%) genes names matched" % (count, len(unique_genes), 100.0 * len(unique_genes) / count if count else 0.0) ) self.UpdateListView() @pyqtSlot(float) def setProgress(self, value): self.progressBarValue = value def GeneNamesFromData(self, data): """ Extract and return gene names from `data`. """ if self.useAttrNames: genes = [str(v.name).strip() for v in data.domain.attributes] elif self.geneAttrCandidates: index = min(self.geneAttrIndex, len(self.geneAttrCandidates) - 1) geneAttr = self.geneAttrCandidates[index] genes = [str(e[geneAttr]) for e in data if not e[geneAttr].isSpecial()] else: raise ValueError("No gene names in data.") return genes def SelectedOrganismCode(self): """ Return the selected organism code. """ return self.organismCodes[min(self.organismIndex, len(self.organismCodes) - 1)] def selectAll(self): """ Select all items in the pathway view. """ changed = False scene = self.pathwayView.scene() with disconnected(scene.selectionChanged, self._onSelectionChanged): for item in scene.items(): if item.flags() & QGraphicsItem.ItemIsSelectable and \ not item.isSelected(): item.setSelected(True) changed = True if changed: self._onSelectionChanged() def _onSelectionChanged(self): # Item selection in the pathwayView/scene has changed if self.autoCommit: self.Commit() else: self._changedFlag = True def Commit(self): if self.data: selectedItems = self.pathwayView.scene().selectedItems() selectedGenes = reduce(set.union, [item.marked_objects for item in selectedItems], set()) if self.useAttrNames: selectedVars = [self.data.domain[self.uniqueGenesDict[gene]] for gene in selectedGenes] newDomain = Orange.data.Domain(selectedVars, 0) data = Orange.data.Table(newDomain, self.data) self.send("Selected Examples", data) elif self.geneAttrCandidates: geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates) - 1)] selectedExamples = [] otherExamples = [] for ex in self.data: names = [self.revUniqueGenesDict.get(name, None) for name in split_and_strip(str(ex[geneAttr]), ",")] if any(name and name in selectedGenes for name in names): selectedExamples.append(ex) else: otherExamples.append(ex) if selectedExamples: selectedExamples = Orange.data.Table(selectedExamples) else: selectedExamples = None if otherExamples: otherExamples = Orange.data.Table(otherExamples) else: otherExamples = None self.send("Selected Examples", selectedExamples) self.send("Unselected Examples", otherExamples) else: self.send("Selected Examples", None) self.send("Unselected Examples", None) def ClearCache(self): from ..kegg import caching try: caching.clear_cache() except Exception, ex: QMessageBox.warning(self, "Cache clear", ex.args[0])
class mainwindow(QtGui.QMainWindow): '''主窗体''' def __init__(self): super(mainwindow, self).__init__() self.setWindowTitle('组件设计工具') self.setWindowIcon(QIcon(':/image/组件设计工具.png')) self.setMinimumWidth(1024) self.setMinimumHeight(800) self.showMaximized() self.menuBar().show() self.createMenus() #self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint) labelSizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) editSizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) cwVLayout = QVBoxLayout() cwHLayout = QHBoxLayout() lLayout = QVBoxLayout() rLayout = QVBoxLayout() self.lw = QListWidget() self.lw.setSelectionMode(QAbstractItemView.SingleSelection) lLayout.addWidget(self.lw) self.lw.itemSelectionChanged.connect(self.on_select) lGroup = QGroupBox('项目列表') lGroup.setLayout(lLayout) cwHLayout.addWidget(lGroup, 2) lGroup.setContentsMargins(0, 12, 0, 22) tLayout = QVBoxLayout() bLayout = QHBoxLayout() self.tGroup = QGroupBox('配置信息') self.bGroup = QGroupBox('生成代码') self.tGroup.setLayout(tLayout) self.tGroup.setEnabled(False) self.bGroup.setLayout(bLayout) self.bGroup.setEnabled(False) cwHLayout.addWidget(self.tGroup, 8) cwVLayout.addLayout(cwHLayout) cwVLayout.addWidget(self.bGroup) self.tw_config = QTreeWidget() headerLabels = QStringList() headerLabels.append(' 项目') headerLabels.append(' 值') self.tw_config.setHeaderLabels(headerLabels) self.tw_config.setColumnWidth(0, 312) self.tw_config.setColumnWidth(1, 660) thLayout = QHBoxLayout() thLayout.setContentsMargins(0, 6, 0, 0) thLayout.addSpacing(10) modify_btn = QPushButton('') #修改 modify_btn.setObjectName('modify_btn') modify_btn.clicked.connect(self.on_modify) del_btn = QPushButton('') #删除 del_btn.setObjectName('del_btn') del_btn.clicked.connect(self.on_del) thLayout.addWidget(modify_btn) thLayout.addWidget(del_btn) thLayout.addStretch(0) tLayout.addLayout(thLayout) tLayout.addWidget(self.tw_config) bhLayout = QHBoxLayout() lable1 = QLabel('工程名称:') lable1.setSizePolicy(labelSizePolicy) self.et_project_name = QLineEdit() self.et_project_name.setSizePolicy(editSizePolicy) bhLayout.addWidget(lable1) bhLayout.addWidget(self.et_project_name) bhLayout.addSpacing(16) lable2 = QLabel('工程位置:') lable2.setSizePolicy(labelSizePolicy) self.et_project_location = QLineEdit() self.et_project_location.setReadOnly(True) self.et_project_location.setSizePolicy(editSizePolicy) btn_location = QPushButton('') #打开 btn_location.setObjectName('btn_location') btn_location.setSizePolicy(labelSizePolicy) btn_location.clicked.connect(self.getProjectLocation) bhLayout.addWidget(lable2) bhLayout.addWidget(self.et_project_location) bhLayout.addSpacing(10) bhLayout.addWidget(btn_location) #bhLayout.addStretch(0) gen_btn = QPushButton('') # 生成 gen_btn.setObjectName('gen_btn') gen_btn.setSizePolicy(labelSizePolicy) gen_btn.clicked.connect(self.on_gen) bhLayout.addSpacing(45) bhLayout.addWidget(gen_btn) bLayout.addLayout(bhLayout) bLayout.setContentsMargins(10, 24, 22, 34) statusBar = self.statusBar() sBH = QHBoxLayout() copyright = QLabel('') copyright.setAlignment(QtCore.Qt.AlignCenter) copyright.setStyleSheet("color:#acacac") statusBar.setMinimumHeight(30) statusBar.addWidget(copyright, 10) cw = QWidget() cw.setLayout(cwVLayout) self.setCentralWidget(cw) self._initByConfig() self.setMinimumSize(400, 200) def _initByConfig(self): '''初始化''' pass def createMenus(self): '''创建菜单''' self.ToolBar = self.addToolBar('') self.ToolBar.setMinimumHeight(54) newBtn = QToolButton() newBtn.setText('创建项目') newBtn.setIcon(QIcon(':/image/创建项目.png')) newBtn.setToolButtonStyle(3) newBtn.setFixedWidth(99) OpenBtn = QToolButton() OpenBtn.setText('打开项目') OpenBtn.setIcon(QIcon(':/image/打开.png')) OpenBtn.setToolButtonStyle(3) OpenBtn.setFixedWidth(99) AboutBtn = QToolButton() AboutBtn.setText('关于') AboutBtn.setIcon(QIcon(':/image/关于.png')) AboutBtn.setToolButtonStyle(3) AboutBtn.setFixedWidth(99) HelpBtn = QToolButton() HelpBtn.setText('帮助') HelpBtn.setIcon(QIcon(':/image/帮助.png')) HelpBtn.setToolButtonStyle(3) HelpBtn.setFixedWidth(99) newBtn.clicked.connect(self.on_new) OpenBtn.clicked.connect(self.on_open) AboutBtn.clicked.connect(self.on_about) HelpBtn.clicked.connect(self.on_help) self.ToolBar.addWidget(newBtn) self.ToolBar.addWidget(OpenBtn) self.ToolBar.addWidget(AboutBtn) self.ToolBar.addWidget(HelpBtn) self.ToolBar.setMovable(False) self.ToolBar.setVisible(True) def on_help(self): app.g_pwd = os.getcwd() if not (QtGui.QDesktopServices.openUrl( QUrl.fromLocalFile(app.g_pwd + os.sep + 'image' + os.sep + 'help.pdf'))): print app.g_pwd + os.sep + '/image/help.pdf' QMessageBox.critical(None, "Failure", "Cannot open help manual") def on_about(self): abt = AboutDlg() abt.exec_() def on_new(self): '''新建向导''' app.g_configurations = Configuration() # 用来渲染的配置数据 dlg = wizard.MyWizard() if dlg.exec_(): app.g_configurations.initialized = True app.g_projects.append(app.g_configurations) content = app.g_configurations.toJson() self.path = QFileDialog.getSaveFileName( self, "选择模板保存的路径", app.g_pwd + os.sep + "configurations" + os.sep + app.g_configurations.project_name.encode('utf-8') + ".json", "Config (*.json)") fileInfo = QFileInfo(self.path) if not self.path.isEmpty(): path = app.QString2str(self.path) with open(path, 'w+') as f: f.write(content) self.addConfig(fileInfo.baseName(), fileInfo.filePath(), content) #self.lw.addItem(app.g_configurations.project_name) def getProjectLocation(self): '''获取项目路径''' path = QFileDialog.getExistingDirectory() path = QDir.fromNativeSeparators(path) self.et_project_location.setText(path) def on_open(self): '''打开现有配置''' fileName = QFileDialog.getOpenFileName( self, "选择现有模板", app.g_pwd + os.sep + "configurations", "Config (*.json)") if fileName.isEmpty(): return self.path = fileName with open(app.QString2str(fileName), 'r') as f: content = f.read() fileInfo = QFileInfo(fileName) if not fileInfo.exists(): return config = Configuration() config.fromJson(content) config.allone_dir = os.getenv('ALLONEDIR', '../..').replace('\\', '/') self.addConfig(fileInfo.baseName(), fileInfo.filePath(), content) self.on_select() def on_del(self): self.tw_config.clear() self.bGroup.setEnabled(False) self.tGroup.setEnabled(False) index = self.lw.currentRow() self.lw.takeItem(index) def on_select(self): '''选取配置''' item = self.lw.currentItem() if item != None: content = item.data(QtCore.Qt.UserRole).toString() config = Configuration() config.fromJson(app.QString2str(content)) self.currentConfig = config self.showConfigInfo(self.currentConfig) self.bGroup.setEnabled(True) self.path = item.data(QtCore.Qt.UserRole + 1).toString() # index = self.lw.currentRow() # if index < len(app.g_projects): # self.currentConfig = app.g_projects[index] # self.showConfigInfo(self.currentConfig) # self.bGroup.setEnabled(True) def addConfig(self, fileName, filePath, config): item = QListWidgetItem(fileName) item.setData(QtCore.Qt.UserRole, config) item.setData(QtCore.Qt.UserRole + 1, filePath) self.lw.addItem(item) self.lw.setCurrentRow(0) def showConfigInfo(self, cf): '''显示配置信息''' self.tw_config.clear() self.et_project_name.setText(cf.project_name) self.et_project_location.setText(cf.project_location) sr = QStringList() sr.append('信息') root1 = QTreeWidgetItem(sr) sr = QStringList() sr.append('Qt库') root2 = QTreeWidgetItem(sr) sr = QStringList() sr.append('模块') root3a = QTreeWidgetItem(sr) sr = QStringList() sr.append('第三方库') root3b = QTreeWidgetItem(sr) sr = QStringList() sr.append('接口') root4 = QTreeWidgetItem(sr) self.tw_config.addTopLevelItem(root1) self.tw_config.addTopLevelItem(root2) self.tw_config.addTopLevelItem(root3a) self.tw_config.addTopLevelItem(root3b) self.tw_config.addTopLevelItem(root4) sr1c00 = QStringList() sr1c00.append("项目名称") sr1c00.append(cf.project_name) r1c00 = QTreeWidgetItem(sr1c00) root1.addChild(r1c00) # sr1c0 = QStringList() # sr1c0.append("项目位置") # sr1c0.append(cf.project_location) # r1c0 = QTreeWidgetItem(sr1c0) # root1.addChild(r1c0) sr1c1 = QStringList() sr1c1.append("组件类型") sr1c1.append(cf.component_type) r1c1 = QTreeWidgetItem(sr1c1) root1.addChild(r1c1) sr1c2 = QStringList() sr1c2.append("源模板") sr1c2.append(cf.template_source) r1c2 = QTreeWidgetItem(sr1c2) root1.addChild(r1c2) sr1c3 = QStringList() sr1c3.append("平台类型") tmp_pt = "" if cf.platform_type & configuration.PT_WIN32: tmp_pt += "win32;" if cf.platform_type & configuration.PT_LINUX: tmp_pt += "linux" sr1c3.append(tmp_pt) r1c3 = QTreeWidgetItem(sr1c3) root1.addChild(r1c3) sr1c4 = QStringList() sr1c4.append("平台级别") sr1c4.append(cf.platform_version) r1c4 = QTreeWidgetItem(sr1c4) root1.addChild(r1c4) sr1c5 = QStringList() sr1c5.append("资源文件") if cf.resourcesFile == "True": sr1c5.append("添加") else: sr1c5.append("未添加") r1c5 = QTreeWidgetItem(sr1c5) root1.addChild(r1c5) sr1c6 = QStringList() sr1c6.append("翻译文件") if cf.translateFile == "True": sr1c6.append("添加") else: sr1c6.append("未添加") r1c6 = QTreeWidgetItem(sr1c6) root1.addChild(r1c6) for qt in cf.qt_libs: sr2 = QStringList() sr2.append(qt['name']) sr2.append(qt['qt']) r2 = QTreeWidgetItem(sr2) root2.addChild(r2) for module in cf.modules: sr3a = QStringList() sr3a.append(module['name']) sr3a.append(module['description']) r3a = QTreeWidgetItem(sr3a) root3a.addChild(r3a) # sr3b = QStringList() # sr3b.append('ALLONE_DIR') # sr3b.append(os.getenv('ALLONEDIR','../..')) # 第二个参数是默认值 # r3b = QTreeWidgetItem(sr3b) # root3b.addChild(r3b) for info in cf.thirdpart_lib: sr3b = QStringList() sr3b.append(info['libname']) sr3b.append(info['libpath']) r3b = QTreeWidgetItem(sr3b) root3b.addChild(r3b) for key in cf.interfaces.keys(): sr4 = QStringList() sr4.append(key) if cf.interfaces[key]: sr4.append('实现') else: sr4.append('未实现') r4 = QTreeWidgetItem(sr4) root4.addChild(r4) self.tw_config.expandAll() self.tw_config.header().resizeSection(0, 300) self.tGroup.setEnabled(True) def on_modify(self): '''修改配置''' if self.currentConfig: app.g_configurations = copy.copy(self.currentConfig) dlg = wizard.MyWizard() if dlg.exec_(): item = self.lw.currentItem() if item != None: content = app.g_configurations.toJson() item.setData(QtCore.Qt.UserRole, content) path = item.data(QtCore.Qt.UserRole + 1).toString() if not path.isEmpty(): path = app.QString2str(path) with open(path, 'w+') as f: f.write(content) self.on_select() def on_gen(self): '''生成工程''' if not self.currentConfig: return #获取工程名及有效路径 project_name = self.et_project_name.text() project_location = self.et_project_location.text() qdir = QDir(project_location) if not qdir.exists(): if not qdir.mkpath(project_location): QMessageBox.warning(self, '警告', '路径无效!') return project_location = qdir.absolutePath() if not project_location.endsWith( '/') and not project_location.endsWith('\\'): project_location += os.sep project_location.replace('\\', '/') if project_name.isEmpty() or project_location.isEmpty(): QMessageBox.warning(self, '警告', '项目名称或路径不能为空!') return self.currentConfig.project_name = app.QString2str(project_name) self.currentConfig.project_location = app.QString2str(project_location) content = self.currentConfig.toJson() fileInfo = QFileInfo(self.path) if not self.path.isEmpty(): path = app.QString2str(self.path) with open(path, 'w+') as f: f.write(content) item = self.lw.currentItem() item.setData(QtCore.Qt.UserRole, content) template_name = self.currentConfig.template_source template_dir = app.g_pwd + os.sep + 'templates' + os.sep + template_name.encode( 'utf-8') with open(template_dir + os.sep + 'config.json', 'r') as f: self.currentConfig.config_content = f.read() ret_json = app.render(self.currentConfig.config_content, config=self.currentConfig) self.currentConfig.config = json.loads(ret_json) for file in self.currentConfig.config['files']: sourcepath = template_dir + os.sep + file['source'].encode('utf-8') targetdir = self.currentConfig.project_location + self.currentConfig.project_name targetpath = targetdir + os.sep + file['target'] fi = QFileInfo(targetpath) qdir = fi.absoluteDir() if not qdir.exists(): qdir.mkpath(fi.absolutePath()) with open(sourcepath, 'r') as f: content = f.read() content = app.render(content, config=self.currentConfig) #渲染文件 with open(targetpath, 'w+') as f: f.write(content.encode('utf-8')) QMessageBox.information(self, '提示', '生成成功!')
class mainwindow(QtGui.QMainWindow): '''主窗体''' def __init__(self): super(mainwindow,self).__init__() self.setWindowTitle('组件设计工具') self.showMaximized() self.menuBar().show() self.createMenus() cwHLayout = QHBoxLayout() lLayout = QVBoxLayout() rLayout = QVBoxLayout() self.lw = QListWidget() self.lw.setSelectionMode(QAbstractItemView.SingleSelection ) lLayout.addWidget(self.lw) self.lw.itemSelectionChanged.connect(self.on_select) lGroup = QGroupBox('项目列表') lGroup.setLayout(lLayout) cwHLayout.addWidget(lGroup,2) cwHLayout.addLayout(rLayout,8) tLayout = QVBoxLayout() bLayout = QVBoxLayout() tGroup = QGroupBox('配置信息') self.bGroup = QGroupBox('生成代码') tGroup.setLayout(tLayout) self.bGroup.setLayout(bLayout) self.bGroup.setEnabled(False) rLayout.addWidget(tGroup) rLayout.addWidget(self.bGroup) self.tw_config = QTreeWidget() headerLabels = QStringList() headerLabels.append('项目') headerLabels.append('值') self.tw_config.setHeaderLabels(headerLabels) thLayout = QHBoxLayout() thLayout.addStretch(0) modify_btn = QPushButton('修改') modify_btn.clicked.connect(self.on_modify) del_btn = QPushButton('删除') del_btn.clicked.connect(self.on_del) thLayout.addWidget(modify_btn) thLayout.addWidget(del_btn) tLayout.addWidget(self.tw_config) tLayout.addLayout(thLayout) bhLayout = QHBoxLayout() bhLayout.addStretch(0) gen_btn = QPushButton('生成') gen_btn.clicked.connect(self.on_gen) bhLayout.addWidget(gen_btn) row1 = QHBoxLayout() lable1 = QLabel('工程名称:') self.et_project_name = QLineEdit() row1.addSpacing(10) row1.addWidget(lable1) row1.addWidget(self.et_project_name) row1.addStretch(0) row2 = QHBoxLayout() lable2 = QLabel('工程位置:') self.et_project_location = QLineEdit() self.et_project_location.setReadOnly(True) btn_location = QPushButton('...') btn_location.setFixedWidth(50) btn_location.clicked.connect(self.getProjectLocation) row2.addSpacing(10) row2.addWidget(lable2) row2.addWidget(self.et_project_location) row2.addWidget(btn_location) row2.addStretch(0) bLayout.addLayout(row1) bLayout.addLayout(row2) bLayout.addLayout(bhLayout) cw = QWidget() cw.setLayout(cwHLayout) self.setCentralWidget(cw) self._initByConfig() self.setMinimumSize(400,200) def _initByConfig(self): '''初始化''' pass def createMenus(self): '''创建菜单''' menueBar = self.menuBar() menuSys = menueBar.addMenu('系统') actNew = menuSys.addAction('新建工程') actOpen = menuSys.addAction('打开工程') actNew.triggered.connect(self.on_new) actOpen.triggered.connect(self.on_open) menueBar.addMenu(menuSys) def on_new(self): '''新建向导''' app.g_configurations = Configuration() # 用来渲染的配置数据 dlg = wizard.MyWizard() if dlg.exec_(): app.g_configurations.initialized = True app.g_projects.append(app.g_configurations) content = app.g_configurations.toJson() path = QFileDialog.getSaveFileName(self,"选择模板保存的路径", app.g_pwd + os.sep + "configurations" + os.sep + app.g_configurations.project_name + ".json" ,"Config (*.json)") if not path.isEmpty(): path = app.QString2str(path) with open(path,'w+') as f: f.write(content) self.lw.addItem(app.g_configurations.project_name) def getProjectLocation(self): '''获取项目路径''' path = QFileDialog.getExistingDirectory() path = QDir.fromNativeSeparators(path) self.et_project_location.setText(path) def on_open(self): '''打开现有配置''' fileName = QFileDialog.getOpenFileName(self,"选择现有模板",app.g_pwd + os.sep + "configurations","Config (*.json)") if fileName.isEmpty(): return with open(app.QString2str(fileName), 'r') as f: content = f.read() config = Configuration() config.fromJson(content) app.g_projects.append(config) self.lw.addItem(config.project_name) def on_del(self): index = self.lw.currentRow() if index < app.g_projects: self.bGroup.setEnabled(False) self.lw.takeItem(index) config = app.g_projects[index] app.g_projects.remove(config) self.tw_config.clear() return def on_select(self): '''选取配置''' index = self.lw.currentRow() if index < app.g_projects: self.bGroup.setEnabled(True) self.currentConfig = app.g_projects[index] self.showConfigInfo(self.currentConfig) def showConfigInfo(self,cf): '''显示配置信息''' self.tw_config.clear() self.et_project_name.setText(cf.project_name) self.et_project_location.setText(cf.project_location) sr = QStringList() sr.append('信息') root1 = QTreeWidgetItem(sr) sr = QStringList() sr.append('Qt库') root2 = QTreeWidgetItem(sr) sr = QStringList() sr.append('模块') root3 = QTreeWidgetItem(sr) sr = QStringList() sr.append('接口') root4 = QTreeWidgetItem(sr) self.tw_config.addTopLevelItem(root1) self.tw_config.addTopLevelItem(root2) self.tw_config.addTopLevelItem(root3) self.tw_config.addTopLevelItem(root4) sr1c00 = QStringList() sr1c00.append("项目名称") sr1c00.append(cf.project_name) r1c00 = QTreeWidgetItem(sr1c00) root1.addChild(r1c00) # sr1c0 = QStringList() # sr1c0.append("项目位置") # sr1c0.append(cf.project_location) # r1c0 = QTreeWidgetItem(sr1c0) # root1.addChild(r1c0) sr1c1 = QStringList() sr1c1.append("组件类型") sr1c1.append(cf.component_type) r1c1 = QTreeWidgetItem(sr1c1) root1.addChild(r1c1) sr1c2 = QStringList() sr1c2.append("源模板") sr1c2.append(cf.template_source) r1c2 = QTreeWidgetItem(sr1c2) root1.addChild(r1c2) sr1c3 = QStringList() sr1c3.append("平台类型") tmp_pt = "" if cf.platform_type & configuration.PT_WIN32: tmp_pt += "win32;" if cf.platform_type & configuration.PT_LINUX: tmp_pt += "linux" sr1c3.append(tmp_pt) r1c3 = QTreeWidgetItem(sr1c3) root1.addChild(r1c3) sr1c4 = QStringList() sr1c4.append("平台级别") sr1c4.append(cf.platform_version) r1c4 = QTreeWidgetItem(sr1c4) root1.addChild(r1c4) for qt in cf.qt_libs: sr2 = QStringList() sr2.append(qt['name']) sr2.append(qt['qt']) r2 = QTreeWidgetItem(sr2) root2.addChild(r2) for module in cf.modules: sr3 = QStringList() sr3.append(module['name']) sr3.append(module['description']) r3 = QTreeWidgetItem(sr3) root3.addChild(r3) for key in cf.interfaces.keys(): sr4 = QStringList() sr4.append(key) if cf.interfaces[key]: sr4.append('实现') else: sr4.append('未实现') r4 = QTreeWidgetItem(sr4) root4.addChild(r4) self.tw_config.expandAll() self.tw_config.header().resizeSection(0,300) def on_modify(self): '''修改配置''' if self.currentConfig: app.g_configurations = copy.copy(self.currentConfig) dlg = wizard.MyWizard() if dlg.exec_(): index = self.lw.currentRow() if index < app.g_projects: self.currentConfig = app.g_configurations app.g_projects[index] = self.currentConfig self.showConfigInfo(self.currentConfig) def on_gen(self): '''生成工程''' if not self.currentConfig: return #获取工程名及有效路径 project_name = self.et_project_name.text() project_location = self.et_project_location.text() qdir = QDir(project_location) if not qdir.exists(): if not qdir.mkpath(project_location): QMessageBox.warning(self, '警告', '路径无效!') return project_location = qdir.absolutePath() if not project_location.endsWith('/') and not project_location.endsWith('\\'): project_location += os.sep if project_name.isEmpty() or project_location.isEmpty(): QMessageBox.warning(self, '警告', '项目名称或路径不能为空!') return self.currentConfig.project_name = app.QString2str(project_name) self.currentConfig.project_location = app.QString2str(project_location) template_name = self.currentConfig.template_source template_dir = app.g_pwd + os.sep + 'templates' + os.sep + template_name with open(template_dir + os.sep + 'config.json', 'r') as f: self.currentConfig.config_content = f.read() ret_json = app.render(self.currentConfig.config_content, config=self.currentConfig) self.currentConfig.config = json.loads(ret_json) for file in self.currentConfig.config['files']: sourcepath = template_dir + os.sep + file['source'] targetdir = self.currentConfig.project_location + self.currentConfig.project_name targetpath = targetdir + os.sep + file['target'] fi = QFileInfo(targetpath) qdir = fi.absoluteDir() if not qdir.exists(): qdir.mkpath(fi.absolutePath()) with open(sourcepath, 'r') as f: content = f.read() content = app.render(content, config=self.currentConfig) #渲染文件 with open(targetpath, 'w+') as f: f.write(content.encode('utf-8')) QMessageBox.information(self,'提示','生成成功!')
class OWItemsets(widget.OWWidget): name = 'Frequent Itemsets' description = 'Explore sets of items that frequently appear together.' icon = 'icons/FrequentItemsets.svg' priority = 10 inputs = [("Data", Table, 'set_data')] outputs = [(Output.DATA, Table)] minSupport = settings.Setting(30) maxItemsets = settings.Setting(10000) filterSearch = settings.Setting(True) autoFind = settings.Setting(False) autoSend = settings.Setting(True) filterKeywords = settings.Setting('') filterMinItems = settings.Setting(1) filterMaxItems = settings.Setting(10000) UserAdviceMessages = [ widget.Message( 'Itemset are listed in item-sorted order, i.e. ' 'an itemset containing A and B is only listed once, as ' 'A > B (and not also B > A).', 'itemsets-order', widget.Message.Warning), widget.Message( 'To select all the itemsets that are descendants of ' '(include) some item X (i.e. the whole subtree), you ' 'can fold the subtree at that item and then select it.', 'itemsets-order', widget.Message.Information) ] def __init__(self): self._is_running = False self.isRegexMatch = lambda x: True self.tree = QTreeWidget(self.mainArea, columnCount=2, allColumnsShowFocus=True, alternatingRowColors=True, selectionMode=QTreeWidget.ExtendedSelection, uniformRowHeights=True) self.tree.setHeaderLabels(["Itemsets", "Support", "%"]) self.tree.header().setStretchLastSection(True) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.mainArea.layout().addWidget(self.tree) box = gui.widgetBox(self.controlArea, "Info") self.nItemsets = self.nSelectedExamples = self.nSelectedItemsets = '' gui.label(box, self, "Number of itemsets: %(nItemsets)s") gui.label(box, self, "Selected itemsets: %(nSelectedItemsets)s") gui.label(box, self, "Selected examples: %(nSelectedExamples)s") hbox = gui.widgetBox(box, orientation='horizontal') gui.button(hbox, self, "Expand all", callback=self.tree.expandAll) gui.button(hbox, self, "Collapse all", callback=self.tree.collapseAll) box = gui.widgetBox(self.controlArea, 'Find itemsets') gui.valueSlider(box, self, 'minSupport', values=[.0001, .0005, .001, .005, .01, .05, .1, .5] + list(range(1, 101)), label='Minimal support:', labelFormat="%g%%", callback=lambda: self.find_itemsets()) gui.hSlider(box, self, 'maxItemsets', minValue=10000, maxValue=100000, step=10000, label='Max. number of itemsets:', labelFormat="%d", callback=lambda: self.find_itemsets()) self.button = gui.auto_commit(box, self, 'autoFind', 'Find itemsets', commit=self.find_itemsets) box = gui.widgetBox(self.controlArea, 'Filter itemsets') gui.lineEdit(box, self, 'filterKeywords', 'Contains:', callback=self.filter_change, orientation='horizontal', tooltip='A comma or space-separated list of regular ' 'expressions.') hbox = gui.widgetBox(box, orientation='horizontal') gui.spin(hbox, self, 'filterMinItems', 1, 998, label='Min. items:', callback=self.filter_change) gui.spin(hbox, self, 'filterMaxItems', 2, 999, label='Max. items:', callback=self.filter_change) gui.checkBox(box, self, 'filterSearch', label='Apply these filters in search', tooltip='If checked, the itemsets are filtered according ' 'to these filter conditions already in the search ' 'phase. \nIf unchecked, the only filters applied ' 'during search are the ones above, ' 'and the itemsets are \nfiltered afterwards only for ' 'display, i.e. only the matching itemsets are shown.') gui.rubber(hbox) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, 'autoSend', 'Send selection') self.filter_change() ITEM_DATA_ROLE = Qt.UserRole + 1 def selectionChanged(self): X = self.X mapping = self.onehot_mapping instances = set() where = np.where def whole_subtree(node): yield node for i in range(node.childCount()): yield from whole_subtree(node.child(i)) def itemset(node): while node: yield node.data(0, self.ITEM_DATA_ROLE) node = node.parent() def selection_ranges(node): n_children = node.childCount() if n_children: yield (self.tree.indexFromItem(node.child(0)), self.tree.indexFromItem(node.child(n_children - 1))) for i in range(n_children): yield from selection_ranges(node.child(i)) nSelectedItemsets = 0 item_selection = QItemSelection() for node in self.tree.selectedItems(): nodes = (node, ) if node.isExpanded() else whole_subtree(node) if not node.isExpanded(): for srange in selection_ranges(node): item_selection.select(*srange) for node in nodes: nSelectedItemsets += 1 cols, vals = zip(*(mapping[i] for i in itemset(node))) if issparse(X): rows = (len(cols) == np.bincount( (X[:, cols] != 0).indices, minlength=X.shape[0])).nonzero()[0] else: rows = where((X[:, cols] == vals).all(axis=1))[0] instances.update(rows) self.tree.itemSelectionChanged.disconnect(self.selectionChanged) self.tree.selectionModel().select( item_selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.nSelectedExamples = len(instances) self.nSelectedItemsets = nSelectedItemsets self.output = self.data[sorted(instances)] or None self.commit() def commit(self): self.send(Output.DATA, self.output) def filter_change(self): self.warning(9) try: isRegexMatch = self.isRegexMatch = re.compile( '|'.join( i.strip() for i in re.split('(,|\s)+', self.filterKeywords.strip()) if i.strip()), re.IGNORECASE).search except Exception as e: self.warning(9, 'Error in regular expression: {}'.format(e.args[0])) isRegexMatch = self.isRegexMatch = lambda x: True def hide(node, depth, has_kw): if not has_kw: has_kw = isRegexMatch(node.text(0)) hidden = ( sum( hide(node.child(i), depth + 1, has_kw) for i in range(node.childCount())) == node.childCount() if node.childCount() else (not has_kw or not self.filterMinItems <= depth <= self.filterMaxItems)) node.setHidden(hidden) return hidden hide(self.tree.invisibleRootItem(), 0, False) class TreeWidgetItem(QTreeWidgetItem): def data(self, column, role): """Construct lazy tooltips""" if role != Qt.ToolTipRole: return super().data(column, role) tooltip = [] while self: tooltip.append(self.text(0)) self = self.parent() return ' '.join(reversed(tooltip)) def find_itemsets(self): if self.data is None: return if self._is_running: return self._is_running = True data = self.data self.tree.clear() self.tree.setUpdatesEnabled(False) self.tree.blockSignals(True) class ItemDict(dict): def __init__(self, item): self.item = item top = ItemDict(self.tree.invisibleRootItem()) X, mapping = OneHot.encode(data) self.onehot_mapping = mapping ITEM_FMT = '{}' if issparse(data.X) else '{}={}' names = { item: ITEM_FMT.format(var.name, val) for item, var, val in OneHot.decode(mapping.keys(), data, mapping) } nItemsets = 0 filterSearch = self.filterSearch filterMinItems, filterMaxItems = self.filterMinItems, self.filterMaxItems isRegexMatch = self.isRegexMatch # Find itemsets and populate the TreeView with self.progressBar(self.maxItemsets + 1) as progress: for itemset, support in frequent_itemsets(X, self.minSupport / 100): if filterSearch and not filterMinItems <= len( itemset) <= filterMaxItems: continue parent = top first_new_item = None itemset_matches_filter = False for item in sorted(itemset): name = names[item] if filterSearch and not itemset_matches_filter: itemset_matches_filter = isRegexMatch(name) child = parent.get(name) if child is None: try: wi = self.TreeWidgetItem(parent.item, [ name, str(support), '{:.4g}'.format( 100 * support / len(data)) ]) except RuntimeError: # FIXME: When autoFind was in effect and the support # slider was moved, this line excepted with: # RuntimeError: wrapped C/C++ object of type # TreeWidgetItem has been deleted return wi.setData(0, self.ITEM_DATA_ROLE, item) child = parent[name] = ItemDict(wi) if first_new_item is None: first_new_item = (parent, name) parent = child if filterSearch and not itemset_matches_filter: parent, name = first_new_item parent.item.removeChild(parent[name].item) del parent[name].item del parent[name] else: nItemsets += 1 progress.advance() if nItemsets >= self.maxItemsets: break if not filterSearch: self.filter_change() self.nItemsets = nItemsets self.nSelectedItemsets = 0 self.nSelectedExamples = 0 self.tree.expandAll() for i in range(self.tree.columnCount()): self.tree.resizeColumnToContents(i) self.tree.setUpdatesEnabled(True) self.tree.blockSignals(False) self._is_running = False def set_data(self, data): self.data = data is_error = False if data is not None: self.warning(0) self.error(1) self.button.setDisabled(False) self.X = data.X if issparse(data.X): self.X = data.X.tocsc() else: if not data.domain.has_discrete_attributes(): self.error( 1, 'Discrete features required but data has none.') is_error = True self.button.setDisabled(True) elif data.domain.has_continuous_attributes(): self.warning( 0, 'Data has continuous attributes which will be skipped.' ) else: self.output = None self.commit() if self.autoFind and not is_error: self.find_itemsets()
class GmApp(QMainWindow): def __init__(self): super(QMainWindow, self).__init__() self.setWindowTitle("GuloMail by GulonSoft") self.setWindowIcon(QIcon("g-square.png")) self.createActions() self.createStatusBar() self.createMenus() self.createToolbars() self.createWidgets() self.createLayouts() def createActions(self): self.newAction=QAction("&New", self, shortcut=QKeySequence.New, statusTip="New") self.sendReceiveAction=QAction("Send / &Receive", self, shortcut="F9", statusTip="Send / Receive") self.printAction=QAction("&Print...", self, shortcut="Ctrl+P", statusTip="Print") self.quitAction=QAction("&Quit", self, shortcut="Ctrl+Q", statusTip="Quit", triggered=self.close) self.copyAction=QAction("&Copy", self, statusTip="Copy", shortcut=QKeySequence.Copy) self.deleteAction=QAction("&Delete", self, statusTip="Delete Message") self.nextAction=QAction("Next &Unread Message", self, shortcut="Ctrl+]", statusTip="Next unread message") self.previousAction=QAction("P&revious Unread Message", self, shortcut="Ctrl+[", statusTip="Previous unread message") self.replyAction=QAction("&Reply", self, shortcut="Ctrl+R", statusTip="Reply to sender", triggered=self.reply) self.replyToAllAction=QAction("Reply to &All", self, shortcut="Ctrl+Shift+R", statusTip="Reply to all", triggered=self.replyToAll) self.forwardAction=QAction("&Forward", self, shortcut="Ctrl+F", statusTip="Forward") self.junkAction=QAction("Junk", self, shortcut="Ctrl+J", statusTip="Mark as Junk") self.notJunkAction=QAction("Not junk", self, shortcut="Shift+Ctrl+J", statusTip="Mark as Not Junk") self.contentsAction=QAction("&Contents", self, statusTip="Help Contents", shortcut="F1", triggered=self.helpContents) self.aboutAction=QAction("&About", self, statusTip="About GuloMail", triggered=self.about) self.cancelAction=QAction("&Cancel", self, statusTip="Cancel") def createStatusBar(self): self.statusBar() def createMenus(self): self.fileMenu=self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAction) self.fileMenu.addAction(self.sendReceiveAction) self.fileMenu.addAction(self.printAction) self.fileMenu.addAction(self.quitAction) self.editMenu=self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.copyAction) self.editMenu.addAction(self.deleteAction) self.viewMenu=self.menuBar().addMenu("&View") self.folderMenu=self.menuBar().addMenu("F&older") self.messageMenu=self.menuBar().addMenu("&Message") self.goToMenu=self.messageMenu.addMenu("&Go To") self.goToMenu.addAction(self.nextAction) self.goToMenu.addAction(self.previousAction) self.messageMenu.addAction(self.replyAction) self.messageMenu.addAction(self.replyToAllAction) self.messageMenu.addAction(self.forwardAction) self.markAsMenu=self.messageMenu.addMenu("Mar&k as...") self.markAsMenu.addAction(self.junkAction) self.markAsMenu.addAction(self.notJunkAction) self.searchMenu=self.menuBar().addMenu("&Search") self.helpMenu=self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.contentsAction) self.helpMenu.addAction(self.aboutAction) def createToolbars(self): self.toolbar=self.addToolBar('Main Toolbar') self.toolbar.setMovable(False) self.toolbar.addAction(self.newAction) self.toolbar.addSeparator() self.toolbar.addAction(self.sendReceiveAction) self.toolbar.addSeparator() self.toolbar.addAction(self.replyAction) self.toolbar.addAction(self.replyToAllAction) self.toolbar.addAction(self.forwardAction) self.toolbar.addSeparator() self.toolbar.addAction(self.printAction) self.toolbar.addAction(self.deleteAction) self.toolbar.addAction(self.junkAction) self.toolbar.addAction(self.notJunkAction) self.toolbar.addAction(self.cancelAction) self.toolbar.addSeparator() self.toolbar.addAction(self.previousAction) self.toolbar.addAction(self.nextAction) def createWidgets(self): ## Message Table self.table=QTableView() self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setGridStyle(Qt.NoPen) self.model = QStandardItemModel(8, 3, self) self.model.setHeaderData(0, Qt.Horizontal, "From") self.model.setHeaderData(1, Qt.Horizontal, "Subject") self.model.setHeaderData(2, Qt.Horizontal, "Received") self.table.setModel(self.model) self.selectionModel = QItemSelectionModel(self.model) self.selectionModel.SelectionFlag=0x0020 self.table.setSelectionModel(self.selectionModel) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.setAlternatingRowColors(True) ## Folder Tree View self.folderTree=QTreeWidget() self.folderTree.setColumnCount(1) self.folderTree.setHeaderLabel(QString('Folders')) self.treeItem=QTreeWidgetItem() self.treeItem.setText(0, 'Folders') self.inbox=QTreeWidgetItem() self.inbox.setText(0, 'Inbox') self.deletedItems=QTreeWidgetItem() self.deletedItems.setText(0, 'Deleted Items') self.drafts=QTreeWidgetItem() self.drafts.setText(0, 'Drafts') self.junk=QTreeWidgetItem() self.junk.setText(0, 'Junk') self.outbox=QTreeWidgetItem() self.outbox.setText(0, 'Outbox') self.sent=QTreeWidgetItem() self.sent.setText(0, 'Sent') self.treeItem.addChild(self.inbox) self.treeItem.addChild(self.deletedItems) self.treeItem.addChild(self.drafts) self.treeItem.addChild(self.junk) self.treeItem.addChild(self.outbox) self.treeItem.addChild(self.sent) self.folderTree.addTopLevelItem(self.treeItem) self.folderTree.expandAll() self.folderTree.setAnimated(True) self.folderTree.setMaximumWidth(150) ## Temp. placeholders self.textEdit=QTextEdit() self.textEdit2=QTextEdit() def createLayouts(self): self.mainSplitter=QSplitter() self.setCentralWidget(self.mainSplitter) self.mainSplitter.addWidget(self.folderTree) self.messageSplitter=QSplitter(Qt.Vertical) self.messageSplitter.addWidget(self.table) self.messageSplitter.addWidget(self.textEdit2) self.mainSplitter.addWidget(self.messageSplitter) def helpContents(self): print "Help" def reply(self): print "Reply" def replyToAll(self): print "Reply To All" def about(self): text=QString("GuloMail v0.1\n\n") text.append("GuloMail is a freeware email client written in Python using PyQt4 (Python bindings for Nokia's Qt)\n\n") text.append(QChar(0x00A9)) text.append("GulonSoft 2010\nhttp://www.gulon.co.uk/") QMessageBox.about(self, "About GuloMail", text)
class OWGEODatasets(OWWidget): name = "GEO Data Sets" description = DESCRIPTION icon = "../widgets/icons/GEODataSets.svg" priority = PRIORITY inputs = [] outputs = [("Expression Data", Orange.data.Table)] settingsList = ["outputRows", "mergeSpots", "gdsSelectionStates", "splitterSettings", "currentGds", "autoCommit", "datasetNames"] outputRows = Setting(False) mergeSpots = Setting(True) gdsSelectionStates = Setting({}) currentGds = Setting(None) datasetNames = Setting({}) splitterSettings = Setting( (b'\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x01\xea\x00\x00\x00\xd7\x01\x00\x00\x00\x07\x01\x00\x00\x00\x02', b'\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x01\xb5\x00\x00\x02\x10\x01\x00\x00\x00\x07\x01\x00\x00\x00\x01') ) autoCommit = Setting(True) def __init__(self, parent=None, signalManager=None, name=" GEO Data Sets"): OWWidget.__init__(self, parent, signalManager, name) self.selectionChanged = False self.filterString = "" self.datasetName = "" ## GUI box = gui.widgetBox(self.controlArea, "Info", addSpace=True) self.infoBox = gui.widgetLabel(box, "Initializing\n\n") box = gui.widgetBox(self.controlArea, "Output", addSpace=True) gui.radioButtonsInBox(box, self, "outputRows", ["Genes or spots", "Samples"], "Rows", callback=self.commitIf) gui.checkBox(box, self, "mergeSpots", "Merge spots of same gene", callback=self.commitIf) gui.separator(box) self.nameEdit = gui.lineEdit( box, self, "datasetName", "Data set name", tooltip="Override the default output data set name", callback=self.onNameEdited ) self.nameEdit.setPlaceholderText("") if sys.version_info < (3, ): box = gui.widgetBox(self.controlArea, "Commit", addSpace=True) self.commitButton = gui.button( box, self, "Commit", callback=self.commit) cb = gui.checkBox(box, self, "autoCommit", "Commit on any change") gui.setStopper(self, self.commitButton, cb, "selectionChanged", self.commit) else: gui.auto_commit(self.controlArea, self, "autoCommit", "Commit", box="Commit") gui.rubber(self.controlArea) # self.filterLineEdit = OWGUIEx.lineEditHint( # self.mainArea, self, "filterString", "Filter", # caseSensitive=False, matchAnywhere=True, # callback=self.filter, delimiters=" ") gui.widgetLabel(self.mainArea, "Filter") self.filterLineEdit = QLineEdit( textChanged=self.filter ) self.completer = QCompleter( caseSensitivity=Qt.CaseInsensitive ) self.completer.setModel(QStringListModel(self)) self.filterLineEdit.setCompleter(self.completer) self.mainArea.layout().addWidget(self.filterLineEdit) splitter = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(splitter) self.treeWidget = QTreeView(splitter) self.treeWidget.setSelectionMode(QTreeView.SingleSelection) self.treeWidget.setRootIsDecorated(False) self.treeWidget.setSortingEnabled(True) self.treeWidget.setAlternatingRowColors(True) self.treeWidget.setUniformRowHeights(True) self.treeWidget.setEditTriggers(QTreeView.NoEditTriggers) linkdelegate = LinkStyledItemDelegate(self.treeWidget) self.treeWidget.setItemDelegateForColumn(1, linkdelegate) self.treeWidget.setItemDelegateForColumn(8, linkdelegate) self.treeWidget.setItemDelegateForColumn( 0, gui.IndicatorItemDelegate(self.treeWidget, role=Qt.DisplayRole)) proxyModel = MySortFilterProxyModel(self.treeWidget) self.treeWidget.setModel(proxyModel) self.treeWidget.selectionModel().selectionChanged.connect( self.updateSelection ) self.treeWidget.viewport().setMouseTracking(True) splitterH = QSplitter(Qt.Horizontal, splitter) box = gui.widgetBox(splitterH, "Description") self.infoGDS = gui.widgetLabel(box, "") self.infoGDS.setWordWrap(True) gui.rubber(box) box = gui.widgetBox(splitterH, "Sample Annotations") self.annotationsTree = QTreeWidget(box) self.annotationsTree.setHeaderLabels( ["Type (Sample annotations)", "Sample count"] ) self.annotationsTree.setRootIsDecorated(True) box.layout().addWidget(self.annotationsTree) self.annotationsTree.itemChanged.connect( self.annotationSelectionChanged ) self._annotationsUpdating = False self.splitters = splitter, splitterH for sp, setting in zip(self.splitters, self.splitterSettings): sp.splitterMoved.connect(self.splitterMoved) sp.restoreState(setting) self.searchKeys = ["dataset_id", "title", "platform_organism", "description"] self.gds = [] self.gds_info = None self.resize(1000, 600) self.setBlocking(True) self.setEnabled(False) self.progressBarInit() self._executor = ThreadExecutor() func = partial(get_gds_model, methodinvoke(self, "_setProgress", (float,))) self._inittask = Task(function=func) self._inittask.finished.connect(self._initializemodel) self._executor.submit(self._inittask) self._datatask = None @Slot(float) def _setProgress(self, value): self.progressBarValue = value def _initializemodel(self): assert self.thread() is QThread.currentThread() model, self.gds_info, self.gds = self._inittask.result() model.setParent(self) proxy = self.treeWidget.model() proxy.setFilterKeyColumn(0) proxy.setFilterRole(TextFilterRole) proxy.setFilterCaseSensitivity(False) proxy.setFilterFixedString(self.filterString) proxy.setSourceModel(model) proxy.sort(0, Qt.DescendingOrder) self.progressBarFinished() self.setBlocking(False) self.setEnabled(True) filter_items = " ".join( gds[key] for gds in self.gds for key in self.searchKeys ) tr_chars = ",.:;!?(){}[]_-+\\|/%#@$^&*<>~`" tr_table = str.maketrans(tr_chars, " " * len(tr_chars)) filter_items = filter_items.translate(tr_table) filter_items = sorted(set(filter_items.split(" "))) filter_items = [item for item in filter_items if len(item) > 3] self.completer.model().setStringList(filter_items) # self.filterLineEdit.setItems(filter_items) if self.currentGds: current_id = self.currentGds["dataset_id"] gdss = [(i, qunpack(proxy.data(proxy.index(i, 1), Qt.DisplayRole))) for i in range(proxy.rowCount())] current = [i for i, data in gdss if data and data == current_id] if current: current_index = proxy.index(current[0], 0) self.treeWidget.selectionModel().select( current_index, QItemSelectionModel.Select | QItemSelectionModel.Rows ) self.treeWidget.scrollTo( current_index, QTreeView.PositionAtCenter) for i in range(8): self.treeWidget.resizeColumnToContents(i) self.treeWidget.setColumnWidth( 1, min(self.treeWidget.columnWidth(1), 300)) self.treeWidget.setColumnWidth( 2, min(self.treeWidget.columnWidth(2), 200)) self.updateInfo() def updateInfo(self): gds_info = self.gds_info text = ("%i datasets\n%i datasets cached\n" % (len(gds_info), len(glob.glob(serverfiles.localpath("GEO") + "/GDS*")))) filtered = self.treeWidget.model().rowCount() if len(self.gds) != filtered: text += ("%i after filtering") % filtered self.infoBox.setText(text) def updateSelection(self, *args): current = self.treeWidget.selectedIndexes() mapToSource = self.treeWidget.model().mapToSource current = [mapToSource(index).row() for index in current] if current: self.currentGds = self.gds[current[0]] self.setAnnotations(self.currentGds) self.infoGDS.setText(self.currentGds.get("description", "")) self.nameEdit.setPlaceholderText(self.currentGds["title"]) self.datasetName = \ self.datasetNames.get(self.currentGds["dataset_id"], "") else: self.currentGds = None self.nameEdit.setPlaceholderText("") self.datasetName = "" self.commitIf() def setAnnotations(self, gds): self._annotationsUpdating = True self.annotationsTree.clear() annotations = defaultdict(set) subsetscount = {} for desc in gds["subsets"]: annotations[desc["type"]].add(desc["description"]) subsetscount[desc["description"]] = str(len(desc["sample_id"])) for type, subsets in annotations.items(): key = (gds["dataset_id"], type) subsetItem = QTreeWidgetItem(self.annotationsTree, [type]) subsetItem.setFlags(subsetItem.flags() | Qt.ItemIsUserCheckable | Qt.ItemIsTristate) subsetItem.setCheckState( 0, self.gdsSelectionStates.get(key, Qt.Checked) ) subsetItem.key = key for subset in subsets: key = (gds["dataset_id"], type, subset) item = QTreeWidgetItem( subsetItem, [subset, subsetscount.get(subset, "")] ) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState( 0, self.gdsSelectionStates.get(key, Qt.Checked) ) item.key = key self._annotationsUpdating = False self.annotationsTree.expandAll() for i in range(self.annotationsTree.columnCount()): self.annotationsTree.resizeColumnToContents(i) def annotationSelectionChanged(self, item, column): if self._annotationsUpdating: return for i in range(self.annotationsTree.topLevelItemCount()): item = self.annotationsTree.topLevelItem(i) self.gdsSelectionStates[item.key] = item.checkState(0) for j in range(item.childCount()): child = item.child(j) self.gdsSelectionStates[child.key] = child.checkState(0) def filter(self): filter_string = unicode(self.filterLineEdit.text()) proxyModel = self.treeWidget.model() if proxyModel: strings = filter_string.lower().strip().split() proxyModel.setFilterFixedStrings(strings) self.updateInfo() def selectedSamples(self): """ Return the currently selected sample annotations. The return value is a list of selected (sample type, sample value) tuples. .. note:: if some Sample annotation type has no selected values. this method will return all values for it. """ samples = [] unused_types = [] used_types = [] for stype in childiter(self.annotationsTree.invisibleRootItem()): selected_values = [] all_values = [] for sval in childiter(stype): value = (str(stype.text(0)), str(sval.text(0))) if self.gdsSelectionStates.get(sval.key, True): selected_values.append(value) all_values.append(value) if selected_values: samples.extend(selected_values) used_types.append(str(stype.text(0))) else: # If no sample of sample type is selected we don't filter # on it. samples.extend(all_values) unused_types.append(str(stype.text(0))) return samples, used_types def commitIf(self): if self.autoCommit: self.commit() else: self.selectionChanged = True def commit(self): if self.currentGds: self.error(0) sample_type = None self.progressBarInit() self.progressBarSet(10) _, groups = self.selectedSamples() if len(groups) == 1 and self.outputRows: sample_type = groups[0] self.setEnabled(False) self.setBlocking(True) def get_data(gds_id, report_genes, transpose, sample_type, title): gds = geo.GDS(gds_id) data = gds.getdata( report_genes=report_genes, transpose=transpose, sample_type=sample_type ) data.name = title return data get_data = partial( get_data, self.currentGds["dataset_id"], report_genes=self.mergeSpots, transpose=self.outputRows, sample_type=sample_type, title=self.datasetName or self.currentGds["title"] ) self._datatask = Task(function=get_data) self._datatask.finished.connect(self._on_dataready) self._executor.submit(self._datatask) def _on_dataready(self): self.setEnabled(True) self.setBlocking(False) self.progressBarSet(50) try: data = self._datatask.result() except urlrequest.URLError as error: self.error(0, "Error while connecting to the NCBI ftp server! %r" % error) self._datatask = None self.progressBarFinished() return self._datatask = None data_name = data.name samples, _ = self.selectedSamples() self.warning(0) message = None if self.outputRows: def samplesinst(ex): out = [] for meta in data.domain.metas: out.append((meta.name, ex[meta].value)) if data.domain.class_var.name != 'class': out.append((data.domain.class_var.name, ex[data.domain.class_var].value)) return out samples = set(samples) mask = [samples.issuperset(samplesinst(ex)) for ex in data] data = data[numpy.array(mask, dtype=bool)] if len(data) == 0: message = "No samples with selected sample annotations." else: samples = set(samples) domain = Orange.data.Domain( [attr for attr in data.domain.attributes if samples.issuperset(attr.attributes.items())], data.domain.class_var, data.domain.metas ) # domain.addmetas(data.domain.getmetas()) if len(domain.attributes) == 0: message = "No samples with selected sample annotations." stypes = set(s[0] for s in samples) for attr in domain.attributes: attr.attributes = dict( (key, value) for key, value in attr.attributes.items() if key in stypes ) data = Orange.data.Table(domain, data) if message is not None: self.warning(0, message) data_hints.set_hint(data, "taxid", self.currentGds.get("taxid", ""), 10.0) data_hints.set_hint(data, "genesinrows", self.outputRows, 10.0) self.progressBarFinished() data.name = data_name self.send("Expression Data", data) model = self.treeWidget.model().sourceModel() row = self.gds.index(self.currentGds) model.setData(model.index(row, 0), " ", Qt.DisplayRole) self.updateInfo() self.selectionChanged = False def splitterMoved(self, *args): self.splitterSettings = [str(sp.saveState()) for sp in self.splitters] def onDeleteWidget(self): if self._inittask: self._inittask.future().cancel() self._inittask.finished.disconnect(self._initializemodel) if self._datatask: self._datatask.future().cancel() self._datatask.finished.disconnect(self._on_dataready) self._executor.shutdown(wait=False) super(OWGEODatasets, self).onDeleteWidget() def onNameEdited(self): if self.currentGds: gds_id = self.currentGds["dataset_id"] self.datasetNames[gds_id] = unicode(self.nameEdit.text()) self.commitIf()
class Preferences(QDialog): configuration = {} weight = 0 def __init__(self, parent=None): super(Preferences, self).__init__(parent, Qt.Dialog) self.setWindowTitle(translations.TR_PREFERENCES_TITLE) self.setMinimumSize(QSize(800, 600)) self.setMaximumSize(QSize(0, 0)) vbox = QVBoxLayout(self) hbox = QHBoxLayout() vbox.setContentsMargins(0, 0, 5, 5) hbox.setContentsMargins(0, 0, 0, 0) self.tree = QTreeWidget() self.tree.header().setHidden(True) self.tree.setSelectionMode(QTreeWidget.SingleSelection) self.tree.setAnimated(True) self.tree.header().setHorizontalScrollMode( QAbstractItemView.ScrollPerPixel) self.tree.header().setResizeMode(0, QHeaderView.ResizeToContents) self.tree.header().setStretchLastSection(False) self.tree.setFixedWidth(200) self.stacked = QStackedLayout() hbox.addWidget(self.tree) hbox.addLayout(self.stacked) vbox.addLayout(hbox) hbox_footer = QHBoxLayout() self._btnSave = QPushButton(translations.TR_SAVE) self._btnCancel = QPushButton(translations.TR_CANCEL) hbox_footer.addSpacerItem(QSpacerItem(1, 0, QSizePolicy.Expanding)) hbox_footer.addWidget(self._btnCancel) hbox_footer.addWidget(self._btnSave) vbox.addLayout(hbox_footer) self.connect(self.tree, SIGNAL("itemSelectionChanged()"), self._change_current) self.connect(self._btnCancel, SIGNAL("clicked()"), self.close) self.connect(self._btnSave, SIGNAL("clicked()"), self._save_preferences) self.load_ui() self.tree.setCurrentItem(self.tree.topLevelItem(0)) def _save_preferences(self): self.emit(SIGNAL("savePreferences()")) self.close() def load_ui(self): sections = sorted(list(Preferences.configuration.keys()), key=lambda item: Preferences.configuration[item]['weight']) for section in sections: text = Preferences.configuration[section]['text'] Widget = Preferences.configuration[section]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) item = QTreeWidgetItem([text]) item.setData(0, Qt.UserRole, index) self.tree.addTopLevelItem(item) #Sort Item Children subcontent = Preferences.configuration[section].get( 'subsections', {}) subsections = sorted(list(subcontent.keys()), key=lambda item: subcontent[item]['weight']) for sub in subsections: text = subcontent[sub]['text'] Widget = subcontent[sub]['widget'] widget = Widget(self) area = QScrollArea() area.setWidgetResizable(True) area.setWidget(widget) index = self.stacked.addWidget(area) subitem = QTreeWidgetItem([text]) subitem.setData(0, Qt.UserRole, index) item.addChild(subitem) self.tree.expandAll() def _change_current(self): item = self.tree.currentItem() index = item.data(0, Qt.UserRole) self.stacked.setCurrentIndex(index) @classmethod def register_configuration(cls, section, widget, text, weight=None, subsection=None): if weight is None: Preferences.weight += 1 weight = Preferences.weight if not subsection: Preferences.configuration[section] = {'widget': widget, 'weight': weight, 'text': text} else: config = Preferences.configuration.get(section, {}) if not config: config[section] = {'widget': None, 'weight': 100} subconfig = config.get('subsections', {}) subconfig[subsection] = {'widget': widget, 'weight': weight, 'text': text} config['subsections'] = subconfig Preferences.configuration[section] = config
def __init__(self, term, row, parent=None): super(EditReportDialog, self).__init__(parent) self.term = term self.sid = term self.row = row terms = self.pullOnes('terms', self.term) datas = self.pullOnes('datas', self.row) session = self.pullOnes('session', terms['sessionID']) self.termname = str( session['name']) + ' ' + terms['name'] + ' Term Report' self.pagetitle = self.termname ko = 0 #prepare data d = datas['description'] d = d.split(':::') _title = d[0] _theme = d[1] _font = d[2] _ass = d[3] _gra = d[4] _set = d[5] _ass_list = _ass.split('::') _gra_list = _gra.split('::') _set_list = _set.split('::') _cla_list = _set.split('::') layout1 = QGridLayout() Form1 = QFormLayout() Form2 = QFormLayout() #title self.title = QLabel("Report Title") self.titleData = QLineEdit() self.titleData.setObjectName("name") self.titleData.setText(_title) tree = QTreeWidget() tree.setItemDelegate(Delegate()) tree.setHeaderLabel("Which grading system will you be using?") tree1 = QTreeWidget() tree1.setHeaderLabel("Choose Assessments and classes") tree2 = QTreeWidget() tree2.setHeaderLabel("Report Card Settings") self.ass_arr = {} parent = QTreeWidgetItem(tree1) parent.setText(0, "Select Assessments") parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) arr = self.pullCas() if arr and len(arr) > 0: for val in arr: dt = self.pullOne(val['name']) child = QTreeWidgetItem(parent) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(dt['name']).upper()) self.ass_arr[val['id']] = child if str(val['id']) in _ass_list: child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) ko += 1 self.cla_arr = {} parent1 = QTreeWidgetItem(tree1) parent1.setText(0, "Select Class") parent1.setFlags(parent1.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) arr = self.pullClass() if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(parent1) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) self.cla_arr[val['id']] = child va = str(val['id']) if (va in _cla_list): child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) ko += 1 self.gra_arr = {} parent2 = QTreeWidgetItem(tree) parent2.setText(0, "Select Grade") arr = self.pullGrade() if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(parent2) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(val['name']).upper()) self.gra_arr[val['id']] = child if str(val['id']) in _gra_list: child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) ko += 1 self.set_arr = {} parent3 = QTreeWidgetItem(tree2) parent3.setText(0, "Include ...") parent3.setFlags(parent3.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) arr = { 1: 'School Number', 2: 'Class Position', 3: 'Class Unit Position', 4: 'Total (100%)', 5: 'Total', 6: 'Grading', 7: 'Subject Average', 8: 'Ranking', 9: 'Ranking and Student Population', 10: 'Student Passport', 11: 'School Logo', 12: 'School Address', 13: 'Students Address', 14: 'Attendance', 15: 'Fees Owed', 16: 'Test/Assesments' } if arr and len(arr) > 0: for val in arr: child = QTreeWidgetItem(parent3) child.setFlags(child.flags() | Qt.ItemIsUserCheckable) child.setText(0, str(arr[val]).upper()) self.set_arr[val] = child if str(val) in _set_list: child.setCheckState(0, Qt.Checked) else: child.setCheckState(0, Qt.Unchecked) child1 = QTreeWidgetItem(parent3) child1.setFlags(child1.flags() | Qt.ItemIsUserCheckable) child1.setText(0, 'AFFECTIVE DOMAIN REPORT') self.set_arr['aff'] = child1 if 'aff' in _set_list: child1.setCheckState(0, Qt.Checked) else: child1.setCheckState(0, Qt.Unchecked) child2 = QTreeWidgetItem(child1) child2.setFlags(child2.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) child2.setText(0, 'TABLE') self.set_arr['afftable'] = child2 if 'afftable' in _set_list: child2.setCheckState(0, Qt.Checked) else: child2.setCheckState(0, Qt.Unchecked) child3 = QTreeWidgetItem(child1) child3.setFlags(child3.flags() | Qt.ItemIsUserCheckable) child3.setText(0, 'GRAPH') self.set_arr['affgraph'] = child3 if 'affgraph' in _set_list: child3.setCheckState(0, Qt.Checked) else: child3.setCheckState(0, Qt.Unchecked) child4 = QTreeWidgetItem(parent3) child4.setFlags(child4.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) child4.setText(0, 'PYSCHOMOTOR DOMAIN REPORT') self.set_arr['psy'] = child4 if 'psy' in _set_list: child4.setCheckState(0, Qt.Checked) else: child4.setCheckState(0, Qt.Unchecked) child5 = QTreeWidgetItem(child4) child5.setFlags(child5.flags() | Qt.ItemIsUserCheckable) child5.setText(0, 'TABLE') self.set_arr['psytable'] = child5 if 'psytable' in _set_list: child5.setCheckState(0, Qt.Checked) else: child5.setCheckState(0, Qt.Unchecked) child6 = QTreeWidgetItem(child4) child6.setFlags(child6.flags() | Qt.ItemIsUserCheckable) child6.setText(0, 'GRAPH') self.set_arr['psygraph'] = child6 if 'psygraph' in _set_list: child6.setCheckState(0, Qt.Checked) else: child6.setCheckState(0, Qt.Unchecked) tree.expandAll() tree1.expandAll() tree2.expandAll() #tree.show() self.l5 = QLabel("Theme Color") self.pbc = QPushButton() self.pbc.setObjectName("Pickcolor") self.pbc.setText("Click to change") self.le5 = QLineEdit() self.le5.setObjectName("Showcolor") self.le5.setText(_theme) self.pbc.setStyleSheet("background-color: " + _theme + "; color: white") self.connect(self.pbc, SIGNAL("clicked()"), lambda: self.color_picker()) self.l6 = QLabel("Pick Theme Font") self.pbf = QPushButton() self.pbf.setObjectName("Pickfont") self.pbf.setText(_font) self.le6 = QLineEdit() self.le6.setObjectName("Showcolor") self.le6.setText("#000000") self.pbf.setStyleSheet("color: black") self.connect(self.pbf, SIGNAL("clicked()"), lambda: self.font_picker()) self.lv_box = QHBoxLayout() self.lv_box.addWidget(self.pbc) self.lv_box.addWidget(self.le5) self.lv_box1 = QHBoxLayout() self.lv_box1.addWidget(self.pbf) self.lv_box1.addWidget(self.le6) Form1.addRow(self.title, self.titleData) Form2.addRow(self.l5, self.lv_box) Form2.addRow(self.l6, self.lv_box1) Gbo = QGridLayout() Gbo.addLayout(Form1, 0, 0, 1, 2) Gbo.addWidget(tree, 1, 0) Gbo.addWidget(tree1, 1, 1) Gbo.addWidget(tree2, 2, 0) Gbo.addLayout(Form2, 2, 1) groupBox1 = QGroupBox('Academic Report Setup') groupBox1.setLayout(Gbo) self.pb = QPushButton() self.pb.setObjectName("Add") self.pb.setText("Add Assessment") self.pb1 = QPushButton() self.pb1.setObjectName("Cancel") self.pb1.setText("Cancel") hbo = QHBoxLayout() hbo.addWidget(self.pb1) hbo.addStretch() hbo.addWidget(self.pb) groupBox2 = QGroupBox('') groupBox2.setLayout(hbo) grid = QGridLayout() grid.addWidget(groupBox1, 0, 0) grid.addWidget(groupBox2, 1, 0) self.setLayout(grid) self.connect(self.pb, SIGNAL("clicked()"), lambda: self.button_click(self)) self.connect(self.pb1, SIGNAL("clicked()"), lambda: self.button_close(self)) self.setWindowTitle(self.pagetitle)
class OWItemsets(widget.OWWidget): name = "Frequent Itemsets" description = "Explore sets of items that frequently appear together." icon = "icons/FrequentItemsets.svg" priority = 10 inputs = [("Data", Table, "set_data")] outputs = [(Output.DATA, Table)] minSupport = settings.Setting(30) maxItemsets = settings.Setting(10000) filterSearch = settings.Setting(True) autoFind = settings.Setting(False) autoSend = settings.Setting(True) filterKeywords = settings.Setting("") filterMinItems = settings.Setting(1) filterMaxItems = settings.Setting(10000) UserAdviceMessages = [ widget.Message( "Itemset are listed in item-sorted order, i.e. " "an itemset containing A and B is only listed once, as " "A > B (and not also B > A).", "itemsets-order", widget.Message.Warning, ), widget.Message( "To select all the itemsets that are descendants of " "(include) some item X (i.e. the whole subtree), you " "can fold the subtree at that item and then select it.", "itemsets-order", widget.Message.Information, ), ] def __init__(self): self._is_running = False self.isRegexMatch = lambda x: True self.tree = QTreeWidget( self.mainArea, columnCount=2, allColumnsShowFocus=True, alternatingRowColors=True, selectionMode=QTreeWidget.ExtendedSelection, uniformRowHeights=True, ) self.tree.setHeaderLabels(["Itemsets", "Support", "%"]) self.tree.header().setStretchLastSection(True) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.mainArea.layout().addWidget(self.tree) box = gui.widgetBox(self.controlArea, "Info") self.nItemsets = self.nSelectedExamples = self.nSelectedItemsets = "" gui.label(box, self, "Number of itemsets: %(nItemsets)s") gui.label(box, self, "Selected itemsets: %(nSelectedItemsets)s") gui.label(box, self, "Selected examples: %(nSelectedExamples)s") hbox = gui.widgetBox(box, orientation="horizontal") gui.button(hbox, self, "Expand all", callback=self.tree.expandAll) gui.button(hbox, self, "Collapse all", callback=self.tree.collapseAll) box = gui.widgetBox(self.controlArea, "Find itemsets") gui.valueSlider( box, self, "minSupport", values=[0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5] + list(range(1, 101)), label="Minimal support:", labelFormat="%g%%", callback=lambda: self.find_itemsets(), ) gui.hSlider( box, self, "maxItemsets", minValue=10000, maxValue=100000, step=10000, label="Max. number of itemsets:", labelFormat="%d", callback=lambda: self.find_itemsets(), ) self.button = gui.auto_commit(box, self, "autoFind", "Find itemsets", commit=self.find_itemsets) box = gui.widgetBox(self.controlArea, "Filter itemsets") gui.lineEdit( box, self, "filterKeywords", "Contains:", callback=self.filter_change, orientation="horizontal", tooltip="A comma or space-separated list of regular " "expressions.", ) hbox = gui.widgetBox(box, orientation="horizontal") gui.spin(hbox, self, "filterMinItems", 1, 998, label="Min. items:", callback=self.filter_change) gui.spin(hbox, self, "filterMaxItems", 2, 999, label="Max. items:", callback=self.filter_change) gui.checkBox( box, self, "filterSearch", label="Apply these filters in search", tooltip="If checked, the itemsets are filtered according " "to these filter conditions already in the search " "phase. \nIf unchecked, the only filters applied " "during search are the ones above, " "and the itemsets are \nfiltered afterwards only for " "display, i.e. only the matching itemsets are shown.", ) gui.rubber(hbox) gui.rubber(self.controlArea) gui.auto_commit(self.controlArea, self, "autoSend", "Send selection") self.filter_change() ITEM_DATA_ROLE = Qt.UserRole + 1 def selectionChanged(self): X = self.X mapping = self.onehot_mapping instances = set() where = np.where def whole_subtree(node): yield node for i in range(node.childCount()): yield from whole_subtree(node.child(i)) def itemset(node): while node: yield node.data(0, self.ITEM_DATA_ROLE) node = node.parent() def selection_ranges(node): n_children = node.childCount() if n_children: yield (self.tree.indexFromItem(node.child(0)), self.tree.indexFromItem(node.child(n_children - 1))) for i in range(n_children): yield from selection_ranges(node.child(i)) nSelectedItemsets = 0 item_selection = QItemSelection() for node in self.tree.selectedItems(): nodes = (node,) if node.isExpanded() else whole_subtree(node) if not node.isExpanded(): for srange in selection_ranges(node): item_selection.select(*srange) for node in nodes: nSelectedItemsets += 1 cols, vals = zip(*(mapping[i] for i in itemset(node))) if issparse(X): rows = (len(cols) == np.bincount((X[:, cols] != 0).indices, minlength=X.shape[0])).nonzero()[0] else: rows = where((X[:, cols] == vals).all(axis=1))[0] instances.update(rows) self.tree.itemSelectionChanged.disconnect(self.selectionChanged) self.tree.selectionModel().select(item_selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.tree.itemSelectionChanged.connect(self.selectionChanged) self.nSelectedExamples = len(instances) self.nSelectedItemsets = nSelectedItemsets self.output = self.data[sorted(instances)] or None self.commit() def commit(self): self.send(Output.DATA, self.output) def filter_change(self): self.warning(9) try: isRegexMatch = self.isRegexMatch = re.compile( "|".join(i.strip() for i in re.split("(,|\s)+", self.filterKeywords.strip()) if i.strip()), re.IGNORECASE, ).search except Exception as e: self.warning(9, "Error in regular expression: {}".format(e.args[0])) isRegexMatch = self.isRegexMatch = lambda x: True def hide(node, depth, has_kw): if not has_kw: has_kw = isRegexMatch(node.text(0)) hidden = ( sum(hide(node.child(i), depth + 1, has_kw) for i in range(node.childCount())) == node.childCount() if node.childCount() else (not has_kw or not self.filterMinItems <= depth <= self.filterMaxItems) ) node.setHidden(hidden) return hidden hide(self.tree.invisibleRootItem(), 0, False) class TreeWidgetItem(QTreeWidgetItem): def data(self, column, role): """Construct lazy tooltips""" if role != Qt.ToolTipRole: return super().data(column, role) tooltip = [] while self: tooltip.append(self.text(0)) self = self.parent() return " ".join(reversed(tooltip)) def find_itemsets(self): if self.data is None: return if self._is_running: return self._is_running = True data = self.data self.tree.clear() self.tree.setUpdatesEnabled(False) self.tree.blockSignals(True) class ItemDict(dict): def __init__(self, item): self.item = item top = ItemDict(self.tree.invisibleRootItem()) X, mapping = OneHot.encode(data) self.onehot_mapping = mapping ITEM_FMT = "{}" if issparse(data.X) else "{}={}" names = { item: ITEM_FMT.format(var.name, val) for item, var, val in OneHot.decode(mapping.keys(), data, mapping) } nItemsets = 0 filterSearch = self.filterSearch filterMinItems, filterMaxItems = self.filterMinItems, self.filterMaxItems isRegexMatch = self.isRegexMatch # Find itemsets and populate the TreeView with self.progressBar(self.maxItemsets + 1) as progress: for itemset, support in frequent_itemsets(X, self.minSupport / 100): if filterSearch and not filterMinItems <= len(itemset) <= filterMaxItems: continue parent = top first_new_item = None itemset_matches_filter = False for item in sorted(itemset): name = names[item] if filterSearch and not itemset_matches_filter: itemset_matches_filter = isRegexMatch(name) child = parent.get(name) if child is None: try: wi = self.TreeWidgetItem( parent.item, [name, str(support), "{:.4g}".format(100 * support / len(data))] ) except RuntimeError: # FIXME: When autoFind was in effect and the support # slider was moved, this line excepted with: # RuntimeError: wrapped C/C++ object of type # TreeWidgetItem has been deleted return wi.setData(0, self.ITEM_DATA_ROLE, item) child = parent[name] = ItemDict(wi) if first_new_item is None: first_new_item = (parent, name) parent = child if filterSearch and not itemset_matches_filter: parent, name = first_new_item parent.item.removeChild(parent[name].item) del parent[name].item del parent[name] else: nItemsets += 1 progress.advance() if nItemsets >= self.maxItemsets: break if not filterSearch: self.filter_change() self.nItemsets = nItemsets self.nSelectedItemsets = 0 self.nSelectedExamples = 0 self.tree.expandAll() for i in range(self.tree.columnCount()): self.tree.resizeColumnToContents(i) self.tree.setUpdatesEnabled(True) self.tree.blockSignals(False) self._is_running = False def set_data(self, data): self.data = data is_error = False if data is not None: self.warning(0) self.error(1) self.button.setDisabled(False) self.X = data.X if issparse(data.X): self.X = data.X.tocsc() else: if not data.domain.has_discrete_attributes(): self.error(1, "Discrete features required but data has none.") is_error = True self.button.setDisabled(True) elif data.domain.has_continuous_attributes(): self.warning(0, "Data has continuous attributes which will be skipped.") else: self.output = None self.commit() if self.autoFind and not is_error: self.find_itemsets()
class OWGEODatasets(OWWidget): name = "GEO Data Sets" description = DESCRIPTION icon = "../widgets/icons/GEODataSets.svg" priority = PRIORITY inputs = [] outputs = [("Expression Data", Orange.data.Table)] settingsList = [ "outputRows", "mergeSpots", "gdsSelectionStates", "splitterSettings", "currentGds", "autoCommit", "datasetNames" ] outputRows = Setting(True) mergeSpots = Setting(True) gdsSelectionStates = Setting({}) currentGds = Setting(None) datasetNames = Setting({}) splitterSettings = Setting(( b'\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x01\xea\x00\x00\x00\xd7\x01\x00\x00\x00\x07\x01\x00\x00\x00\x02', b'\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x01\xb5\x00\x00\x02\x10\x01\x00\x00\x00\x07\x01\x00\x00\x00\x01' )) autoCommit = Setting(False) def __init__(self, parent=None, signalManager=None, name=" GEO Data Sets"): OWWidget.__init__(self, parent, signalManager, name) self.selectionChanged = False self.filterString = "" self.datasetName = "" ## GUI box = gui.widgetBox(self.controlArea, "Info", addSpace=True) self.infoBox = gui.widgetLabel(box, "Initializing\n\n") box = gui.widgetBox(self.controlArea, "Output", addSpace=True) gui.radioButtonsInBox(box, self, "outputRows", ["Genes in rows", "Samples in rows"], "Rows", callback=self.commitIf) gui.checkBox(box, self, "mergeSpots", "Merge spots of same gene", callback=self.commitIf) gui.separator(box) self.nameEdit = gui.lineEdit( box, self, "datasetName", "Data set name", tooltip="Override the default output data set name", callback=self.onNameEdited) self.nameEdit.setPlaceholderText("") if sys.version_info < (3, ): box = gui.widgetBox(self.controlArea, "Commit", addSpace=True) self.commitButton = gui.button(box, self, "Commit", callback=self.commit) cb = gui.checkBox(box, self, "autoCommit", "Commit on any change") gui.setStopper(self, self.commitButton, cb, "selectionChanged", self.commit) else: gui.auto_commit(self.controlArea, self, "autoCommit", "Commit", box="Commit") self.commitIf = self.commit gui.rubber(self.controlArea) gui.widgetLabel(self.mainArea, "Filter") self.filterLineEdit = QLineEdit(textChanged=self.filter) self.completer = TokenListCompleter(self, caseSensitivity=Qt.CaseInsensitive) self.filterLineEdit.setCompleter(self.completer) self.mainArea.layout().addWidget(self.filterLineEdit) splitter = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(splitter) self.treeWidget = QTreeView(splitter) self.treeWidget.setSelectionMode(QTreeView.SingleSelection) self.treeWidget.setRootIsDecorated(False) self.treeWidget.setSortingEnabled(True) self.treeWidget.setAlternatingRowColors(True) self.treeWidget.setUniformRowHeights(True) self.treeWidget.setEditTriggers(QTreeView.NoEditTriggers) linkdelegate = LinkStyledItemDelegate(self.treeWidget) self.treeWidget.setItemDelegateForColumn(1, linkdelegate) self.treeWidget.setItemDelegateForColumn(8, linkdelegate) self.treeWidget.setItemDelegateForColumn( 0, gui.IndicatorItemDelegate(self.treeWidget, role=Qt.DisplayRole)) proxyModel = MySortFilterProxyModel(self.treeWidget) self.treeWidget.setModel(proxyModel) self.treeWidget.selectionModel().selectionChanged.connect( self.updateSelection) self.treeWidget.viewport().setMouseTracking(True) splitterH = QSplitter(Qt.Horizontal, splitter) box = gui.widgetBox(splitterH, "Description") self.infoGDS = gui.widgetLabel(box, "") self.infoGDS.setWordWrap(True) gui.rubber(box) box = gui.widgetBox(splitterH, "Sample Annotations") self.annotationsTree = QTreeWidget(box) self.annotationsTree.setHeaderLabels( ["Type (Sample annotations)", "Sample count"]) self.annotationsTree.setRootIsDecorated(True) box.layout().addWidget(self.annotationsTree) self.annotationsTree.itemChanged.connect( self.annotationSelectionChanged) self._annotationsUpdating = False self.splitters = splitter, splitterH for sp, setting in zip(self.splitters, self.splitterSettings): sp.splitterMoved.connect(self.splitterMoved) sp.restoreState(setting) self.searchKeys = [ "dataset_id", "title", "platform_organism", "description" ] self.gds = [] self.gds_info = None self.resize(1000, 600) self.setBlocking(True) self.setEnabled(False) self.progressBarInit() self._executor = ThreadExecutor() func = partial(get_gds_model, methodinvoke(self, "_setProgress", (float, ))) self._inittask = Task(function=func) self._inittask.finished.connect(self._initializemodel) self._executor.submit(self._inittask) self._datatask = None @Slot(float) def _setProgress(self, value): self.progressBarValue = value def _initializemodel(self): assert self.thread() is QThread.currentThread() model, self.gds_info, self.gds = self._inittask.result() model.setParent(self) proxy = self.treeWidget.model() proxy.setFilterKeyColumn(0) proxy.setFilterRole(TextFilterRole) proxy.setFilterCaseSensitivity(False) proxy.setFilterFixedString(self.filterString) proxy.setSourceModel(model) proxy.sort(0, Qt.DescendingOrder) self.progressBarFinished() self.setBlocking(False) self.setEnabled(True) filter_items = " ".join(gds[key] for gds in self.gds for key in self.searchKeys) tr_chars = ",.:;!?(){}[]_-+\\|/%#@$^&*<>~`" tr_table = str.maketrans(tr_chars, " " * len(tr_chars)) filter_items = filter_items.translate(tr_table) filter_items = sorted(set(filter_items.split(" "))) filter_items = [item for item in filter_items if len(item) > 3] self.completer.setTokenList(filter_items) if self.currentGds: current_id = self.currentGds["dataset_id"] gdss = [(i, qunpack(proxy.data(proxy.index(i, 1), Qt.DisplayRole))) for i in range(proxy.rowCount())] current = [i for i, data in gdss if data and data == current_id] if current: current_index = proxy.index(current[0], 0) self.treeWidget.selectionModel().select( current_index, QItemSelectionModel.Select | QItemSelectionModel.Rows) self.treeWidget.scrollTo(current_index, QTreeView.PositionAtCenter) for i in range(8): self.treeWidget.resizeColumnToContents(i) self.treeWidget.setColumnWidth( 1, min(self.treeWidget.columnWidth(1), 300)) self.treeWidget.setColumnWidth( 2, min(self.treeWidget.columnWidth(2), 200)) self.updateInfo() def updateInfo(self): gds_info = self.gds_info text = ("%i datasets\n%i datasets cached\n" % (len(gds_info), len(glob.glob(serverfiles.localpath("GEO") + "/GDS*")))) filtered = self.treeWidget.model().rowCount() if len(self.gds) != filtered: text += ("%i after filtering") % filtered self.infoBox.setText(text) def updateSelection(self, *args): current = self.treeWidget.selectedIndexes() mapToSource = self.treeWidget.model().mapToSource current = [mapToSource(index).row() for index in current] if current: self.currentGds = self.gds[current[0]] self.setAnnotations(self.currentGds) self.infoGDS.setText(self.currentGds.get("description", "")) self.nameEdit.setPlaceholderText(self.currentGds["title"]) self.datasetName = \ self.datasetNames.get(self.currentGds["dataset_id"], "") else: self.currentGds = None self.nameEdit.setPlaceholderText("") self.datasetName = "" self.commitIf() def setAnnotations(self, gds): self._annotationsUpdating = True self.annotationsTree.clear() annotations = defaultdict(set) subsetscount = {} for desc in gds["subsets"]: annotations[desc["type"]].add(desc["description"]) subsetscount[desc["description"]] = str(len(desc["sample_id"])) for type, subsets in annotations.items(): key = (gds["dataset_id"], type) subsetItem = QTreeWidgetItem(self.annotationsTree, [type]) subsetItem.setFlags(subsetItem.flags() | Qt.ItemIsUserCheckable | Qt.ItemIsTristate) subsetItem.setCheckState( 0, self.gdsSelectionStates.get(key, Qt.Checked)) subsetItem.key = key for subset in subsets: key = (gds["dataset_id"], type, subset) item = QTreeWidgetItem( subsetItem, [subset, subsetscount.get(subset, "")]) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState( 0, self.gdsSelectionStates.get(key, Qt.Checked)) item.key = key self._annotationsUpdating = False self.annotationsTree.expandAll() for i in range(self.annotationsTree.columnCount()): self.annotationsTree.resizeColumnToContents(i) def annotationSelectionChanged(self, item, column): if self._annotationsUpdating: return for i in range(self.annotationsTree.topLevelItemCount()): item = self.annotationsTree.topLevelItem(i) self.gdsSelectionStates[item.key] = item.checkState(0) for j in range(item.childCount()): child = item.child(j) self.gdsSelectionStates[child.key] = child.checkState(0) def filter(self): filter_string = unicode(self.filterLineEdit.text()) proxyModel = self.treeWidget.model() if proxyModel: strings = filter_string.lower().strip().split() proxyModel.setFilterFixedStrings(strings) self.updateInfo() def selectedSamples(self): """ Return the currently selected sample annotations. The return value is a list of selected (sample type, sample value) tuples. .. note:: if some Sample annotation type has no selected values. this method will return all values for it. """ samples = [] unused_types = [] used_types = [] for stype in childiter(self.annotationsTree.invisibleRootItem()): selected_values = [] all_values = [] for sval in childiter(stype): value = (str(stype.text(0)), str(sval.text(0))) if self.gdsSelectionStates.get(sval.key, True): selected_values.append(value) all_values.append(value) if selected_values: samples.extend(selected_values) used_types.append(str(stype.text(0))) else: # If no sample of sample type is selected we don't filter # on it. samples.extend(all_values) unused_types.append(str(stype.text(0))) return samples, used_types def commitIf(self): if self.autoCommit: self.commit() else: self.selectionChanged = True @Slot(int, int) def progressCompleted(self, value, total): if total > 0: self.progressBarSet(100. * value / total, processEvents=False) else: pass # TODO: report 'indeterminate progress' def commit(self): if self.currentGds: self.error(0) sample_type = None self.progressBarInit(processEvents=None) _, groups = self.selectedSamples() if len(groups) == 1 and self.outputRows: sample_type = groups[0] self.setEnabled(False) self.setBlocking(True) progress = methodinvoke(self, "progressCompleted", (int, int)) def get_data(gds_id, report_genes, transpose, sample_type, title): gds_ensure_downloaded(gds_id, progress) gds = geo.GDS(gds_id) data = gds.getdata(report_genes=report_genes, transpose=transpose, sample_type=sample_type) data.name = title return data get_data = partial(get_data, self.currentGds["dataset_id"], report_genes=self.mergeSpots, transpose=self.outputRows, sample_type=sample_type, title=self.datasetName or self.currentGds["title"]) self._datatask = Task(function=get_data) self._datatask.finished.connect(self._on_dataready) self._executor.submit(self._datatask) def _on_dataready(self): self.setEnabled(True) self.setBlocking(False) self.progressBarFinished(processEvents=False) try: data = self._datatask.result() except urlrequest.URLError as error: self.error(0, ("Error while connecting to the NCBI ftp server! " "'%s'" % error)) sys.excepthook(type(error), error, getattr(error, "__traceback__")) return finally: self._datatask = None data_name = data.name samples, _ = self.selectedSamples() self.warning(0) message = None if self.outputRows: def samplesinst(ex): out = [] for meta in data.domain.metas: out.append((meta.name, ex[meta].value)) if data.domain.class_var.name != 'class': out.append((data.domain.class_var.name, ex[data.domain.class_var].value)) return out samples = set(samples) mask = [samples.issuperset(samplesinst(ex)) for ex in data] data = data[numpy.array(mask, dtype=bool)] if len(data) == 0: message = "No samples with selected sample annotations." else: samples = set(samples) domain = Orange.data.Domain([ attr for attr in data.domain.attributes if samples.issuperset(attr.attributes.items()) ], data.domain.class_var, data.domain.metas) # domain.addmetas(data.domain.getmetas()) if len(domain.attributes) == 0: message = "No samples with selected sample annotations." stypes = set(s[0] for s in samples) for attr in domain.attributes: attr.attributes = dict( (key, value) for key, value in attr.attributes.items() if key in stypes) data = Orange.data.Table(domain, data) if message is not None: self.warning(0, message) data_hints.set_hint(data, "taxid", self.currentGds.get("taxid", ""), 10.0) data_hints.set_hint(data, "genesinrows", self.outputRows, 10.0) data.name = data_name self.send("Expression Data", data) model = self.treeWidget.model().sourceModel() row = self.gds.index(self.currentGds) model.setData(model.index(row, 0), " ", Qt.DisplayRole) self.updateInfo() self.selectionChanged = False def splitterMoved(self, *args): self.splitterSettings = [ bytes(sp.saveState()) for sp in self.splitters ] def send_report(self): self.report_items("GEO Dataset", [("ID", self.currentGds['dataset_id']), ("Title", self.currentGds['title']), ("Organism", self.currentGds['sample_organism'])]) self.report_items("Data", [("Samples", self.currentGds['sample_count']), ("Features", self.currentGds['feature_count']), ("Genes", self.currentGds['gene_count'])]) self.report_name("Sample annotations") subsets = defaultdict(list) for subset in self.currentGds['subsets']: subsets[subset['type']].append( (subset['description'], len(subset['sample_id']))) self.report_html += "<ul>" for type in subsets: self.report_html += "<b>" + type + ":</b></br>" for desc, count in subsets[type]: self.report_html += 9 * " " + "<b>{}:</b> {}</br>".format( desc, count) self.report_html += "</ul>" def onDeleteWidget(self): if self._inittask: self._inittask.future().cancel() self._inittask.finished.disconnect(self._initializemodel) if self._datatask: self._datatask.future().cancel() self._datatask.finished.disconnect(self._on_dataready) self._executor.shutdown(wait=False) super(OWGEODatasets, self).onDeleteWidget() def onNameEdited(self): if self.currentGds: gds_id = self.currentGds["dataset_id"] self.datasetNames[gds_id] = unicode(self.nameEdit.text()) self.commitIf()
def expandAll(self): self._treeDepth=10000 QTreeWidget.expandAll(self)
class GmApp(QMainWindow): def __init__(self): super(QMainWindow, self).__init__() self.setWindowTitle("GuloMail by GulonSoft") self.setWindowIcon(QIcon("g-square.png")) self.createActions() self.createStatusBar() self.createMenus() self.createToolbars() self.createWidgets() self.createLayouts() def createActions(self): self.newAction = QAction("&New", self, shortcut=QKeySequence.New, statusTip="New") self.sendReceiveAction = QAction("Send / &Receive", self, shortcut="F9", statusTip="Send / Receive") self.printAction = QAction("&Print...", self, shortcut="Ctrl+P", statusTip="Print") self.quitAction = QAction("&Quit", self, shortcut="Ctrl+Q", statusTip="Quit", triggered=self.close) self.copyAction = QAction("&Copy", self, statusTip="Copy", shortcut=QKeySequence.Copy) self.deleteAction = QAction("&Delete", self, statusTip="Delete Message") self.nextAction = QAction("Next &Unread Message", self, shortcut="Ctrl+]", statusTip="Next unread message") self.previousAction = QAction("P&revious Unread Message", self, shortcut="Ctrl+[", statusTip="Previous unread message") self.replyAction = QAction("&Reply", self, shortcut="Ctrl+R", statusTip="Reply to sender", triggered=self.reply) self.replyToAllAction = QAction("Reply to &All", self, shortcut="Ctrl+Shift+R", statusTip="Reply to all", triggered=self.replyToAll) self.forwardAction = QAction("&Forward", self, shortcut="Ctrl+F", statusTip="Forward") self.junkAction = QAction("Junk", self, shortcut="Ctrl+J", statusTip="Mark as Junk") self.notJunkAction = QAction("Not junk", self, shortcut="Shift+Ctrl+J", statusTip="Mark as Not Junk") self.contentsAction = QAction("&Contents", self, statusTip="Help Contents", shortcut="F1", triggered=self.helpContents) self.aboutAction = QAction("&About", self, statusTip="About GuloMail", triggered=self.about) self.cancelAction = QAction("&Cancel", self, statusTip="Cancel") def createStatusBar(self): self.statusBar() def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAction) self.fileMenu.addAction(self.sendReceiveAction) self.fileMenu.addAction(self.printAction) self.fileMenu.addAction(self.quitAction) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.copyAction) self.editMenu.addAction(self.deleteAction) self.viewMenu = self.menuBar().addMenu("&View") self.folderMenu = self.menuBar().addMenu("F&older") self.messageMenu = self.menuBar().addMenu("&Message") self.goToMenu = self.messageMenu.addMenu("&Go To") self.goToMenu.addAction(self.nextAction) self.goToMenu.addAction(self.previousAction) self.messageMenu.addAction(self.replyAction) self.messageMenu.addAction(self.replyToAllAction) self.messageMenu.addAction(self.forwardAction) self.markAsMenu = self.messageMenu.addMenu("Mar&k as...") self.markAsMenu.addAction(self.junkAction) self.markAsMenu.addAction(self.notJunkAction) self.searchMenu = self.menuBar().addMenu("&Search") self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.contentsAction) self.helpMenu.addAction(self.aboutAction) def createToolbars(self): self.toolbar = self.addToolBar('Main Toolbar') self.toolbar.setMovable(False) self.toolbar.addAction(self.newAction) self.toolbar.addSeparator() self.toolbar.addAction(self.sendReceiveAction) self.toolbar.addSeparator() self.toolbar.addAction(self.replyAction) self.toolbar.addAction(self.replyToAllAction) self.toolbar.addAction(self.forwardAction) self.toolbar.addSeparator() self.toolbar.addAction(self.printAction) self.toolbar.addAction(self.deleteAction) self.toolbar.addAction(self.junkAction) self.toolbar.addAction(self.notJunkAction) self.toolbar.addAction(self.cancelAction) self.toolbar.addSeparator() self.toolbar.addAction(self.previousAction) self.toolbar.addAction(self.nextAction) def createWidgets(self): ## Message Table self.table = QTableView() self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setGridStyle(Qt.NoPen) self.model = QStandardItemModel(8, 3, self) self.model.setHeaderData(0, Qt.Horizontal, "From") self.model.setHeaderData(1, Qt.Horizontal, "Subject") self.model.setHeaderData(2, Qt.Horizontal, "Received") self.table.setModel(self.model) self.selectionModel = QItemSelectionModel(self.model) self.selectionModel.SelectionFlag = 0x0020 self.table.setSelectionModel(self.selectionModel) self.table.horizontalHeader().setStretchLastSection(True) self.table.verticalHeader().setVisible(False) self.table.setSortingEnabled(True) self.table.setAlternatingRowColors(True) ## Folder Tree View self.folderTree = QTreeWidget() self.folderTree.setColumnCount(1) self.folderTree.setHeaderLabel(QString('Folders')) self.treeItem = QTreeWidgetItem() self.treeItem.setText(0, 'Folders') self.inbox = QTreeWidgetItem() self.inbox.setText(0, 'Inbox') self.deletedItems = QTreeWidgetItem() self.deletedItems.setText(0, 'Deleted Items') self.drafts = QTreeWidgetItem() self.drafts.setText(0, 'Drafts') self.junk = QTreeWidgetItem() self.junk.setText(0, 'Junk') self.outbox = QTreeWidgetItem() self.outbox.setText(0, 'Outbox') self.sent = QTreeWidgetItem() self.sent.setText(0, 'Sent') self.treeItem.addChild(self.inbox) self.treeItem.addChild(self.deletedItems) self.treeItem.addChild(self.drafts) self.treeItem.addChild(self.junk) self.treeItem.addChild(self.outbox) self.treeItem.addChild(self.sent) self.folderTree.addTopLevelItem(self.treeItem) self.folderTree.expandAll() self.folderTree.setAnimated(True) self.folderTree.setMaximumWidth(150) ## Temp. placeholders self.textEdit = QTextEdit() self.textEdit2 = QTextEdit() def createLayouts(self): self.mainSplitter = QSplitter() self.setCentralWidget(self.mainSplitter) self.mainSplitter.addWidget(self.folderTree) self.messageSplitter = QSplitter(Qt.Vertical) self.messageSplitter.addWidget(self.table) self.messageSplitter.addWidget(self.textEdit2) self.mainSplitter.addWidget(self.messageSplitter) def helpContents(self): print "Help" def reply(self): print "Reply" def replyToAll(self): print "Reply To All" def about(self): text = QString("GuloMail v0.1\n\n") text.append( "GuloMail is a freeware email client written in Python using PyQt4 (Python bindings for Nokia's Qt)\n\n" ) text.append(QChar(0x00A9)) text.append("GulonSoft 2010\nhttp://www.gulon.co.uk/") QMessageBox.about(self, "About GuloMail", text)