class ViewChemicalShiftsPopup(BasePopup): """ **A Table of Chemical Shifts for Export** This section is designed to make a layout of a table for chemical shifts on a per-residue basis which may them be exported as either PostScript, for printing and graphical manipulation, or as plain text for import into other software or computer scripts. The user chooses the molecular chain (which sequence) and the shift list to use at the top of the popup, together with a few other options that control how things are rendered. Then buttons are toggled to select which kinds of atom will be displayed in aligned columns; other kinds will simply be listed to the right of the columns. Thus for example if the shift list does not contain any carbonyl resonances in a protein chain then the user may toggle the empty "C" column off. Once the desired layout is achieved the user then uses the [Export PostScript] or [Export Text] buttons to write the data into a file of the appropriate type. The user will be presented wit ha file browser to specify the location and the name of the file to be saved. It should be noted that although the graphical display in the popup itself is somewhat limited, e.g. the gaps and spacing doesn't always look perfect, the PostScript version that is exported is significantly neater. **Caveats & Tips** If you need a chemical shift list represented in a particular format, specific for a particular external NMR program then you should use the FormatConverter software. Chemical shifts may also be exported from any table in Analysis that contains such data by clicking the right mouse button over the table and selecting the export option. """ def __init__(self, parent, *args, **kw): self.shiftList = None self.font = 'Helvetica 10' self.boldFont = 'Helvetica 10 bold' self.symbolFont = 'Symbol 8' self.smallFont = 'Helvetica 8' self.chain = None self.textOut = '' self.textMatrix = [] BasePopup.__init__(self, parent=parent, title='Chart : Chemical Shifts Table') def body(self, guiFrame): row = 0 frame = Frame(guiFrame, grid=(row, 0)) frame.expandGrid(None, 6) label = Label(frame, text='Chain:', grid=(0, 0)) tipText = 'Selects which molecular chain to show residues and chemical shift values for' self.chainPulldown = PulldownList(frame, callback=self.changeChain, grid=(0, 1), tipText=tipText) label = Label(frame, text=' Shift List:', grid=(0, 2)) tipText = 'Selects which shift list is used to derive the displayed chemical shift values' self.shiftListPulldown = PulldownList(frame, callback=self.changeShiftList, grid=(0, 3), tipText=tipText) label = Label(frame, text=' List all shifts:', grid=(0, 4)) tipText = 'Sets whether to display all the chemical shifts for residues or just for the nominated atom types in columns' self.otherShiftsSelect = CheckButton(frame, callback=self.draw, grid=(0, 5), tipText=tipText) utilButtons = UtilityButtonList(frame, helpUrl=self.help_url, grid=(0, 7)) row += 1 frame = Frame(guiFrame, grid=(row, 0)) frame.expandGrid(None, 6) label = Label(frame, text=' 1-letter codes:', grid=(0, 0)) tipText = 'Whether to use 1-letter residue codes in the table, or otherwise Ccp/three-letter codes' self.oneLetterSelect = CheckButton(frame, callback=self.draw, grid=(0, 1), selected=False, tipText=tipText) precisions = [0.1, 0.01, 0.001] texts = [str(t) for t in precisions] label = Label(frame, text=' 1H precision:', grid=(0, 2)) tipText = 'Specifies how many decimal places to use when displaying 1H chemical shift values' self.protonPrecisionSelect = PulldownList(frame, texts=texts, objects=precisions, callback=self.draw, index=1, grid=(0, 3), tipText=tipText) label = Label(frame, text=' Other precision:') label.grid(row=0, column=4, sticky='w') tipText = 'Specifies how many decimal places to use when displaying chemical shift values for isotopes other than 1H' self.otherPrecisionSelect = PulldownList(frame, texts=texts, objects=precisions, callback=self.draw, index=1, grid=(0, 5), tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0)) frame.expandGrid(None, 1) label = Label(frame, text='Column\nAtoms:', grid=(0, 0)) tipText = 'Selects which kinds of atoms are displayed in aligned columns, or otherwise displayed at the end of the residue row (if "List all shifts" is set)' self.optSelector = PartitionedSelector(frame, self.toggleOpt, tipText=tipText, maxRowObjects=10, grid=(0, 1), sticky='ew') options = ['H', 'N', 'C', 'CA', 'CB', 'CG'] self.optSelector.update(objects=options, labels=options, selected=['H', 'N', 'CA']) row += 1 guiFrame.expandGrid(row, 0) self.canvasFrame = ScrolledCanvas(guiFrame, relief='groove', width=650, borderwidth=2, resizeCallback=None, grid=(row, 0), padx=1, pady=1) self.canvas = self.canvasFrame.canvas #self.canvas.bind('<Button-1>', self.toggleResidue) row += 1 tipTexts = [ 'Output information from the table as PostScript file, for printing etc.', 'Output information from the table as a whitespace separated plain text file' ] commands = [self.makePostScript, self.exportText] texts = ['Export PostScript', 'Export Text'] buttonList = ButtonList(guiFrame, commands=commands, texts=texts, grid=(row, 0), tipTexts=tipTexts) chains = self.getChains() if len(chains) > 1: self.chain = chains[1] else: self.chain = None self.updateShiftLists() self.updateChains() self.otherShiftsSelect.set(True) self.update() for func in ('__init__', 'delete'): self.registerNotify(self.updateChains, 'ccp.molecule.MolSystem.Chain', func) for func in ('__init__', 'delete'): self.registerNotify(self.updateShiftLists, 'ccp.nmr.Nmr.ShiftList', func) def changeShiftList(self, shiftList): if shiftList is not self.shiftList: self.shiftList = shiftList self.update() def updateShiftLists(self, *opt): names = [] index = 0 shiftLists = getShiftLists(self.nmrProject) shiftList = self.shiftList if shiftLists: names = [ '%s [%d]' % (sl.name or '<No name>', sl.serial) for sl in shiftLists ] if shiftList not in shiftLists: shiftList = shiftLists[0] index = shiftLists.index(shiftList) if self.shiftList is not shiftList: self.shiftList = shiftList self.shiftListPulldown.setup(names, shiftLists, index) def getChains(self): chains = [ None, ] for molSystem in self.project.sortedMolSystems(): for chain in molSystem.sortedChains(): if len(chain.residues) > 1: chains.append(chain) return chains def changeChain(self, chain): if chain is not self.chain: self.chain = chain self.update() def updateChains(self, *opt): names = [] index = -1 chains = self.getChains() chain = self.chain if len(chains) > 1: names = [ 'None', ] + ['%s:%s' % (ch.molSystem.code, ch.code) for ch in chains[1:]] if chain not in chains: chain = chains[1] index = chains.index(chain) else: chain = None self.chainPulldown.setup(names, chains, index) def destroy(self): for func in ('__init__', 'delete'): self.unregisterNotify(self.updateChains, 'ccp.molecule.MolSystem.Chain', func) for func in ('__init__', 'delete'): self.unregisterNotify(self.updateShiftLists, 'ccp.nmr.Nmr.ShiftList', func) BasePopup.destroy(self) def exportText(self, *event): from memops.gui.FileSelect import FileType from memops.gui.FileSelectPopup import FileSelectPopup if self.textOut: fileTypes = [ FileType('Text', ['*.txt']), FileType('CSV', ['*.csv']), FileType('All', ['*']) ] fileSelectPopup = FileSelectPopup(self, file_types=fileTypes, title='Save table as text', dismiss_text='Cancel', selected_file_must_exist=False) fileName = fileSelectPopup.getFile() if fileName: file = open(fileName, 'w') if fileName.endswith('.csv'): for textRow in self.textMatrix: file.write(','.join(textRow) + '\n') else: file.write(self.textOut) def toggleOpt(self, selected): self.draw() def makePostScript(self): self.canvasFrame.printCanvas() def update(self): colors = [] selected = set() atomNames = set() if self.chain: for residue in self.chain.sortedResidues(): for atom in residue.atoms: chemAtom = atom.chemAtom if colorDict.get(chemAtom.elementSymbol) is None: continue if chemAtom.waterExchangeable: continue atomNames.add(atom.name[:2]) molType = residue.molResidue.molType if molType == 'protein': selected.add('H') selected.add('N') selected.add('CA') selected.add('C') elif molType == 'DNA': selected.add("C1'") elif molType == 'RNA': selected.add("C1'") elif molType == 'carbohydrate': selected.add("C1") else: for spinSystem in self.shiftList.nmrProject.resonanceGroups: if not spinSystem.residue: for resonance in spinSystem.resonances: for name in resonance.assignNames: atomNames.add(name) options = list(atomNames) molType = 'protein' if self.chain: molType = self.chain.molecule.molType options = greekSortAtomNames(options, molType=molType) if 'H' in options: options.remove('H') options = [ 'H', ] + options colors = [colorDict.get(n[0]) for n in options] if options and not selected: selected = [ options[0], ] self.optSelector.update(objects=options, labels=options, colors=colors, selected=list(selected)) self.draw() def draw(self, *opt): if not self.shiftList: return nmrProject = self.shiftList.nmrProject shiftList = self.shiftList font = self.font bfont = self.boldFont symbolFont = self.symbolFont sFont = self.smallFont bbox = self.canvas.bbox doOthers = self.otherShiftsSelect.get() spc = 4 gap = 14 x = gap y = gap ct = self.canvas.create_text cl = self.canvas.create_line cc = self.canvas.coords self.canvas.delete('all') ssDict = {} formatDict = { 0.1: '%.1f', 0.01: '%.2f', 0.001: '%.3f', } protonFormat = formatDict[self.protonPrecisionSelect.getObject()] otherFormat = formatDict[self.otherPrecisionSelect.getObject()] uSpinSystems = [] chains = set() molSystems = set() for spinSystem in nmrProject.resonanceGroups: residue = spinSystem.residue if residue: ssDict[residue] = ssDict.get(residue, []) + [ spinSystem, ] else: uSpinSystems.append((spinSystem.serial, spinSystem)) uSpinSystems.sort() commonAtoms = self.optSelector.getSelected() N = len(commonAtoms) chain = self.chain if chain: spinSystems = [] for residue in chain.sortedResidues(): spinSystems0 = ssDict.get(residue, []) for spinSystem in spinSystems0: if spinSystem and spinSystem.resonances: spinSystems.append([residue, spinSystem]) else: spinSystems = uSpinSystems strings = [] doOneLetter = self.oneLetterSelect.get() if spinSystems: x = gap y += gap numItems = [] codeItems = [] commonItems = [] otherItems = [] numWidth = 0 codeWidth = 0 commonWidths = [0] * N commonCounts = [0] * N for residue, spinSystem in spinSystems: if type(residue) is type(1): seqNum = '{%d}' % residue if doOneLetter: ccpCode = '-' else: ccpCode = spinSystem.ccpCode or '' else: if doOneLetter: ccpCode = residue.chemCompVar.chemComp.code1Letter else: ccpCode = getResidueCode(residue) seqNum = str(residue.seqCode) subStrings = [] subStrings.append(seqNum) subStrings.append(ccpCode) item = ct(x, y, text=seqNum, font=font, anchor='se') box = bbox(item) iWidth = box[2] - box[0] numWidth = max(numWidth, iWidth) numItems.append(item) item = ct(x, y, text=ccpCode, font=font, anchor='sw') box = bbox(item) iWidth = box[2] - box[0] codeWidth = max(codeWidth, iWidth) codeItems.append(item) commonShifts, commonElements, otherShifts = self.getShiftData( spinSystem, shiftList, commonAtoms) items = [] for i in range(N): values = commonShifts[i] element = commonElements[i] if element == 'H': shiftFormat = protonFormat else: shiftFormat = otherFormat subItems = [] for value in values: text = shiftFormat % value if text: item = ct(x, y, text=text, font=font, anchor='se') box = bbox(item) iWidth = box[2] - box[0] commonWidths[i] = max(commonWidths[i], iWidth) commonCounts[i] += 1 subItems.append(item) subStrings.append( ','.join([shiftFormat % v for v in values]) or '-') items.append(subItems) commonItems.append(items) if doOthers: items0 = [] i = 0 I = len(otherShifts) for atomLabel, element, value in otherShifts: label = atomLabel if label[0] == '?': label = label[3:-1] if element == 'H': shiftFormat = protonFormat else: shiftFormat = otherFormat subStrings.append('%6s:%-4s' % (shiftFormat % value, label)) i += 1 atoms = atomLabel.split('|') items = [] j = 0 for atom in atoms: text = element if j > 0: text = '/' + text item = ct(x, y, text=text, font=font, anchor='sw') box = bbox(item) iWidth = box[2] - box[0] - 3 items.append((iWidth, item, 0)) p = len(element) if len(atom) > p: letter = atom[p] if letter not in ('0123456789'): item = ct(x, y, text=letter.lower(), font=symbolFont, anchor='sw') box = bbox(item) iWidth = box[2] - box[0] - 2 items.append((iWidth, item, -4)) p += 1 text = atom[p:] if text: item = ct(x, y, text=text, font=sFont, anchor='sw') box = bbox(item) iWidth = box[2] - box[0] - 2 items.append((iWidth, item, -4)) j += 1 text = ' ' + shiftFormat % value if i != I: text += ',' item = ct(x, y, text=text, font=font, anchor='sw') box = bbox(item) iWidth = box[2] - box[0] - 4 items.append((iWidth, item, 0)) items0.append(items) otherItems.append(items0) strings.append(subStrings) y0 = y x = x0 = gap + numWidth + codeWidth + spc + spc for i in range(N): if not commonCounts[i]: continue x += commonWidths[i] + spc + spc element = commonElements[i] iWidth = 0 text = commonAtoms[i][len(element):].lower() if text: item = ct(x, y, text=text, font=symbolFont, anchor='se') box = bbox(item) iWidth = box[2] - box[0] - 2 ct(x - iWidth, y, text=element, font=font, anchor='se') y += gap for i in range(len(numItems)): x = gap + numWidth + spc cc(numItems[i], x, y) x += spc cc(codeItems[i], x, y) x += codeWidth x1 = x + spc yM = y for j in range(N): if not commonCounts[j]: continue x += commonWidths[j] + spc + spc items = commonItems[i][j] yB = y - gap for item in items: yB += gap cc(item, x, yB) yM = max(yB, yM) x += gap if doOthers: x += spc x3 = x for items in otherItems[i]: if x > 550: x = x3 y += gap for iWidth, item, dy in items: cc(item, x, y + dy) x += iWidth y = max(y, yM) y += gap x = x0 for i in range(N): if not commonCounts[i]: continue x += commonWidths[i] + spc + spc cl(x + 8, y0, x + 8, y - gap, width=0.3, fill='#808080') cl(x1, y0, x1, y - gap, width=0.3, fill='#808080') cl(0, 0, 550, 0, width=0.3, fill='#FFFFFF') y += gap textWidths = {} for subStrings in strings: for i, text in enumerate(subStrings): if text and len(text) > textWidths.get(i, 0): textWidths[i] = len(text) else: textWidths[i] = 0 formats = {} for i in textWidths.keys(): formats[i] = ' %%%ds' % max(6, textWidths[i]) textOut = '!' textRow = ['', ''] textMatrix = [textRow] textOut += ' ' * (max(6, textWidths.get(0, 6)) + max(6, textWidths.get(1, 6)) + 1) i = 2 for atom in commonAtoms: if i in formats: textOut += formats[i] % atom textRow.append((formats[i] % atom).strip()) i += 1 textOut += '\n' for subStrings in strings: textRow = [] textMatrix.append(textRow) i = 0 for text in subStrings: textOut += formats[i] % text textRow.append((formats[i] % text).strip()) i += 1 textOut += '\n' self.textOut = textOut self.textMatrix = textMatrix def getShiftData(self, spinSystem, shiftList, commonAtoms=('H', 'N', 'CA', 'CB')): commonShifts = [] commonResonances = {} commonElements = [] for atomName in commonAtoms: elements = set() resonances = [] for resonance in spinSystem.resonances: resonanceSet = resonance.resonanceSet if resonanceSet: for atomSet in resonanceSet.atomSets: for atom in atomSet.atoms: if atomName == atom.name[:2]: resonances.append(resonance) break else: continue break else: for assignName in resonance.assignNames: if atomName == assignName[:2]: resonances.append(resonance) break shiftValues = [] for resonance in resonances: isotope = resonance.isotope if isotope: elements.add(isotope.chemElement.symbol) commonResonances[resonance] = True shift = resonance.findFirstShift(parentList=shiftList) if shift: shiftValues.append(shift.value) if not elements: element = atomName[0] else: element = elements.pop() commonElements.append(element) commonShifts.append(shiftValues) otherShifts = [] for resonance in spinSystem.resonances: if not commonResonances.get(resonance): shift = resonance.findFirstShift(parentList=shiftList) if shift: isotope = resonance.isotope if isotope: element = isotope.chemElement.symbol else: element = '??' if resonance.assignNames or resonance.resonanceSet: name = getResonanceName(resonance) else: name = '??[%d]' % resonance.serial otherShifts.append((name, element, shift.value)) molType = 'protein' if spinSystem.residue: molType = spinSystem.residue.molResidue.molType otherShifts = greekSortAtomNames(otherShifts, molType) return commonShifts, commonElements, otherShifts
class ConfirmSeqSpinSystemsPopup(BasePopup): def __init__(self, parent, *args, **kw): self.guiParent = parent self.spinSystems = [] self.spectrum = None self.spectra = [] self.waiting = 0 self.shiftList = None self.spinSystem = None self.link = '-1' BasePopup.__init__(self, parent=parent, title="Confirm Sequential Spin System", **kw) def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) row = 0 frame = Frame(guiFrame) frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(3, weight=1) label = Label(frame, text='Shift List:') label.grid(row=0, column=0, sticky='w') self.shiftListPulldown = PulldownMenu(frame, callback=self.setShiftList) self.shiftListPulldown.grid(row=0, column=1, sticky='w') label = Label(frame, text='Sequential Link Type:') label.grid(row=0, column=2, sticky='w') entries = ['-1', '-1,+1', '+1'] self.linkPulldown = PulldownMenu(frame, callback=self.setLink, entries=entries, do_initial_callback=False, selected_index=entries.index( self.link)) self.linkPulldown.grid(row=0, column=3, sticky='w') row += 1 frame = LabelFrame(guiFrame, text='Link Atoms:') frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) labels = ['C', 'CA', 'CB', 'CG', 'CD', 'H', 'HA', 'HB', 'HG', 'HD'] selected = ['CA', 'CB'] self.atomSelector = PartitionedSelector(frame, objects=labels, labels=labels, selected=selected, toggledBg='#808080', callback=self.changeAtoms, maxRowObjects=10) self.atomSelector.grid(row=0, column=0, sticky='ew') row += 1 guiFrame.grid_rowconfigure(row, weight=1) frame = LabelFrame(guiFrame, text='Predicted Residue Assignments') frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) headingList = [ '#', 'Predicted\nResidue', 'Prob.', 'Links', 'CA', 'CA -1', 'CB', 'CB -1' ] self.spinSystemMatrix = ScrolledMatrix(frame, headingList=headingList, callback=self.selectSpinSystem, multiSelect=1) self.spinSystemMatrix.grid(row=0, column=0, sticky='nsew') row += 1 texts = ['Link Selected', 'Link All', 'Commit Assignment'] commands = [ self.linkSelectedSpinSystems, self.linkAllSpinSystems, self.commitAssignments ] buttonList = UtilityButtonList(guiFrame, texts=texts, commands=commands, helpUrl=self.help_url) buttonList.grid(row=row, column=0, sticky='ew') self.buttons = buttonList.buttons for func in ('__init__', 'delete'): for clazz in ('ccp.nmr.Nmr.ShiftList', ): self.registerNotify(self.updateShiftLists, clazz, func) for func in ('__init__', 'delete', 'setNmrChains', 'setResidue', 'setResonances', 'addResonance', 'removeResonance'): self.registerNotify(self.updateSpinSystemsAfter, 'ccp.nmr.Nmr.ResonanceGroup', func) self.updateShiftLists() def setLink(self, index, name): self.link = name self.updateSpinSystemsAfter() def updateButtons(self): if len(self.spinSystemMatrix.currentObjects) > 1: self.buttons[0].enable() else: self.buttons[0].disable() if self.spinSystemMatrix.objectList: self.buttons[1].enable() else: self.buttons[1].disable() if self.spinSystem: self.buttons[2].enable() else: self.buttons[2].disable() def changeAtoms(self, *opt): self.updateSpinSystemsAfter() def getShiftListNames(self, shiftLists): shiftListNames = [] for shiftList in shiftLists: if not hasattr(shiftList, 'name'): shiftList.name = "ShiftList " + str(shiftList.serial) elif not shiftList.name: shiftList.name = "ShiftList " + str(shiftList.serial) shiftListNames.append(shiftList.name) return shiftListNames def updateShiftLists(self, *opt): shiftLists = list( self.nmrProject.findAllMeasurementLists(className='ShiftList')) shiftListNames = self.getShiftListNames(shiftLists) shiftList = None index = -1 if shiftListNames: if self.shiftList in shiftLists: shiftList = self.shiftList else: shiftList = shiftLists[0] index = shiftLists.index(shiftList) self.shiftList = shiftList self.shiftListPulldown.setup(shiftListNames, index) def setShiftList(self, index, name=None): shiftLists = list( self.nmrProject.findAllMeasurementLists(className='ShiftList')) if shiftLists: self.shiftList = shiftLists[index] else: self.shiftList = None self.updateSpinSystemsAfter() def linkSelectedSpinSystems(self): spinSystems = self.spinSystemMatrix.currentObjects self.linkSpinSystems(spinSystems) def linkAllSpinSystems(self): spinSystems = self.spinSystemMatrix.objectList self.linkSpinSystems(spinSystems) def linkSpinSystems(self, spinSystems): data = [] for spinSystem in spinSystems: residue, p = self.getProbableResidue(spinSystem) key = '%s%s%4.4d' % (residue.chain.molSystem.code, residue.chain.code, residue.seqCode) data.append([key, residue.seqCode, residue, spinSystem]) data.sort() seqCodes = [x[1] for x in data] residues = [x[2] for x in data] spinSystems = [x[3] for x in data] N = len(data) for i in range(N): if i > 0: delta = seqCodes[i] - seqCodes[i - 1] if delta == 1 and (residues[i].chain is residues[i - 1].chain): ss = findConnectedSpinSystem(spinSystems[i], delta=-1) if ss: mergeSpinSystems( ss, spinSystems[i - 1]) # copy resonances across & delete makeSeqSpinSystemLink(spinSystems[i - 1], spinSystems[i], delta=1) if i < N - 1: delta = seqCodes[i + 1] - seqCodes[i] if delta == 1 and (residues[i].chain is residues[i + 1].chain): ss = findConnectedSpinSystem(spinSystems[i], delta=1) if ss: mergeSpinSystems( ss, spinSystems[i + 1]) # copy resonances across & delete makeSeqSpinSystemLink(spinSystems[i], spinSystems[i + 1], delta=1) self.updateSpinSystemsAfter() def commitAssignments(self): merge = showYesNo('Query', 'Merge with any existing spin systems?', self) for spinSystem in self.spinSystemMatrix.currentObjects: if not spinSystem.residue: residue, p = self.getProbableResidue(spinSystem) assignSpinSystemResidue(spinSystem, residue, warnMerge=merge) def getProbableResidue(self, spinSystem): residue = None probability = 0.0 if spinSystem.residue: return spinSystem.residue, 1.0 data = [] for residueProb in spinSystem.residueProbs: data.append((residueProb.weight, residueProb.possibility)) data.sort() if data: residue, probability = data[-1] return residue, probability def getTentativeSpinSystems(self): spinSystemsList = [] if self.project: for spinSystem in self.nmrProject.sortedResonanceGroups(): if spinSystem.residueProbs and not spinSystem.residue: #if spinSystem.residue: residue, p = self.getProbableResidue(spinSystem) key = '%s%s%4.4d' % (residue.chain.molSystem.code, residue.chain.code, residue.seqCode) spinSystemsList.append((key, spinSystem)) spinSystemsList.sort() return [x[1] for x in spinSystemsList] def updateSpinSystemsAfter(self, spinSystem=None): if self.waiting: return else: if spinSystem: if not spinSystem.residueProbs: return if spinSystem.residue: return self.waiting = True self.after_idle(self.updateSpinSystems) def getHeadings(self): headingList = ['#', 'Predicted\nResidue', 'Prob.', 'Links'] atoms = self.atomSelector.getSelected() for atom in atoms: headingList.append(atom) if self.link == '-1': headingList.append('%s -1' % atom) headingList.append('D %s -1' % atom) elif self.link == '+1': headingList.append('%s +1' % atom) headingList.append('D %s +1' % atom) else: headingList.append('%s -1' % atom) headingList.append('D %s -1' % atom) headingList.append('%s +1' % atom) headingList.append('D %s +1' % atom) return headingList def addShiftData(self, spinSystem, datum): prevSS, nextSS = self.getConnectedSpinSystems(spinSystem) atoms = self.atomSelector.getSelected() dict = {} residue, p = self.getProbableResidue(spinSystem) prevRes = residue.chain.findFirstResidue(seqCode=residue.seqCode - 1) nextRes = residue.chain.findFirstResidue(seqCode=residue.seqCode + 1) prevSS0 = None nextSS0 = None for ss in self.getTentativeSpinSystems(): if self.getProbableResidue(ss)[0] is prevRes: prevSS0 = ss if self.getProbableResidue(ss)[0] is nextRes: nextSS0 = ss if nextSS0 and prevSS0: break for atom in atoms: resonances = [] resonancesPrev = [] resonancesNext = [] resonancesPrev0 = [] resonancesNext0 = [] for resonance0 in spinSystem.sortedResonances(): for name in resonance0.assignNames: if name[:2] == atom: resonances.append(resonance0) break text = '' if resonances: text = self.getResonanceText(resonances) datum.append(text) if prevSS and ('-1' in self.link): for resonance0 in prevSS.sortedResonances(): for name in resonance0.assignNames: if name[:2] == atom: resonancesPrev.append(resonance0) break deltasPrev = [] if prevSS0 and resonancesPrev: for resonance1 in prevSS0.sortedResonances(): for name1 in resonance1.assignNames: if name1[:2] == atom: shift1 = resonance1.findFirstShift( parentList=self.shiftList) deltas = [] for resonance2 in resonancesPrev: shift2 = resonance2.findFirstShift( parentList=self.shiftList) if shift1 and shift2: deltas.append( abs(shift1.value - shift2.value)) if deltas: deltas.sort() deltasPrev.append('%.2f' % deltas[0]) break if nextSS and ('+1' in self.link): for resonance0 in nextSS.sortedResonances(): for name in resonance0.assignNames: if name[:2] == atom: resonancesNext.append(resonance0) break deltasNext = [] if nextSS0 and resonancesNext: for resonance1 in nextSS0.sortedResonances(): for name1 in resonance1.assignNames: if name1[:2] == atom: shift1 = resonance1.findFirstShift( parentList=self.shiftList) deltas = [] for resonance2 in resonancesNext: shift2 = resonance2.findFirstShift( parentList=self.shiftList) if shift1 and shift2: deltas.append( abs(shift1.value - shift2.value)) if deltas: deltas.sort() deltasNext.append('%.2f' % deltas[0]) break if self.link == '-1': ppms = '' diff = '' if resonancesPrev: ppms = self.getResonanceText(resonancesPrev) diff = ','.join(deltasPrev) datum.append(ppms) datum.append(diff) elif self.link == '+1': ppms = '' diff = '' if resonancesNext: ppms = self.getResonanceText(resonancesNext) diff = ','.join(deltasNext) datum.append(ppms) datum.append(diff) else: ppms = '' diff = '' if resonancesPrev: ppms = self.getResonanceText(resonancesPrev) diff = ','.join(deltasPrev) datum.append(ppms) datum.append(diff) ppms = '' diff = '' if resonancesNext: ppms = self.getResonanceText(resonancesNext) diff = ','.join(deltasNext) datum.append(ppms) datum.append(diff) def updateSpinSystems(self): textMatrix = [] objectList = [] colorMatrix = [] headingList = self.getHeadings() for spinSystem in self.getTentativeSpinSystems(): residueText = None residue, probability = self.getProbableResidue(spinSystem) if residue: residueText = '%d%s' % (residue.seqCode, getResidueCode(residue)) links = [] color = '#D04040' if findConnectedSpinSystem(spinSystem, delta=-1): links.append('-1') if findConnectedSpinSystem(spinSystem, delta=1): links.append('+1') if len(links) == 2: color = '#40B040' elif len(links) == 1: color = '#B0B040' datum = [] datum.append(spinSystem.serial) datum.append(residueText) datum.append(probability) datum.append(' '.join(links)) self.addShiftData(spinSystem, datum) colors = [None] * len(headingList) colors[3] = color objectList.append(spinSystem) textMatrix.append(datum) colorMatrix.append(colors) if self.spinSystem not in objectList: self.spinSystem = None self.spinSystemMatrix.update(headingList=headingList, objectList=objectList, textMatrix=textMatrix, colorMatrix=colorMatrix) self.updateButtons() self.waiting = False def getResonanceText(self, resonances): shifts = [] for resonance in resonances: shift = resonance.findFirstShift(parentList=self.shiftList) if shift: shifts.append('%.2f' % shift.value) return ','.join(shifts) def getConnectedSpinSystems(self, spinSystem): if self.link == '-1': prevSS = findConnectedSpinSystem(spinSystem, delta=-1) nextSS = None elif self.link == '+1': prevSS = None nextSS = findConnectedSpinSystem(spinSystem, delta=1) else: prevSS = findConnectedSpinSystem(spinSystem, delta=-1) nextSS = findConnectedSpinSystem(spinSystem, delta=1) return prevSS, nextSS def selectSpinSystem(self, object, row, col): self.spinSystem = object self.updateButtons() def destroy(self): for func in ('__init__', 'delete'): for clazz in ('ccp.nmr.Nmr.ShiftList', ): self.unregisterNotify(self.updateShiftLists, clazz, func) for func in ('__init__', 'delete', 'setNmrChains', 'setResidue', 'setResonances', 'addResonance', 'removeResonance'): self.unregisterNotify(self.updateSpinSystemsAfter, 'ccp.nmr.Nmr.ResonanceGroup', func) BasePopup.destroy(self)