def body(self, mainFrame): mainFrame.grid_columnconfigure(1, weight=1, minsize=100) mainFrame.config(borderwidth=5, relief='solid') row = 0 label = Label(mainFrame, text="Frame (with sub-widgets):") label.grid(row=row, column=0, sticky=Tkinter.E) frame = Frame(mainFrame, relief='raised', border=2, background='#8080D0') # Frame expands East-West frame.grid(row=row, column=1, sticky=Tkinter.EW) # Last column expands => Widgets pusted to the West frame.grid_columnconfigure(3, weight=1) # Label is within the sub frame label = Label(frame, text='label ') label.grid(row=0, column=0, sticky=Tkinter.W) entry = Entry(frame, text='Entry', returnCallback=self.showWarning) entry.grid(row=0, column=1, sticky=Tkinter.W) self.check = CheckButton(frame, text='Checkbutton', selected=True, callback=self.updateObjects) self.check.grid(row=0, column=2, sticky=Tkinter.W) # stick a button to the East wall button = Button(frame, text='Button', command=self.pressButton) button.grid(row=0, column=3, sticky=Tkinter.E) row += 1 label = Label(mainFrame, text="Text:") label.grid(row=row, column=0, sticky=Tkinter.E) self.textWindow = Text(mainFrame, text='Initial Text\n', width=60, height=5) self.textWindow.grid(row=row, column=1, sticky=Tkinter.NSEW) row += 1 label = Label(mainFrame, text="CheckButtons:") label.grid(row=row, column=0, sticky=Tkinter.E) entries = ['Alpha','Beta','Gamma','Delta'] selected = entries[2:] self.checkButtons = CheckButtons(mainFrame, entries, selected=selected,select_callback=self.changedCheckButtons) self.checkButtons.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="PartitionedSelector:") label.grid(row=row, column=0, sticky=Tkinter.E) labels = ['Bool','Int','Float','String'] objects = [type(0),type(1),type(1.0),type('a')] selected = [type('a')] self.partitionedSelector= PartitionedSelector(mainFrame, labels=labels, objects=objects, colors = ['red','yellow','green','#000080'], callback=self.toggleSelector,selected=selected) self.partitionedSelector.grid(row=row, column=1, sticky=Tkinter.EW) row += 1 label = Label(mainFrame, text="PulldownMenu") label.grid(row=row, column=0, sticky=Tkinter.E) entries = ['Frodo','Pipin','Merry','Sam','Bill','Gandalf','Strider','Gimli','Legolas'] self.pulldownMenu = PulldownMenu(mainFrame, callback=self.selectPulldown, entries=entries, selected_index=2, do_initial_callback=False) self.pulldownMenu.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="RadioButtons in a\nScrolledFrame.frame:") label.grid(row=row, column=0, sticky=Tkinter.EW) frame = ScrolledFrame(mainFrame, yscroll = False, doExtraConfig = True, width=100) frame.grid(row=row, column=1, sticky=Tkinter.EW) frame.grid_columnconfigure(0, weight=1) self.radioButtons = RadioButtons(frame.frame, entries=entries, select_callback=self.checkRadioButtons, selected_index=1, relief='groove') self.radioButtons.grid(row=0, column=0, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="LabelFrame with\nToggleLabels inside:") label.grid(row=row, column=0, sticky=Tkinter.E) labelFrame = LabelFrame(mainFrame, text='Frame Title') labelFrame.grid(row=row, column=1, sticky=Tkinter.NSEW) labelFrame.grid_rowconfigure(0, weight=1) labelFrame.grid_columnconfigure(3, weight=1) self.toggleLabel1 = ToggleLabel(labelFrame, text='ScrolledMatrix', callback=self.toggleFrame1) self.toggleLabel1.grid(row=0, column=0, sticky=Tkinter.W) self.toggleLabel1.arrowOn() self.toggleLabel2 = ToggleLabel(labelFrame, text='ScrolledGraph', callback=self.toggleFrame2) self.toggleLabel2.grid(row=0, column=1, sticky=Tkinter.W) self.toggleLabel3 = ToggleLabel(labelFrame, text='ScrolledCanvas', callback=self.toggleFrame3) self.toggleLabel3.grid(row=0, column=2, sticky=Tkinter.W) row += 1 mainFrame.grid_rowconfigure(row, weight=1) label = Label(mainFrame, text="changing/shrinking frames:") label.grid(row=row, column=0, sticky=Tkinter.E) self.toggleRow = row self.toggleFrame = Frame(mainFrame) self.toggleFrame.grid(row=row, column=1, sticky=Tkinter.NSEW) self.toggleFrame.grid_rowconfigure(0, weight=1) self.toggleFrame.grid_columnconfigure(0, weight=1) # option 1 self.intEntry = IntEntry(self, returnCallback = self.setNumber, width=8) self.multiWidget = MultiWidget(self, Entry, options=None, values=None, callback=self.setKeywords, minRows=3, maxRows=5) editWidgets = [None, None, self.intEntry, self.multiWidget] editGetCallbacks = [None, None, self.getNumber, self.getKeywords] editSetCallbacks = [None, None, self.setNumber, self.setKeywords] headingList = ['Name','Color','Number','Keywords'] self.scrolledMatrix = ScrolledMatrix(self.toggleFrame, headingList=headingList, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, editWidgets=editWidgets, callback=self.selectObject, multiSelect=False) self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW) # option 2 self.scrolledGraph = ScrolledGraph(self.toggleFrame, width=400, height=300, symbolSize=5, symbols=['square','circle'], dataColors=['#000080','#800000'], lineWidths=[0,1] ) self.scrolledGraph.setZoom(1.3) dataSet1 = [[0,0],[1,1],[2,4],[3,9],[4,16],[5,25]] dataSet2 = [[0,0],[1,3],[2,6],[3,9],[4,12],[5,15]] self.scrolledGraph.update(dataSets=[dataSet1,dataSet2], xLabel = 'X axis label', yLabel = 'Y axis label', title = 'Main Title') self.scrolledGraph.draw() # option 3 self.scrolledCanvas = ScrolledCanvas(self.toggleFrame,relief = 'groove', borderwidth = 2, resizeCallback=None) canvas = self.scrolledCanvas.canvas font = 'Helvetica 10' box = canvas.create_rectangle(10,10,150,200, outline='grey', fill='grey90') line = canvas.create_line(0,0,200,200,fill='#800000', width=2) text = canvas.create_text(120,50, text='Text', font=font, fill='black') circle = canvas.create_oval(30,30,50,50,outline='#008000',fill='#404040',width=3) row += 1 label = Label(mainFrame, text="FloatEntry:") label.grid(row=row, column=0, sticky=Tkinter.E) self.floatEntry = FloatEntry(mainFrame, text=3.14159265, returnCallback=self.floatEntryReturn) self.floatEntry.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="Scale:") label.grid(row=row, column=0, sticky=Tkinter.E) self.scale = Scale(mainFrame, from_=10, to=90, value=50, orient=Tkinter.HORIZONTAL) self.scale.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="Value Ramp:") label.grid(row=row, column=0, sticky=Tkinter.E) self.valueRamp = ValueRamp(mainFrame, self.valueRampCallback, speed = 1.5, delay = 50) self.valueRamp.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="ButtonList:") label.grid(row=row, column=0, sticky=Tkinter.E) texts = ['Select File','Close','Quit'] commands = [self.selectFile, self.close, self.quit] bottomButtons = ButtonList(mainFrame, texts=texts, commands=commands, expands=True) bottomButtons.grid(row=row, column=1, sticky=Tkinter.EW) self.protocol('WM_DELETE_WINDOW', self.quit)
class PopupTemplate(BasePopup): def __init__(self, parent, project=None, *args, **kw): self.project = project self.parent = parent self.objects = self.getObjects() self.object = None BasePopup.__init__(self, parent=parent, title='Popup Template', **kw) self.updateObjects() def body(self, mainFrame): mainFrame.grid_columnconfigure(1, weight=1, minsize=100) mainFrame.config(borderwidth=5, relief='solid') row = 0 label = Label(mainFrame, text="Frame (with sub-widgets):") label.grid(row=row, column=0, sticky=Tkinter.E) frame = Frame(mainFrame, relief='raised', border=2, background='#8080D0') # Frame expands East-West frame.grid(row=row, column=1, sticky=Tkinter.EW) # Last column expands => Widgets pusted to the West frame.grid_columnconfigure(3, weight=1) # Label is within the sub frame label = Label(frame, text='label ') label.grid(row=0, column=0, sticky=Tkinter.W) entry = Entry(frame, text='Entry', returnCallback=self.showWarning) entry.grid(row=0, column=1, sticky=Tkinter.W) self.check = CheckButton(frame, text='Checkbutton', selected=True, callback=self.updateObjects) self.check.grid(row=0, column=2, sticky=Tkinter.W) # stick a button to the East wall button = Button(frame, text='Button', command=self.pressButton) button.grid(row=0, column=3, sticky=Tkinter.E) row += 1 label = Label(mainFrame, text="Text:") label.grid(row=row, column=0, sticky=Tkinter.E) self.textWindow = Text(mainFrame, text='Initial Text\n', width=60, height=5) self.textWindow.grid(row=row, column=1, sticky=Tkinter.NSEW) row += 1 label = Label(mainFrame, text="CheckButtons:") label.grid(row=row, column=0, sticky=Tkinter.E) entries = ['Alpha','Beta','Gamma','Delta'] selected = entries[2:] self.checkButtons = CheckButtons(mainFrame, entries, selected=selected,select_callback=self.changedCheckButtons) self.checkButtons.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="PartitionedSelector:") label.grid(row=row, column=0, sticky=Tkinter.E) labels = ['Bool','Int','Float','String'] objects = [type(0),type(1),type(1.0),type('a')] selected = [type('a')] self.partitionedSelector= PartitionedSelector(mainFrame, labels=labels, objects=objects, colors = ['red','yellow','green','#000080'], callback=self.toggleSelector,selected=selected) self.partitionedSelector.grid(row=row, column=1, sticky=Tkinter.EW) row += 1 label = Label(mainFrame, text="PulldownMenu") label.grid(row=row, column=0, sticky=Tkinter.E) entries = ['Frodo','Pipin','Merry','Sam','Bill','Gandalf','Strider','Gimli','Legolas'] self.pulldownMenu = PulldownMenu(mainFrame, callback=self.selectPulldown, entries=entries, selected_index=2, do_initial_callback=False) self.pulldownMenu.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="RadioButtons in a\nScrolledFrame.frame:") label.grid(row=row, column=0, sticky=Tkinter.EW) frame = ScrolledFrame(mainFrame, yscroll = False, doExtraConfig = True, width=100) frame.grid(row=row, column=1, sticky=Tkinter.EW) frame.grid_columnconfigure(0, weight=1) self.radioButtons = RadioButtons(frame.frame, entries=entries, select_callback=self.checkRadioButtons, selected_index=1, relief='groove') self.radioButtons.grid(row=0, column=0, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="LabelFrame with\nToggleLabels inside:") label.grid(row=row, column=0, sticky=Tkinter.E) labelFrame = LabelFrame(mainFrame, text='Frame Title') labelFrame.grid(row=row, column=1, sticky=Tkinter.NSEW) labelFrame.grid_rowconfigure(0, weight=1) labelFrame.grid_columnconfigure(3, weight=1) self.toggleLabel1 = ToggleLabel(labelFrame, text='ScrolledMatrix', callback=self.toggleFrame1) self.toggleLabel1.grid(row=0, column=0, sticky=Tkinter.W) self.toggleLabel1.arrowOn() self.toggleLabel2 = ToggleLabel(labelFrame, text='ScrolledGraph', callback=self.toggleFrame2) self.toggleLabel2.grid(row=0, column=1, sticky=Tkinter.W) self.toggleLabel3 = ToggleLabel(labelFrame, text='ScrolledCanvas', callback=self.toggleFrame3) self.toggleLabel3.grid(row=0, column=2, sticky=Tkinter.W) row += 1 mainFrame.grid_rowconfigure(row, weight=1) label = Label(mainFrame, text="changing/shrinking frames:") label.grid(row=row, column=0, sticky=Tkinter.E) self.toggleRow = row self.toggleFrame = Frame(mainFrame) self.toggleFrame.grid(row=row, column=1, sticky=Tkinter.NSEW) self.toggleFrame.grid_rowconfigure(0, weight=1) self.toggleFrame.grid_columnconfigure(0, weight=1) # option 1 self.intEntry = IntEntry(self, returnCallback = self.setNumber, width=8) self.multiWidget = MultiWidget(self, Entry, options=None, values=None, callback=self.setKeywords, minRows=3, maxRows=5) editWidgets = [None, None, self.intEntry, self.multiWidget] editGetCallbacks = [None, None, self.getNumber, self.getKeywords] editSetCallbacks = [None, None, self.setNumber, self.setKeywords] headingList = ['Name','Color','Number','Keywords'] self.scrolledMatrix = ScrolledMatrix(self.toggleFrame, headingList=headingList, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, editWidgets=editWidgets, callback=self.selectObject, multiSelect=False) self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW) # option 2 self.scrolledGraph = ScrolledGraph(self.toggleFrame, width=400, height=300, symbolSize=5, symbols=['square','circle'], dataColors=['#000080','#800000'], lineWidths=[0,1] ) self.scrolledGraph.setZoom(1.3) dataSet1 = [[0,0],[1,1],[2,4],[3,9],[4,16],[5,25]] dataSet2 = [[0,0],[1,3],[2,6],[3,9],[4,12],[5,15]] self.scrolledGraph.update(dataSets=[dataSet1,dataSet2], xLabel = 'X axis label', yLabel = 'Y axis label', title = 'Main Title') self.scrolledGraph.draw() # option 3 self.scrolledCanvas = ScrolledCanvas(self.toggleFrame,relief = 'groove', borderwidth = 2, resizeCallback=None) canvas = self.scrolledCanvas.canvas font = 'Helvetica 10' box = canvas.create_rectangle(10,10,150,200, outline='grey', fill='grey90') line = canvas.create_line(0,0,200,200,fill='#800000', width=2) text = canvas.create_text(120,50, text='Text', font=font, fill='black') circle = canvas.create_oval(30,30,50,50,outline='#008000',fill='#404040',width=3) row += 1 label = Label(mainFrame, text="FloatEntry:") label.grid(row=row, column=0, sticky=Tkinter.E) self.floatEntry = FloatEntry(mainFrame, text=3.14159265, returnCallback=self.floatEntryReturn) self.floatEntry.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="Scale:") label.grid(row=row, column=0, sticky=Tkinter.E) self.scale = Scale(mainFrame, from_=10, to=90, value=50, orient=Tkinter.HORIZONTAL) self.scale.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="Value Ramp:") label.grid(row=row, column=0, sticky=Tkinter.E) self.valueRamp = ValueRamp(mainFrame, self.valueRampCallback, speed = 1.5, delay = 50) self.valueRamp.grid(row=row, column=1, sticky=Tkinter.W) row += 1 label = Label(mainFrame, text="ButtonList:") label.grid(row=row, column=0, sticky=Tkinter.E) texts = ['Select File','Close','Quit'] commands = [self.selectFile, self.close, self.quit] bottomButtons = ButtonList(mainFrame, texts=texts, commands=commands, expands=True) bottomButtons.grid(row=row, column=1, sticky=Tkinter.EW) self.protocol('WM_DELETE_WINDOW', self.quit) def floatEntryReturn(self, event): value = self.floatEntry.get() self.textWindow.setText('%s\n' % value) def selectObject(self, object, row, col): self.object = object def getKeywords(self, object): if object : values = object.keywords self.multiWidget.set(values) def setKeywords(self, event): values = self.multiWidget.get() self.object.keywords = values self.updateObjects() def getNumber(self, object): if object : self.intEntry.set(object.quantity) def setNumber(self, event): value = self.intEntry.get() self.object.quantity = value self.updateObjects() def toggleFrame1(self, isHidden): if isHidden: self.scrolledMatrix.grid_forget() self.toggleFrame.grid_forget() else: self.scrolledGraph.grid_forget() self.scrolledCanvas.grid_forget() self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW) self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW) self.toggleLabel2.arrowOff() self.toggleLabel3.arrowOff() def toggleFrame2(self, isHidden): if isHidden: self.scrolledGraph.grid_forget() self.toggleFrame.grid_forget() else: self.scrolledMatrix.grid_forget() self.scrolledCanvas.grid_forget() self.scrolledGraph.grid(row=0, column=0, sticky=Tkinter.NSEW) self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW) self.toggleLabel1.arrowOff() self.toggleLabel3.arrowOff() def toggleFrame3(self, isHidden): if isHidden: self.scrolledCanvas.grid_forget() self.toggleFrame.grid_forget() else: self.scrolledMatrix.grid_forget() self.scrolledGraph.grid_forget() self.scrolledCanvas.grid(row=0, column=0, sticky=Tkinter.NSEW) self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW) self.toggleLabel1.arrowOff() self.toggleLabel2.arrowOff() def valueRampCallback(self, value): self.textWindow.setText('%s\n' % value) def checkRadioButtons(self, value): self.textWindow.setText('%s\n' % value) def selectPulldown(self, index, name): self.textWindow.setText('%d, %s\n' % (index, name)) def toggleSelector(self, value): self.textWindow.setText('%s\n' % value) def changedCheckButtons(self, values): self.textWindow.setText(','.join(values) + '\n') def getObjects(self): objects = [] objects.append( Fruit('Lemon', '#FFFF00',1,keywords=['Bitter','Tangy'] ) ) objects.append( Fruit('Orange', '#FF8000',4 ) ) objects.append( Fruit('Banana', '#FFF000',5 ) ) objects.append( Fruit('Pinapple','#FFD000',9 ) ) objects.append( Fruit('Kiwi', '#008000',12) ) objects.append( Fruit('Lime', '#00FF00',2 ) ) objects.append( Fruit('Apple', '#800000',5,keywords=['Crunchy'] ) ) objects.append( Fruit('Pear', '#408000',6 ) ) objects.append( Fruit('Peach', '#FFE0C0',2,keywords=['Sweet','Furry'] ) ) objects.append( Fruit('Plumb', '#800080',7 ) ) return objects def updateObjects(self, event=None): textMatrix = [] objectList = [] colorMatrix = [] for object in self.objects: datum = [] datum.append( object.name ) datum.append( None ) datum.append( object.quantity ) datum.append( ','.join(object.keywords) ) colors = [None, object.color, None, None] textMatrix.append(datum) objectList.append(object) colorMatrix.append(colors) if self.check.get(): self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList) else: self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList, colorMatrix=colorMatrix) def selectFile(self): fileSelectPopup = FileSelectPopup(self, title = 'Choose file', dismiss_text = 'Cancel', selected_file_must_exist = True) fileName = fileSelectPopup.getFile() self.textWindow.setText('File Selected: %s\n' % fileName) def showWarning(self, eventObject): self.textWindow.setText('Text Entry Return Pressed\n') showWarning('Warning Title','Warning Message') return def pressButton(self): self.textWindow.setText('Button Pressed\n') if showYesNo('Title','Prompt: Clear text window?'): self.textWindow.clear() return def quit(self): BasePopup.destroy(self)
def body(self, guiFrame): self.geometry("775x500") guiFrame.expandGrid(0,0) options = ['1D Graphs','Amino Acid CA CB'] tipTexts = ['Simple graphs of how chemical shift values are distributed for a given atom type', 'Density plots of alpha a & beta carbon shift distributions for common amnio acids'] tabbedFrame = TabbedFrame(guiFrame, options=options, grid=(0,0), tipTexts=tipTexts) frameA, frameB = tabbedFrame.frames # # # # # # # 1D GRAPHS # # # # # # # row = 0 MolType = self.project.metaclass.metaObjFromQualName('ccp.molecule.ChemComp.MolType') molTypes = MolType.enumeration molTypes.remove('other') molTypes.remove('carbohydrate') self.molType = 'protein' ccpCodes = self.getCcpCodes(self.molType) or [None,] self.ccpCode = 'Ala' self.atomType = ATOM_TYPES[0] self.atomNamesDict = {} self.chemAtomNmrRefs = self.getCcpCodeData(self.ccpCode, atomType=self.atomType) tipText = 'Which of the common bio-polymer types to show data for' self.molTypeLabel = Label(frameA, text = 'Molecule Type:', grid=(row,0)) self.molTypePulldown = PulldownList(frameA, callback=self.changeMolType, texts=molTypes, grid=(row,1), tipText=tipText) tipText = 'Which residue code to show chemical shift distributions for' self.ccpCodeLabel = Label(frameA, text = 'Residue Code:', grid=(row,2)) self.ccpCodePulldown = PulldownList(frameA, callback=self.changeCcpCode, texts=ccpCodes, index=ccpCodes.index(self.ccpCode), grid=(row,3), tipText=tipText) tipText = 'Whether to show distributions for hydrogen atoms or other atoms' self.atomTypeLabel = Label(frameA, text = 'Atom Type:', grid=(row,4)) self.atomTypePulldown = PulldownList(frameA, callback=self.changeAtomType, texts=ATOM_TYPES, tipText=tipText, grid=(row,5)) row += 1 tipText = 'The selection of atom name to display distributions for' self.atomSelector = PartitionedSelector(frameA, self.toggleAtom, tipText=tipText, maxRowObjects=20) self.atomSelector.grid(row=row, column=0, columnspan=6, sticky='ew') row += 1 frameA.expandGrid(row,5) self.scrolledGraph = ScrolledGraph(frameA, symbolSize=2, reverseX=True, width=650, height=300, title='Chemical shift distribution', xLabel='Chemical shift', yLabel='proportion', motionCallback=self.updateCrosshairs) self.scrolledGraph.grid(row=row, column=0, columnspan=6, sticky='nsew') # # # # # # # PROTEIN CA CB # # # # # # # frameB.expandGrid(0,0) matrix, ppms = self.getCaCbMatrix() title = 'Amino Acid CA & CB Chemical Shifts' self.cacbMatrix = ScrolledDensityMatrix(frameB, matrix=matrix, boxSize=14, title=title, xLabels=ppms, yLabels=AMINO_ACIDS, borderColor='grey', zoom=1.0, labelAxes=True, barPlot=False, doLegend=False, grid=(0,0)) sdm = self.cacbMatrix font = sdm.boldFont x0, y0 = (470,370) sdm.canvas.create_rectangle(x0+170,y0-6,x0+182,y0+6,fill='#4040A0', outline=sdm.borderColor, width=1) sdm.canvas.create_text(x0+200, y0, text='CA', font=font) sdm.canvas.create_rectangle(x0+220,y0-6,x0+232,y0+6,fill='#A04040', outline=sdm.borderColor, width=1) sdm.canvas.create_text(x0+250, y0, text='CB', font=font) sdm.canvas.create_text(x0, y0, text='13C PPM +/- 0.5', font=font) # # # # # # # M A I N # # # # # # # tipText = 'Whether to use chemical shift data from the BMRB (unfiltered) or RefDB sets' label = Label(tabbedFrame.sideFrame, text='Source Database:', grid=(0,0), sticky='e') index = SOURCE_NAMES.index(self.sourceName) self.sourcePulldown = PulldownList(tabbedFrame.sideFrame, self.changeSource, texts=SOURCE_NAMES, index=index, grid=(0,1), sticky='e', tipText=tipText) self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, expands=True, helpUrl=self.help_url, sticky='e', grid=(0,2)) self.waiting = False self.updateAfter() for func in ('__init__', 'delete'): self.registerNotify(self.updateAfter, 'ccp.nmr.NmrReference.NmrReferenceStore', func)
class BrowseReferenceShiftsPopup(BasePopup): """ **Graphs and Charts of Database Chemical Shift Data** This popup window presents the user with the distributions of known chemical shift values, for various kinds of atom, as they appear in the BioMagResBank or re-referenced RefDB databases. This information is useful when attempting to determine the type of a residue from its NMR spectra, for example when performing protein sequence assignment. The popup is divided into two tabs for two different kinds of graphical display. The first "1D graphs" tab shows the distributions of chemical shift value for either hydrogens or other "heavy" atoms within a given kind of residue. The buttons that carry atom names above the main graph can be toggled two switch the display for different kinds of atom on or off. The second "Amino Acid CA CB" tab is a special display to assist in the assignment of protein sequences when using triple-resonance experiments like HNCA/CB. Data for all of the common amino acids is displayed, but only for the alpha and beta carbons. **Caveats & Tips** Two dimensional correlations, e.g. between a 1H resonance and a covalently bound 13C will be added to Analysis in the future. DNA and RNA chemical shift distributions is not present in the RefDB data, but are present in the BMRB data; to view the BMRB data change the pulldown menu at the top-right. Some of the atom types have a second, minor chemical shift distribution, far from the main peak, that is erroneous (this data is still present in the source databases). An example of this is for the NE atom of the amino acid arginine at around 115 ppm, which in this instance is probably caused by peaks being assigned in HSQC spectra in the normal backbone amide ppm range when the NE peak is really an aliased harmonic and should be a spectrum width away, nearer 85 ppm. Distributions that are notably jagged, due to lack of data for a given atom type should naturally not be relied upon to any great degree. """ def __init__(self, parent, *args, **kw): self.guiParent = parent self.sourceName = 'RefDB' self.chemAtomNmrRefs = {} BasePopup.__init__(self, parent=parent, title="Resonance : Reference Chemical Shifts", **kw) def body(self, guiFrame): self.geometry("775x500") guiFrame.expandGrid(0,0) options = ['1D Graphs','Amino Acid CA CB'] tipTexts = ['Simple graphs of how chemical shift values are distributed for a given atom type', 'Density plots of alpha a & beta carbon shift distributions for common amnio acids'] tabbedFrame = TabbedFrame(guiFrame, options=options, grid=(0,0), tipTexts=tipTexts) frameA, frameB = tabbedFrame.frames # # # # # # # 1D GRAPHS # # # # # # # row = 0 MolType = self.project.metaclass.metaObjFromQualName('ccp.molecule.ChemComp.MolType') molTypes = MolType.enumeration molTypes.remove('other') molTypes.remove('carbohydrate') self.molType = 'protein' ccpCodes = self.getCcpCodes(self.molType) or [None,] self.ccpCode = 'Ala' self.atomType = ATOM_TYPES[0] self.atomNamesDict = {} self.chemAtomNmrRefs = self.getCcpCodeData(self.ccpCode, atomType=self.atomType) tipText = 'Which of the common bio-polymer types to show data for' self.molTypeLabel = Label(frameA, text = 'Molecule Type:', grid=(row,0)) self.molTypePulldown = PulldownList(frameA, callback=self.changeMolType, texts=molTypes, grid=(row,1), tipText=tipText) tipText = 'Which residue code to show chemical shift distributions for' self.ccpCodeLabel = Label(frameA, text = 'Residue Code:', grid=(row,2)) self.ccpCodePulldown = PulldownList(frameA, callback=self.changeCcpCode, texts=ccpCodes, index=ccpCodes.index(self.ccpCode), grid=(row,3), tipText=tipText) tipText = 'Whether to show distributions for hydrogen atoms or other atoms' self.atomTypeLabel = Label(frameA, text = 'Atom Type:', grid=(row,4)) self.atomTypePulldown = PulldownList(frameA, callback=self.changeAtomType, texts=ATOM_TYPES, tipText=tipText, grid=(row,5)) row += 1 tipText = 'The selection of atom name to display distributions for' self.atomSelector = PartitionedSelector(frameA, self.toggleAtom, tipText=tipText, maxRowObjects=20) self.atomSelector.grid(row=row, column=0, columnspan=6, sticky='ew') row += 1 frameA.expandGrid(row,5) self.scrolledGraph = ScrolledGraph(frameA, symbolSize=2, reverseX=True, width=650, height=300, title='Chemical shift distribution', xLabel='Chemical shift', yLabel='proportion', motionCallback=self.updateCrosshairs) self.scrolledGraph.grid(row=row, column=0, columnspan=6, sticky='nsew') # # # # # # # PROTEIN CA CB # # # # # # # frameB.expandGrid(0,0) matrix, ppms = self.getCaCbMatrix() title = 'Amino Acid CA & CB Chemical Shifts' self.cacbMatrix = ScrolledDensityMatrix(frameB, matrix=matrix, boxSize=14, title=title, xLabels=ppms, yLabels=AMINO_ACIDS, borderColor='grey', zoom=1.0, labelAxes=True, barPlot=False, doLegend=False, grid=(0,0)) sdm = self.cacbMatrix font = sdm.boldFont x0, y0 = (470,370) sdm.canvas.create_rectangle(x0+170,y0-6,x0+182,y0+6,fill='#4040A0', outline=sdm.borderColor, width=1) sdm.canvas.create_text(x0+200, y0, text='CA', font=font) sdm.canvas.create_rectangle(x0+220,y0-6,x0+232,y0+6,fill='#A04040', outline=sdm.borderColor, width=1) sdm.canvas.create_text(x0+250, y0, text='CB', font=font) sdm.canvas.create_text(x0, y0, text='13C PPM +/- 0.5', font=font) # # # # # # # M A I N # # # # # # # tipText = 'Whether to use chemical shift data from the BMRB (unfiltered) or RefDB sets' label = Label(tabbedFrame.sideFrame, text='Source Database:', grid=(0,0), sticky='e') index = SOURCE_NAMES.index(self.sourceName) self.sourcePulldown = PulldownList(tabbedFrame.sideFrame, self.changeSource, texts=SOURCE_NAMES, index=index, grid=(0,1), sticky='e', tipText=tipText) self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, expands=True, helpUrl=self.help_url, sticky='e', grid=(0,2)) self.waiting = False self.updateAfter() for func in ('__init__', 'delete'): self.registerNotify(self.updateAfter, 'ccp.nmr.NmrReference.NmrReferenceStore', func) def open(self): self.updateAfter() BasePopup.open(self) def changeSource(self, sourceName): if sourceName is not self.sourceName: self.sourceName = sourceName self.updateCcpCodes() self.updateAfter() def getAtomColor(self, i,N): h = i/float(N) s = 1 v = 0.8 [r,g,b] = hsbToRgb(h,s,v) return hexRepr(r,g,b) def toggleAtom(self, atomName): if self.atomNamesDict.get(atomName): self.atomNamesDict[atomName] = False else: self.atomNamesDict[atomName] = True self.updateAfter() def getCcpCodes(self, molType): sourceName = self.sourceName ccpCodes = [] for nmrRef in self.project.findAllNmrReferenceStores(molType=molType): chemCompNmrRef = nmrRef.findFirstChemCompNmrRef(sourceName=sourceName) if chemCompNmrRef: ccpCodes.append(nmrRef.ccpCode) ccpCodes.sort() return ccpCodes def getCcpCodeData(self, ccpCode, molType=None, atomType=None): if not molType: molType = self.molType dataDict = {} project = self.project sourceName = self.sourceName nmrRefStore = project.findFirstNmrReferenceStore(molType=molType,ccpCode=ccpCode) chemCompNmrRef = nmrRefStore.findFirstChemCompNmrRef(sourceName=sourceName) if chemCompNmrRef: chemCompVarNmrRef = chemCompNmrRef.findFirstChemCompVarNmrRef(linking='any',descriptor='any') if chemCompVarNmrRef: for chemAtomNmrRef in chemCompVarNmrRef.chemAtomNmrRefs: atomName = chemAtomNmrRef.name element = chemAtomNmrRef.findFirstChemAtom().elementSymbol if not atomType: dataDict[atomName] = chemAtomNmrRef elif (atomType == 'Hydrogen' and element == 'H') or \ (atomType == 'Heavy' and element != 'H'): dataDict[atomName] = chemAtomNmrRef return dataDict def changeMolType(self, molType): self.molType = molType self.updateCcpCodes() def changeCcpCode(self, ccpCode): self.ccpCode = ccpCode self.updateAtomNames() def changeAtomType(self, atomType): self.atomType = atomType self.updateAtomNames() def updateAfter(self, *opt): if self.waiting: return else: self.waiting = True self.after_idle(self.update) def updateCcpCodes(self): ccpCodes = self.getCcpCodes(self.molType) if ccpCodes: self.ccpCodePulldown.setup(ccpCodes, ccpCodes, 0) self.changeCcpCode(ccpCodes[0]) else: self.ccpCodePulldown.setup([], [], 0) self.changeCcpCode(None) def updateAtomNames(self): if self.ccpCode: self.chemAtomNmrRefs = self.getCcpCodeData(self.ccpCode, atomType=self.atomType) atomNames = self.chemAtomNmrRefs.keys() atomNames = greekSortAtomNames(atomNames, self.molType) N = len(atomNames) for atomName in atomNames: if self.atomNamesDict.get(atomName) is None: self.atomNamesDict[atomName] = True colors = [] for i in range(N): colors.append( self.getAtomColor(i,N) ) else: colors = [] atomNames = [] N = 0 self.atomSelector.update(objects=atomNames,labels=atomNames,colors=colors) for i in range(N): if self.atomNamesDict[atomNames[i]]: self.atomSelector.setButtonState(i, True) else: self.atomSelector.setButtonState(i, False) self.updateAfter() def destroy(self): for func in ('__init__', 'delete'): self.unregisterNotify(self.updateAfter, 'ccp.nmr.NmrReference.NmrReferenceStore', func) BasePopup.destroy(self) def update(self): matrix, ppms = self.getCaCbMatrix() self.cacbMatrix.xLabels = ppms self.cacbMatrix.update(matrix) self.updateAtomNames() dataSets = [] colorList = [] atomsString = '' if self.ccpCode: c = 0 atomNames = self.chemAtomNmrRefs.keys() N = len(atomNames) for atomName in greekSortAtomNames(atomNames, self.molType): if self.atomNamesDict[atomName]: atomsString += '%s ' % atomName chemAtomNmrRef = self.chemAtomNmrRefs[atomName] distribution = chemAtomNmrRef.distribution refPoint = chemAtomNmrRef.refPoint refValue = chemAtomNmrRef.refValue valuePerPoint = chemAtomNmrRef.valuePerPoint data = [] for i in range(len(distribution)): x = refValue + valuePerPoint*( i-refPoint) y = distribution[i] data.append( (x,y) ) dataSets.append(data) colorList.append(self.getAtomColor(c,N)) c += 1 self.scrolledGraph.title = '%s %s Chemical shift distribution' % (self.ccpCode,atomsString) else: dataSets = [[(0,0)],] self.scrolledGraph.title = 'Chemical shift distribution' self.scrolledGraph.zoom = 1.0 self.scrolledGraph.update(dataSets=dataSets, dataColors=colorList) self.waiting = False def getCaCbMatrix(self): ppms = range(73,14,-1) blankCol = [0.0]*len(ppms) matrix = [[0.0]*len(AMINO_ACIDS) for x in ppms] for i, ccpCode in enumerate(AMINO_ACIDS): atomRefDict = self.getCcpCodeData(ccpCode, molType='protein') valueDict = {} for atomName in ('CA','CB'): valueDict[atomName] = blankCol[:] chemAtomNmrRef = atomRefDict.get(atomName) if not chemAtomNmrRef: continue distribution = chemAtomNmrRef.distribution refPoint = chemAtomNmrRef.refPoint refValue = chemAtomNmrRef.refValue valuePerPoint = chemAtomNmrRef.valuePerPoint for j, ppm in enumerate(ppms): ppmMin = ppm-0.5 ppmMax = ppm+0.5 v = 0.0 n = 0.0 for k in range(len(distribution)): y = refValue + valuePerPoint*(k-refPoint) if ppmMin < y <= ppmMax: v += distribution[k] n += 1.0 elif y > ppmMax: break if n: valueDict[atomName][j] = v/n for j, ppm in enumerate(ppms): matrix[j][i] = valueDict['CA'][j] - valueDict['CB'][j] return matrix, ppms def updateCrosshairs(self, event): # code below is a bit dangerous position = self.scrolledGraph.getPlotCoords(event)[0] typeLocation = [] isHydrogen = (self.atomType == 'Hydrogen') for panelType in self.analysisProject.panelTypes: axisType = panelType.axisType if isHydrogen: if axisType.name in ('1H', '2H'): typeLocation.append((panelType, position)) else: if axisType.name not in ('1H', '2H'): typeLocation.append((panelType, position)) self.scrolledGraph.mouseEnter(event) self.parent.drawWindowCrosshairs(typeLocation) def drawCrosshairs(self, typeLocation): """ Draw crosshairs at specified locations. typeLocation = tuple of (PanelType, position) """ isHydrogen = (self.atomType == ATOM_TYPES[0]) positions = [] for (panelType, position) in typeLocation: axisType = panelType.axisType if axisType.measurementType != 'Shift': continue if position is None: continue if isHydrogen: if axisType.name in ('1H', '2H'): positions.append(position) else: if axisType.name not in ('1H', '2H'): positions.append(position) self.scrolledGraph.drawVerticalLines(positions)
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
def body(self, guiFrame): guiFrame.grid_columnconfigure(3, weight=1) self.progressBar = TypingEnsemblePopup(self,total=100) self.progressBar.close() row = 0 label = Label(guiFrame, text=' Chain: ', grid=(row,0)) tipText = 'Selects which molecular chain the spin system residue types will be predicted for; determines which range of types are available' self.chainPulldown = PulldownList(guiFrame, self.changeChain, grid=(row,1), tipText=tipText) tipText = 'Selects which shift list will be used as the source of chemical shift information to make the residue type predictions' label = Label(guiFrame, text='Shift List: ', grid=(row,2)) self.shiftListPulldown = PulldownList(guiFrame, callback=self.setShiftList, grid=(row,3), tipText=tipText) utilButtons = UtilityButtonList(guiFrame, helpUrl=self.help_url) utilButtons.grid(row=row, column=4, sticky='w') row += 1 frame = LabelFrame(guiFrame, text='Options', grid=(row,0), gridSpan=(1,5)) frame.grid_columnconfigure(3, weight=1) frow = 0 label = Label(frame, text='Keep existing types?', grid=(frow,0), sticky='e') tipText = 'Whether any existing residue type information should be preserved, when predicting the type of others' self.preserveTypesSelect = CheckButton(frame, grid=(frow,1), selected=False, callback=self.selectPreserveTypes, tipText=tipText) label = Label(frame, text='Assignment threshold: ', grid=(frow,2), sticky='e') tipText = 'The lower limit for the predicted residue type to be set with "Assign Types"; needs to be adjusted according to result statistics and amount of shift data' self.thresholdEntry = FloatEntry(frame, text=self.threshold, width=8, grid=(frow,3), tipText=tipText) frow += 1 label = Label(frame, text='Ensemble size: ', grid=(frow,0), sticky='e') tipText = 'The number of best scoring residue type mappings, from the Monte Carlo search, to use un the prediction' self.ensembleEntry = IntEntry(frame,text=20,width=4, grid=(frow,1), tipText=tipText) label = Label(frame, text='Num Search Steps: ', grid=(frow,2), sticky='e') tipText = 'The number of iterative steps that will be used in the Monte Carlo search of best spin system to residue type mappings' self.stepsEntry = IntEntry(frame, text=100000, width=8, tipText=tipText, grid=(frow,3)) frow += 1 label = Label(frame, text='Isotope shifts to consider:', grid=(frow,0), gridSpan=(1,4)) frow += 1 self.isotopes = ['1H','13C'] isos = ['1H','13C','15N'] colors = [COLOR_DICT[x] for x in isos] tipText = 'Selects which kinds of resonances, in terms of isotope, the residue type predictions will be made with' self.isotopeCheckButtons = PartitionedSelector(frame, labels=isos, objects=isos, colors=colors, callback=self.toggleIsotope, selected=self.isotopes, grid=(frow,0), gridSpan=(1,4), tipText=tipText) row += 1 guiFrame.grid_rowconfigure(row, weight=1) labelFrame = LabelFrame(guiFrame, text='Spin Systems', grid=(row,0), gridSpan=(1,5)) labelFrame.expandGrid(0,0) tipTexts = ['The spin system serial number', 'The residue to which the spin system may currently be assigned', 'Set whether to include a particular spin system in the type predictions', 'The spin system to residue type match score for a prediction; higher (less negative) is better', 'The predicted types of residue that the spin system may be', 'The chemical shifts in the spin system that will be used in the analysis'] headingList = ['#','Residue','Use?','Score','Types','Shifts'] justifyList = ['center','center','center','center','center','left'] editWidgets = [None, None, None, None, None, None] editGetCallbacks = [None, None, self.toggleInclude, None, None, None] editSetCallbacks = [None, None, None, None, None, None] self.scrolledMatrix = ScrolledMatrix(labelFrame, headingList=headingList, justifyList=justifyList, editSetCallbacks=editSetCallbacks, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, callback=self.selectCell, grid=(0,0), tipTexts=tipTexts) row += 1 tipTexts = ['Execute the Monte Carlo search that will make the residue type predictions for the spin systems', 'Assign the residue type of spin systems with a unique type prediction and prediction score above the stated threshold', 'Show a residue type prediction for the selected spin system alone; only considers that spin system of shifts, not how all spin systems fit to the sequence', 'Show a table of peaks that are assigned to the resonances of the selected spin system'] texts = ['Run\nTyping','Assign\nTypes', 'Show Individual\nClassification', 'Show\nPeaks'] commands = [self.run, self.assign, self.individualScore, self.showPeaks] bottomButtons = ButtonList(guiFrame, texts=texts, commands=commands, grid=(row,0), gridSpan=(1,5), tipTexts=tipTexts) self.runButton = bottomButtons.buttons[0] self.assignButton = bottomButtons.buttons[1] self.scoreButton = bottomButtons.buttons[2] self.peaksButton = bottomButtons.buttons[2] self.runButton.config(bg='#B0FFB0') for func in ('__init__','delete'): self.registerNotify(self.updateChains, 'ccp.molecule.MolSystem.Chain', func) self.registerNotify(self.updateShiftLists, 'ccp.nmr.Nmr.ShiftList', func) for func in ('__init__','delete','setCcpCode', 'setResidue','addResonance', 'setName', 'removeResonance','setResonances'): self.registerNotify(self.updateSpinSystemsAfter, 'ccp.nmr.Nmr.ResonanceGroup', func) self.updateChains() self.updateShiftLists() self.updateSpinSystems()
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 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()
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)
def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) row = 0 frame = LabelFrame(guiFrame, text='Options') frame.grid(row=row, column=0, sticky='ew') frame.grid_columnconfigure(1, weight=1) frame.grid_rowconfigure(1, weight=1) label = Label(frame, text='Window:') label.grid(row=0, column=0, sticky='nw') self.windowPulldown = PulldownList(frame, callback=self.changeWindow) self.windowPulldown.grid(row=0, column=1, sticky='nw') label = Label(frame, text='Multiplet Pattern:') label.grid(row=1, column=0, columnspan=2, sticky='nw') self.multipletButtons = PartitionedSelector(frame, callback=self.setMultiplet, radio=True) self.multipletButtons.grid(row=2, column=0, columnspan=2, sticky='ew') row += 1 frame = LabelFrame(guiFrame, text='Active Peak Lists') frame.grid(row=row, column=0, sticky='ew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) headingList = [ 'Experiment', 'Spectrum', 'List', 'Coupled Dims', 'Experiment Type' ] self.peakListMatrix = ScrolledMatrix(frame, headingList=headingList, callback=None, multiSelect=False) self.peakListMatrix.grid(row=0, column=0, sticky='nsew') row += 1 guiFrame.grid_rowconfigure(row, weight=1) frame = LabelFrame(guiFrame, text='Multiplet Peak Clusters') frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) headingList = [ '#', 'Main\nAssignment', 'Num\nPeaks', 'Coupling\nAssignment', 'Value', 'Value' ] self.clusterMatrix = ScrolledMatrix(frame, headingList=headingList, callback=self.selectCluster, multiSelect=True) self.clusterMatrix.grid(row=0, column=0, sticky='nsew') row += 1 texts = [ 'Cluster Selected\nPeaks', 'Assign\nCouplings', 'List\nPeaks', 'Find\nPeaks', 'Delete\nClusters' ] commands = [ self.clusterSelectedPeaks, self.assignCouplings, self.showPeaks, self.findPeaks, self.deleteClusters ] self.bottomButtons = UtilityButtonList(guiFrame, texts=texts, expands=True, commands=commands, helpUrl=self.help_url) self.bottomButtons.grid(row=row, column=0, sticky='ew') self.administerNotifiers(self.registerNotify)
class CalcCouplingPopup(BasePopup): def __init__(self, parent, *args, **kw): self.waiting = False self.peakList = None self.peakLists = [] self.windowPane = None self.cluster = None self.clusters = {} self.multiplet = None self.guiParent = parent BasePopup.__init__(self, parent=parent, title='Measure Couplings', **kw) self.updateWindows() self.updateAfter() def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) row = 0 frame = LabelFrame(guiFrame, text='Options') frame.grid(row=row, column=0, sticky='ew') frame.grid_columnconfigure(1, weight=1) frame.grid_rowconfigure(1, weight=1) label = Label(frame, text='Window:') label.grid(row=0, column=0, sticky='nw') self.windowPulldown = PulldownList(frame, callback=self.changeWindow) self.windowPulldown.grid(row=0, column=1, sticky='nw') label = Label(frame, text='Multiplet Pattern:') label.grid(row=1, column=0, columnspan=2, sticky='nw') self.multipletButtons = PartitionedSelector(frame, callback=self.setMultiplet, radio=True) self.multipletButtons.grid(row=2, column=0, columnspan=2, sticky='ew') row += 1 frame = LabelFrame(guiFrame, text='Active Peak Lists') frame.grid(row=row, column=0, sticky='ew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) headingList = [ 'Experiment', 'Spectrum', 'List', 'Coupled Dims', 'Experiment Type' ] self.peakListMatrix = ScrolledMatrix(frame, headingList=headingList, callback=None, multiSelect=False) self.peakListMatrix.grid(row=0, column=0, sticky='nsew') row += 1 guiFrame.grid_rowconfigure(row, weight=1) frame = LabelFrame(guiFrame, text='Multiplet Peak Clusters') frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) headingList = [ '#', 'Main\nAssignment', 'Num\nPeaks', 'Coupling\nAssignment', 'Value', 'Value' ] self.clusterMatrix = ScrolledMatrix(frame, headingList=headingList, callback=self.selectCluster, multiSelect=True) self.clusterMatrix.grid(row=0, column=0, sticky='nsew') row += 1 texts = [ 'Cluster Selected\nPeaks', 'Assign\nCouplings', 'List\nPeaks', 'Find\nPeaks', 'Delete\nClusters' ] commands = [ self.clusterSelectedPeaks, self.assignCouplings, self.showPeaks, self.findPeaks, self.deleteClusters ] self.bottomButtons = UtilityButtonList(guiFrame, texts=texts, expands=True, commands=commands, helpUrl=self.help_url) self.bottomButtons.grid(row=row, column=0, sticky='ew') self.administerNotifiers(self.registerNotify) def administerNotifiers(self, notifyFunc): for clazz in ('ccp.nmr.Nmr.DataSource', 'ccp.nmr.Nmr.Experiment'): notifyFunc(self.updatePeakListsAfter, clazz, 'setName') for func in ('__init__', 'delete', 'setName'): notifyFunc(self.updateWindows, 'ccpnmr.Analysis.SpectrumWindow', func) for func in ('__init__', 'delete'): notifyFunc(self.updatePeakListsAfter, 'ccp.nmr.Nmr.PeakList', func) for func in ('__init__', 'delete', 'addPeak', 'setPeaks', 'removePeak', 'setAnnotation'): notifyFunc(self.updateAfter, 'ccp.nmr.Nmr.PeakCluster', func) def deleteClusters(self): clusters = self.clusterMatrix.currentObjects for cluster in clusters: deleteCluster(cluster) def findPeaks(self): if self.windowPane and self.cluster: peaks = list(self.cluster.peaks) if not peaks: return spectrum = peaks[0].peakList.dataSource analysisSpectrum = spectrum.analysisSpectrum view = self.windowPane.findFirstSpectrumWindowView( analysisSpectrum=analysisSpectrum) windowFrame = self.windowPane.getWindowFrame() position = {} n = float(len(peaks)) for axisMapping in view.axisMappings: dim = axisMapping.analysisDataDim.dataDim.dim xyz = axisMapping.label mean = 0.0 for peak in peaks: peakDim = peak.findFirstPeakDim(dim=dim) mean += peakDim.realValue mean /= n position[xyz] = mean windowFrame.gotoPosition(position) def updatePeakListsAfter(self, object): if object.className == 'Experiment': for spectrum in object.dataSources: for peakList in spectrum.peakLists: if peakList in self.peakLists: self.updatePeakLists() elif object.className == 'DataSource': for peakList in object.peakLists: if peakList in self.peakLists: self.updatePeakLists() else: if object in self.peakLists: self.updatePeakLists(object) def open(self): BasePopup.open(self) self.updateWindows() self.updateAfter() def showPeaks(self): peaks = {} for peakCluster in self.clusterMatrix.currentObjects: for peak in peakCluster.peaks: peaks[peak] = True if peaks: self.parent.viewPeaks(peaks.keys()) def getWindows(self): windowPanes = [] for window in self.analysisProject.sortedSpectrumWindows(): for windowPane in window.sortedSpectrumWindowPanes(): for view in windowPane.spectrumWindowViews: if view.isPosVisible or view.isNegVisible: spectrum = view.analysisSpectrum.dataSource if self.getCoupledExpDims(spectrum.experiment): windowPanes.append(windowPane) break return windowPanes def getCoupledExpDims(self, experiment): """ Descrn: List the dimensions (ExpDims) of an experiment which carry couplings. Inputs: Nmr.Experiment Output: List of Nmr.ExpDims """ COUPLING_TYPES = ('JCoupling', 'Rdc', 'DipolarCoupling') expDims = [] refExperiment = experiment.refExperiment if refExperiment: for expDim in experiment.expDims: refExpDim = expDim.refExpDim if not refExpDim: # Could be sampled dim continue for refExpDimRef in refExpDim.refExpDimRefs: if refExpDimRef.coupledIsotopeCodes: expDims.append(expDim) break if not expDims: for expDim in experiment.expDims: for expDimRef in expDim.expDimRefs: if expDimRef.measurementType in COUPLING_TYPES: expDims.append(expDim) break return expDims def changeWindow(self, windowPane): if windowPane is not self.windowPane: self.windowPane = windowPane self.updatePeakLists() def updateWindows(self, *object): panes = self.getWindows() index = 0 names = [] pane = self.windowPane if panes: names = [getWindowPaneName(wp) for wp in panes] if pane not in panes: pane = panes[0] index = panes.index(pane) if pane is not self.windowPane: self.windowPane = pane self.updatePeakLists() self.windowPulldown.setup(names, panes, index) def getPeakLists(self): peakLists = [] if self.windowPane: for view in self.windowPane.spectrumWindowViews: try: spectrum = view.analysisSpectrum.dataSource except: continue if spectrum.peakLists: peakList = spectrum.activePeakList if not peakList: peakList = spectrum.findFirstPeakList() peakLists.append(peakList) return peakLists def updatePeakLists(self, peakList=None): objectList = self.getPeakLists() textMatrix = [] spectra = {} for peakList0 in objectList: spectrum = peakList0.dataSource experiment = spectrum.experiment spectra[spectrum] = True refExperiment = experiment.refExperiment coupledDims = [] if refExperiment: experimentType = refExperiment.name for expDim in experiment.expDims: refExpDim = expDim.refExpDim isotopes = {} for refExpDimRef in refExpDim.refExpDimRefs: for isotope in refExpDimRef.coupledIsotopeCodes: isotopes[isotope] = True if isotopes: isoString = ','.join(isotopes) coupledDims.append('%d (%s)' % (expDim.dim, isoString)) else: experimentType = None if not coupledDims: coupledDims = None else: coupledDims = ' '.join(coupledDims) datum = [ experiment.name, spectrum.name, peakList0.serial, coupledDims, experimentType ] textMatrix.append(datum) self.peakLists = objectList self.peakListMatrix.update(objectList=objectList, textMatrix=textMatrix) self.multiplet = None for spectrum in spectra.keys(): multiplet = self.getSpectrumMultiplet(spectrum) if multiplet: self.multiplet = MULTIPLET_PEAK_DICT.get(multiplet) break self.updateMultipletButtons() self.updateAfter() def setMultiplet(self, pattern): for peakList in self.peakLists: spectrum = peakList.dataSource for name in MULTIPLET_PEAK_DICT.keys(): if MULTIPLET_PEAK_DICT[name] == pattern: setSpectrumMultipletPattern(spectrum, name) break self.multiplet = pattern def setSpectrumMultiplet(self, spectrum, pattern): prevPattern = getSpectrumMultipletPattern(spectrum) if prevPattern and (prevPattern != pattern): if showOkCancel('Query', 'Really change multiplet pattern?', parent=self): setSpectrumMultipletPattern(spectrum, pattern) def getSpectrumMultiplet(self, spectrum): name = getSpectrumMultipletPattern(spectrum) if not name: name = self.predictSpectrumMultiplet(spectrum) setSpectrumMultipletPattern(spectrum, name) return name def predictSpectrumMultiplet(self, spectrum): name = None refExperiment = spectrum.experiment.refExperiment if refExperiment: name = EXPT_MULTIPLETS.get(refExperiment.name) return name def updateMultipletButtons(self): import re labels = [] objects = [] colors = [] selected = None if self.windowPane: coupledAxes = [] spectra = {} for peakList in self.peakLists: spectra[peakList.dataSource] = True multiplet = self.getSpectrumMultiplet(peakList.dataSource) selected = MULTIPLET_PEAK_DICT[multiplet] for spectrum in spectra.keys(): mapping = getDataDimAxisMapping(spectrum, self.windowPane) for axisLabel in ('x', 'y'): dataDim = mapping[axisLabel] for expDimRef in dataDim.expDim.expDimRefs: if expDimRef.refExpDimRef and expDimRef.refExpDimRef.coupledIsotopes: if axisLabel not in coupledAxes: coupledAxes.append(axisLabel) break else: coupledAxes = ['x', 'y'] for name in MULTIPLET_PEAK_DICT.keys(): pattern = MULTIPLET_PEAK_DICT[name] if type(pattern[0]) in (type(()), type([])): if 'y' not in coupledAxes: continue if len(pattern[0]) > 1: # x & y if 'x' not in coupledAxes: continue else: # y only if 'x' in coupledAxes: continue else: # x only if 'x' not in coupledAxes: continue if 'y' in coupledAxes: continue label = re.sub('\|', '\n', name) objects.append(pattern) labels.append(label) colors.append('#8080FF') self.multipletButtons.update(objects=objects, colors=colors, labels=labels) self.multipletButtons.setSelected([ selected, ]) def selectPeakList(self, object, row, col): self.peakList = object self.updateButtons() def selectCluster(self, object, row, col): self.cluster = object self.updateButtons() def assignCouplings(self): for cluster in self.clusterMatrix.currentObjects: assignPrimaryClusterCoupling(cluster) def assignAllCouplings(self): for cluster in self.clusters.keys(): assignPrimaryClusterCoupling(cluster) def clusterSelectedPeaks(self): peaks0 = self.parent.currentPeaks peaks = [] for peak in peaks0: if peak.peakList in self.peakLists: peaks.append(peak) if not peaks: showWarning('Cluster Failure', 'No peaks selected from active peak lists', parent=self) return if not self.multiplet: showWarning('Cluster Failure', 'No multiplet pattern selected', parent=self) return cluster = makeMultipletPeakCluster(peaks, self.multiplet, self.windowPane) if cluster: self.clusterMatrix.selectObject(cluster) def getActiveClusterCouplings(self): clusters = {} if self.peakLists: dims = {} for peakList in self.peakLists: experiment = peakList.dataSource.experiment for expDim in getCoupledExpDims(experiment): dims[expDim.dim] = True dims = dims.keys() for cluster in getPeakListsPeakClusters(self.peakLists): values = [] for dim in dims: values.append(getClusterCoupling(cluster, dim)) # Allow Nones? clusters[cluster] = values self.clusters = clusters return clusters def updateButtons(self): pass def updateAfter(self, cluster=None): if self.waiting: return if cluster: for peak in cluster.peaks: if peak.peakList in self.peakLists: self.waiting = True self.after_idle(self.update) break else: self.waiting = True self.after_idle(self.update) def update(self): clusters = self.getActiveClusterCouplings() textMatrix = [] objectList = [] headingList = [ '#', 'Main\nAssignment', 'Num\nPeaks', 'Coupling\nAssignment' ] if clusters: cluster0 = clusters.keys()[0] i = 1 for value in clusters[cluster0]: headingList.append('F%d Value\n(Hz)' % i) i += 1 else: headingList.append('Value') for cluster in clusters.keys(): couplingAssign = ','.join(getCouplingAnnotations(cluster)) datum = [ cluster.serial, cluster.annotation, len(cluster.peaks), couplingAssign ] values = clusters[cluster] for value in values: datum.append(value) textMatrix.append(datum) objectList.append(cluster) self.clusterMatrix.update(headingList=headingList, textMatrix=textMatrix, objectList=objectList) self.updateButtons() self.waiting = False def destroy(self): self.administerNotifiers(self.unregisterNotify) BasePopup.destroy(self)