def saveWorkspace(self): """ Saves the current workspace as is. Saves the trees and all of the nodes (and node data). Does not save windows or window options, but does save the structure information. """ sel = QFileDialog.getSaveFileName( parent=self, caption="Save Workspace", directory=QDir.homePath(), filter="Linnaeo Workspace (*.lno);;Any (*)") filename = sel[0] if filename: if filename[-4:] != ".lno": filename = str(filename + ".lno") file = QFile(filename) file.open(QIODevice.WriteOnly) out = QDataStream(file) self.mainLogger.debug("Beginning file save") out.writeQVariantHash(self.sequences) out.writeQVariantList(self.titles) out.writeUInt32(self.windex) ##################################### # Sequence View ### self.mainLogger.debug("SEQUENCE TREE") self.mainLogger.debug("Children count: %s" % self.bioModel.invisibleRootItem().rowCount()) out.writeUInt32(self.bioModel.invisibleRootItem().rowCount()) for node in utilities.iterTreeView( self.bioModel.invisibleRootItem()): self.mainLogger.debug("Node: %s" % str(node.text())) node.write(out) out.writeUInt32(node.rowCount()) ##################################### # Alignment View # Does not save any metadata! Only the two sequences # So I can't save window options at the moment. # TODO: Consider adding "window modes" to the node. self.mainLogger.debug("ALIGNMENT TREE") self.mainLogger.debug("Children count: %s" % self.bioModel.invisibleRootItem().rowCount()) out.writeUInt32(self.projectModel.invisibleRootItem().rowCount()) for node in utilities.iterTreeView( self.projectModel.invisibleRootItem()): self.mainLogger.debug("Node: %s" % str(node.text())) node.write(out) out.writeUInt32(node.rowCount()) self.mainLogger.debug("Save complete") file.flush() file.close() del sel, filename, file, out, node return True else: self.mainLogger.debug("No filename chosen; canceling") del sel return False
def rebuildTrees(self): """ Run after loading a saved file. At this point, the sequences and the alignments both have Window IDs applied -- but the windows no longer exist. This rebuilds the windows using the saved window IDs and updates the respective models. """ for node in utilities.iterTreeView(self.bioModel.invisibleRootItem()): if node.data(role=self.SequenceRole): self.mainLogger.info("Loading sequence: " + node.data()) self.mainStatus.showMessage("Loading sequence: %s" % node.data(), msecs=3000) ali = {} # empty dict needed to send to open window wid = node.data(role=self.WindowRole) seqr = node.data(role=self.SequenceRole)[0] ali[seqr.name] = str(seqr.seq) self.makeNewWindow(wid, ali, nonode=True) for node in utilities.iterTreeView( self.projectModel.invisibleRootItem()): if node.data(role=self.SequenceRole): self.mainLogger.info("Loading alignment: " + node.data()) self.mainStatus.showMessage("Loading alignment: %s" % node.data(), msecs=3000) seqs = {} wid = node.data(role=self.WindowRole) seqr = node.data(role=self.SequenceRole) for seq in seqr: seqs[seq.name] = str(seq.seq) worker = utilities.AlignThread( self, seqs, seqtype=3, num_threads=self.threadpool.maxThreadCount()) worker.start() worker.finished.connect(worker.deleteLater) worker.finished.connect(worker.quit) worker.wait() ali = worker.aligned del worker self.makeNewWindow(wid, ali, nonode=True) self.bioModel.updateWindows(self.windows) self.projectModel.updateWindows(self.windows) self.mainStatus.showMessage( f"Loading complete! took {float(time.perf_counter()-self.start):.2f} seconds", msecs=4000) self.mainLogger.debug("Regenerating windows took took %f seconds" % float(time.perf_counter() - self.start)) del node
def get_UniprotId(self): """ Uses BioServices to query Uniprot using the saved Sequence ID. See the GetPDBThread for more info. For some reason, on macs the button fails to be disabled after clicking when I freeze the binary... no idea why. """ if self._currentWindow: self.runningDSSP.append(self._currentWindow) self.optionsPane.buttonStructure.setEnabled(False) found = False wid = self._currentWindow.wid for node in utilities.iterTreeView( self.bioModel.invisibleRootItem()): if node.data(self.WindowRole) == wid: self.mainStatus.showMessage( "Beginning PDB search via UNIPROT") self.mainLogger.info( "Running UNIPROT search with the sequence") worker = utilities.GetPDBThread( [node.data(role=self.SequenceRole), [node.index()]], parent=self) worker.logger.connect(self.statuslogger) worker.finished.connect(self.pdbSearchDone) worker.finished.connect(worker.deleteLater) worker.finished.connect(worker.quit) worker.start() del worker, node found = True if not found: for node in utilities.iterTreeView( self.projectModel.invisibleRootItem()): if node.data(self.WindowRole) == wid: self.mainStatus.showMessage( "Beginning PDB search via UNIPROT") self.mainLogger.info( "Running UNIPROT search with first sequence of the alignment" ) seqs = [] # ONLY RUN ON THE TOP SEQUENCE FOR NOW for x in node.data(role=self.SequenceRole): seqs.append(x) worker = utilities.GetPDBThread( [[seqs[0]], [node.index()]], parent=self) worker.finished.connect(self.pdbSearchDone) worker.finished.connect(worker.deleteLater) worker.finished.connect(worker.quit) worker.start() del worker, node, x del found, wid
def _queryTrees(self): """ Currently not used. Spits out everything in the tree. """ print("\n\nBIOROOT") for child in utilities.iterTreeView(self.bioModel.invisibleRootItem()): print("Text: ", child.text()) print("Name: ", child.data(role=Qt.UserRole + 1)) print("Seq: ", child.data(role=Qt.UserRole + 2)) print("Window Index: ", child.data(role=Qt.UserRole + 3)) print("ALIGNMENT ROOT") for child in utilities.iterTreeView( self.projectModel.invisibleRootItem()): print("Text: ", child.text()) print("Name: ", child.data(role=Qt.UserRole + 1)) print("Seq: ", child.data(role=Qt.UserRole + 2)) print("Window Index: ", child.data(role=Qt.UserRole + 3))
def openWindow(self, sub): """ Checks to see if a window is open already. If it is not, reopens the window. If it is, gives focus. """ self.localtime = time.perf_counter() found = False for node in utilities.iterTreeView(self.bioModel.invisibleRootItem()): if node.data(self.WindowRole) == sub.wid: if node.data(self.StructureRole): sub.widget().addStructure(node.data(self.StructureRole), node.data(self.SequenceRole)[0]) found = True if not found: seq = None for node in utilities.iterTreeView( self.projectModel.invisibleRootItem()): if node.data(self.WindowRole) == sub.wid: if node.data(self.StructureRole): seq = node.data(self.SequenceRole)[0] sub.widget().addStructure( node.data(self.StructureRole), seq) found = True del seq del found, node sub.widget().setParams(self.optionsPane.params) if sub.mdiArea() != self.mdiArea: self.mainLogger.debug( "Adding window to MDI Area; creation took %f seconds" % float(time.perf_counter() - self.localtime)) # print(sub.widget().params) # self.sendParams.emit(sub.widget().params.copy()) self.mdiArea.addSubWindow(sub) #print("SUBWINDOWS: %s" % len(self.mdiArea.subWindowList())) else: sub.show() self.mdiArea.setActiveSubWindow(sub) del sub
def pruneNames(self): """ This checks which names are in "TITLES" and deletes if they were not. """ names = [] pruned = [] for node in utilities.iterTreeView(self.bioModel.invisibleRootItem()): if node.data(role=self.SequenceRole): names.append(node.text()) for key, value in self.sequences.items(): if node.data(role=self.SequenceRole) == value: value[0].name = node.data( role=self.SequenceRole)[0].name for title in self.titles: if title not in names: pruned.append(title) self.mainLogger.debug("Tree names: " + str(names) + " vs. Stored names: " + str(self.titles)) self.titles = [x for x in self.titles and names if x not in pruned] self.mainLogger.debug("Removed " + str(pruned) + ", leaving " + str(self.titles)) del names, pruned, title, node
def seqInit(self, seqr, folder=None): """ Ran upon adding a sequence. Input is SeqRecord. Assigns a unique Window ID and adds to list of all Seqs. The Window ID is the core identifier for all sequence and alignment objects, and remains static for as long as the sequence or alignment exists. Creates a node in the BioModel/BioTree with the title linked to the Name Updating this node name only modifies the sName; the sequence ID from the FASTA remains unchanged. """ wid = str(int(self.windex) + 1) sname = seqr.name # Check if title already exists, and if so, changes it. sname, self.titles = utilities.checkName(sname, self.titles) if sname != seqr.name: seqr.name = sname # Adds to the list of sequences, by its Window ID self.sequences[wid] = [seqr] node = QStandardItem(sname) node.setData([seqr], self.SequenceRole) node.setData(node.data(role=self.SequenceRole)[0].name) node.setData(wid, self.WindowRole) node.setFlags(node.flags() ^ Qt.ItemIsDropEnabled) if not folder: self.bioModel.appendRow(node) else: found = False for n in utilities.iterTreeView(self.bioModel.invisibleRootItem()): if n.text() == folder: n.appendRow(node) found = True if not found: nfolder = QStandardItem(str(folder)) nfolder.appendRow(node) self.bioModel.appendRow(nfolder) self.bioTree.setExpanded(nfolder.index(), True) del nfolder, n, found self.windex = int(wid) del node, wid, seqr, folder
def guiSet(self, trees=None, data=None): """ Initialize GUI with default parameters. """ self.lastClickedTree = None self.lastAlignment = {} self.windows = {} # Windows stored as { windex : MDISubWindow } self.windex = 0 # Acts as identifier for tracking alignments (max 2.1 billion) self.sequences = {} # Stored as {WindowID:[SeqRecord(s)] } self.titles = [ ] # maintains a list of sequence titles to confirm uniqueness #self.mainLogger.debug("guiSet took took %f seconds" % float(time.perf_counter() - self.start)) # Load default options for windows (from parameters file if saved) # if PARAMETERS FILE: # params = FROMFILE # print(qApp.instance().defFont.family()) self.default_params = { 'ruler': True, 'colors': True, 'fontsize': 10, 'theme': 'Default', 'font': qApp.instance().defFont, 'byconsv': False, 'tabbed': False, 'darkmode': False, 'dssp': False, } self.params = self.default_params.copy() if sys.platform in ['darwin']: self.params['fontsize'] = 12 # print(self.params['font'].family()) self.optionsPane.setParams(self.params) # This is fired upon loading a saved workspace. if trees: self.mainLogger.info("Loading saved workspace!") self.bioModel, self.projectModel = trees self.sequences, self.titles, self.windex = data self.windex = int(self.windex) self.bioRoot = self.bioModel.invisibleRootItem().child( 0) # TODO: ELIMINATE USE OF ROOT. Use InvsRoot self.projectRoot = self.projectModel.invisibleRootItem().child(0) self.windows = {} self.rebuildTrees() else: self.bioRoot = QStandardItem("Folder") self.bioModel = widgets.ItemModel(self.windows, seqTree=True) self.bioRoot.setData("Folder") self.bioModel.appendRow(self.bioRoot) self.projectRoot = QStandardItem("Folder") self.projectModel = widgets.ItemModel(self.windows) self.projectModel.appendRow(self.projectRoot) self.mainLogger.debug("After Tree Setup") self.bioTree.setModel(self.bioModel) self.projectTree.setModel(self.projectModel) self.bioModel.setHorizontalHeaderLabels(["Sequences"]) self.projectModel.setHorizontalHeaderLabels(["Alignments"]) for node in utilities.iterTreeView(self.bioModel.invisibleRootItem()): self.bioTree.setExpanded(node.index(), True) for node in utilities.iterTreeView( self.projectModel.invisibleRootItem()): self.projectTree.setExpanded(node.index(), True) # self.installEventFilter(self) del trees, data, node