def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) guiFrame.grid_rowconfigure(1, weight=1) frame = LabelFrame(guiFrame, text='Options') frame.grid(row=0,column=0,sticky='ew') frame.grid_columnconfigure(5, weight=1) # Choose type of symmetry set to define or change (if allready present in the model) self.molLabel = Label(frame, text='Symmetry Operator:') self.molLabel.grid(row=0,column=2,sticky='w') self.symmCodePulldown = PulldownMenu(frame, callback=self.setSymmCode, entries=['NCS','C2','C3','C5'], do_initial_callback=False) self.symmCodePulldown.grid(row=0,column=3,sticky='w') frame = LabelFrame(guiFrame, text='Symmetry Operations') frame.grid(row=1,column=0,sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) self.molSysPulldown = PulldownMenu(self, callback=self.setMolSystem, do_initial_callback=False) self.chainSelect = MultiWidget(self, CheckButton, callback=self.setChains, minRows=0, useImages=False) self.segStartEntry = IntEntry(self, returnCallback=self.setSegStart, width=6) self.segLengthEntry = IntEntry(self, returnCallback=self.setSegLength, width=6) headings = ['#','Symmetry\noperator','Mol System','Chains','Start\nresidue','Segment\nlength'] editWidgets = [None, None, self.molSysPulldown, self.chainSelect, self.segStartEntry, self.segLengthEntry] editGetCallbacks = [None, None, self.getMolSystem, self.getChains, self.getSegStart, self.getSegLength] editSetCallbacks = [None, self.setSymmCode, self.setMolSystem, self.setChains, self.setSegStart, self.setSegLength] self.symmetryMatrix = ScrolledMatrix(frame,headingList=headings, callback=self.selectSymmetry, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.symmetryMatrix.grid(row=0,column=0,sticky='nsew') texts = ['Add Symmetry Set','Remove Symmetry Set'] commands = [self.addSymmetrySet,self.removeSymmetrySet] self.buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, expands=True) self.buttonList.grid(row=2,column=0,sticky='ew') self.updateMolPartners() self.notify(self.registerNotify) #Temporary report of parameters print self.molSystem print self.molecules print self.symmetrySet print self.symmetryOp print self.symmetryCode
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, 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 EditSymmetryPopup(BasePopup): def __init__(self, parent, project): self.parent = parent self.ccpnProject = project self.hProject = project.currentHaddockProject self.molPartner = None self.molecules = [] self.symmetrySet = None self.symmetryOp = None self.symmetryCode = None self.waiting = False BasePopup.__init__(self, parent=parent, title='Symmetry Operations') self.font = 'Helvetica 12' self.setFont() def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) guiFrame.grid_rowconfigure(1, weight=1) frame = LabelFrame(guiFrame, text='Options') frame.grid(row=0,column=0,sticky='ew') frame.grid_columnconfigure(5, weight=1) # Choose type of symmetry set to define or change (if allready present in the model) self.molLabel = Label(frame, text='Symmetry Operator:') self.molLabel.grid(row=0,column=2,sticky='w') self.symmCodePulldown = PulldownMenu(frame, callback=self.setSymmCode, entries=['NCS','C2','C3','C5'], do_initial_callback=False) self.symmCodePulldown.grid(row=0,column=3,sticky='w') frame = LabelFrame(guiFrame, text='Symmetry Operations') frame.grid(row=1,column=0,sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) self.molSysPulldown = PulldownMenu(self, callback=self.setMolSystem, do_initial_callback=False) self.chainSelect = MultiWidget(self, CheckButton, callback=self.setChains, minRows=0, useImages=False) self.segStartEntry = IntEntry(self, returnCallback=self.setSegStart, width=6) self.segLengthEntry = IntEntry(self, returnCallback=self.setSegLength, width=6) headings = ['#','Symmetry\noperator','Mol System','Chains','Start\nresidue','Segment\nlength'] editWidgets = [None, None, self.molSysPulldown, self.chainSelect, self.segStartEntry, self.segLengthEntry] editGetCallbacks = [None, None, self.getMolSystem, self.getChains, self.getSegStart, self.getSegLength] editSetCallbacks = [None, self.setSymmCode, self.setMolSystem, self.setChains, self.setSegStart, self.setSegLength] self.symmetryMatrix = ScrolledMatrix(frame,headingList=headings, callback=self.selectSymmetry, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.symmetryMatrix.grid(row=0,column=0,sticky='nsew') texts = ['Add Symmetry Set','Remove Symmetry Set'] commands = [self.addSymmetrySet,self.removeSymmetrySet] self.buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, expands=True) self.buttonList.grid(row=2,column=0,sticky='ew') self.updateMolPartners() self.notify(self.registerNotify) #Temporary report of parameters print self.molSystem print self.molecules print self.symmetrySet print self.symmetryOp print self.symmetryCode def getMolSystem(self, partner): """Select molecular system from list of molsystems stored in the project""" names = []; index = -1 molSystem = partner.molSystem molSystems = self.ccpnProject.sortedMolSystems() if molSystems: names = [ms.code for ms in molSystems] if molSystem not in molSystems: molSystem = molSystems[0] index = molSystems.index(molSystem) self.molSysPulldown.setup(names, index) def getChains(self, partner): names = [] values = [] molSystem = partner.molSystem if molSystem: for chain in molSystem.sortedChains(): names.append(chain.code) if not partner.chains: values.append(True) elif partner.findFirstChain(chain=chain): values.append(True) else: values.append(False) self.chainSelect.set(values=values,options=names) else: showWarning('Warning','Set Mol System or ensemble first',parent=self) self.symmetryMatrix.keyPressEscape() def getSegLength(self, symmetryOp): if symmetryOp and symmetryOp.segmentLength: self.segLengthEntry.set(symmetryOp.segmentLength) def getSegStart(self): pass def setMolSystem(self, partner, name=None): """Get all molsystems as stored in the project as list""" index = self.molSysPulldown.getSelectedIndex() molSystems = self.ccpnProject.sortedMolSystems() if molSystems: molSystem = molSystems[index] self.molPartner.molSystem = molSystem chains = molSystem.sortedChains() if (not self.molPartner.chains) and chains: setPartnerChains(self.molPartner,chains) self.updateAllAfter() def setChains(self, obj): """Get the list of chains for the selected molsystem""" if self.molPartner and self.molPartner.molSystem: if obj is not None: chains = self.molPartner.molSystem.sortedChains() values = self.chainSelect.get() chains = [chains[i] for i in range(len(values)) if values[i]] setPartnerChains(self.molPartner,chains) self.symmetryMatrix.keyPressEscape() self.updateAllAfter() def setSegLength(self, event): value = self.segLengthEntry.get() or 1 self.symmetryOp.segmentLength = value def setSegStart(self): pass def setSymmCode(self, index, name=None): self.symmetryCode = self.symmCodePulldown.getSelected() def selectSymmetry(self, obj, row, col): self.symmetryOp = obj self.updateMolSysPulldown() def notify(self, notifyFunc): for func in ('__init__', 'delete', 'setSymmetryCode','setSegmentLength'): notifyFunc(self.updateAllAfter, 'molsim.Symmetry.Symmetry', func) for func in ('__init__', 'delete','setfirstSeqId'): notifyFunc(self.updateAllAfter, 'molsim.Symmetry.Segment', func) def addSymmetrySet(self): if not self.ccpnProject.molSystems: showWarning('Warning','No molecular systems present in CCPN project',parent=self) return molSystem = self.ccpnProject.findFirstMolSystem() partner = self.hProject.newHaddockPartner(code=molSystem.code, molSystem=molSystem) setPartnerChains(partner, molSystem.chains) self.updateAllAfter() def removeSymmetrySet(self): pass def updateAllAfter(self, obj=None): if self.waiting: return else: self.waiting = True self.after_idle(self.updateSymmetries, self.updateMolPartners) def updateMolPartners(self): textMatrix = [] objectList = [] for partner in self.hProject.sortedHaddockPartners(): datum = [partner.code, self.symmetryCode, partner.molSystem.code, ','.join([c.chain.code for c in partner.chains]), partner.autoHistidinePstate and 'Yes' or 'No', partner.isDna and 'Yes' or 'No'] objectList.append(partner) textMatrix.append(datum) self.symmetryMatrix.update(objectList=objectList, textMatrix=textMatrix) self.updateMolSysPulldown() def updateMolSysPulldown(self): names = [] index = -1 partners = self.hProject.sortedHaddockPartners() if partners: if self.molPartner not in partners: self.molPartner = partners[0] names = ['Partner %s' % p.code for p in partners] index = partners.index(self.molPartner) else: self.molPartner = None self.molSysPulldown.setup(names, index) def updateSymmetries(self): textMatrix = []; objectList = [] if self.symmetrySet: for symmetryOp in self.symmetrySet.symmetries: chains = []; segments = [] length = symmetryOp.segmentLength for segment in symmetryOp.sortedSegments(): code = segment.chainCode chain = self.molSystem.findFirstChain(code=code) if chain: chains.append(code) seqId = segment.firstSeqId residue1 = chain.findFirstResidue(seqId=seqId) residue2 = chain.findFirstResidue(seqId=seqId+length-1) segments.append('%s:%d-%d' % (code,residue1.seqCode,residue2.seqCode)) datum = [symmetryOp.serial, symmetryOp.symmetryCode, length, '\n'.join(chains), '\n'.join(segments)] objectList.append(symmetryOp) textMatrix.append(datum) self.symmetryMatrix.update(objectList=objectList, textMatrix=textMatrix) self.waiting = False def destroy(self): self.notify(self.unregisterNotify) BasePopup.destroy(self)
class EditSymmetryPopup(BasePopup): def __init__(self, parent, project): self.parent = parent self.project = project self.singleMolecule = True self.molSystem = None self.molecules = [] self.symmetrySet = None self.symmetryOp = None self.waiting = False BasePopup.__init__(self, parent=parent, title='Symmetry Operations') def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) guiFrame.grid_rowconfigure(1, weight=1) frame = LabelFrame(guiFrame, text='Options') frame.grid(row=0, column=0, sticky='ew') frame.grid_columnconfigure(5, weight=1) label = Label(frame, text='MolSystem:') label.grid(row=0, column=0, sticky='w') self.molSystemPulldown = PulldownMenu(frame, callback=self.selectMolSystem) self.molSystemPulldown.grid(row=0, column=1, sticky='w') self.molLabel = Label(frame, text='Molecule:') self.molLabel.grid(row=0, column=2, sticky='w') self.moleculePulldown = PulldownMenu(frame, callback=self.selectMolecule) self.moleculePulldown.grid(row=0, column=3, sticky='w') label = Label(frame, text='Same Molecule Symmetry:') label.grid(row=0, column=4, sticky='w') self.molSelect = CheckButton(frame, callback=self.toggleSingleMolecule) self.molSelect.grid(row=0, column=5, sticky='w') self.molSelect.set(self.singleMolecule) frame = LabelFrame(guiFrame, text='Symmetry Operations') frame.grid(row=1, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) self.symmCodePulldown = PulldownMenu(self, callback=self.setSymmCode, do_initial_callback=False) self.segLengthEntry = IntEntry(self, returnCallback=self.setSegLength, width=6) self.setChainMulti = MultiWidget(self, CheckButton, callback=self.setChains, minRows=0, useImages=False) self.setSegmentMulti = MultiWidget(self, IntEntry, callback=self.setSegments, minRows=0, useImages=False) editWidgets = [ None, self.symmCodePulldown, self.segLengthEntry, self.setChainMulti, self.setSegmentMulti ] editGetCallbacks = [ None, self.getSymmCode, self.getSegLength, self.getChains, self.getSegments ] editSetCallbacks = [ None, self.setSymmCode, self.setSegLength, self.setChains, self.setSegments ] headings = [ '#', 'Symmetry\nType', 'Segment\nLength', 'Chains', 'Segment\nPositions' ] self.symmetryMatrix = ScrolledMatrix(frame, headingList=headings, callback=self.selectSymmetry, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.symmetryMatrix.grid(row=0, column=0, sticky='nsew') texts = ['Add Symmetry Op', 'Remove Symmetrey Op'] commands = [self.addSymmOp, self.removeSymmOp] buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, expands=True) buttonList.grid(row=2, column=0, sticky='ew') self.updateMolSystems() self.updateMolecules() self.updateSymmetriesAfter() self.notify(self.registerNotify) def open(self): self.updateMolSystems() self.updateMolecules() self.updateSymmetriesAfter() BasePopup.open(self) def notify(self, notifyFunc): for func in ('__init__', 'delete', 'setSymmetryCode', 'setSegmentLength'): notifyFunc(self.updateSymmetriesAfter, 'molsim.Symmetry.Symmetry', func) for func in ('__init__', 'delete', 'setfirstSeqId'): notifyFunc(self.updateSymmetriesAfter, 'molsim.Symmetry.Segment', func) def getSymmCode(self, symmetryOp): """Get allowed symmetry operators from the model""" symmetryOpCodes = symmetryOp.parent.metaclass.container.getElement( 'SymmetryOpCode').enumeration index = 0 if symmetryOp.symmetryCode in symmetryOpCodes: index = symmetryOpCodes.index(symmetryOp.symmetryCode) self.symmCodePulldown.setup(symmetryOpCodes, index) def getSegLength(self, symmetryOp): if symmetryOp and symmetryOp.segmentLength: self.segLengthEntry.set(symmetryOp.segmentLength) def getChains(self, symmetryOp): chains = [] for chain in self.molSystem.chains: if chain.residues: if chain.molecule in self.molecules: chains.append(chain.code) chains.sort() values = [] for chain in chains: if symmetryOp.findFirstSegment(chainCode=chain): values.append(True) else: values.append(False) self.setChainMulti.set(values=values, options=chains) def getSegments(self, symmetryOp): values = [] names = [] if symmetryOp: for segment in symmetryOp.sortedSegments(): names.append(segment.chainCode) values.append(segment.firstSeqId) n = len(values) self.setSegmentMulti.maxRows = n self.setSegmentMulti.minRows = n self.setSegmentMulti.set(values=values, options=names) def setSymmCode(self, index, name=None): """Set the symmetry code as NCS,C2,C3,C4,C5,C6""" if self.symmetryOp: symmCode = self.symmCodePulldown.getSelected() self.symmetryOp.symmetryCode = symmCode def setSegLength(self, event): value = self.segLengthEntry.get() or 1 self.symmetryOp.segmentLength = value def setChains(self, obj): if self.symmetryOp and obj: codes = self.setChainMulti.options segment = self.symmetryOp.findFirstSegment() values = self.setChainMulti.get() if segment: seqId0 = segment.firstSeqId else: seqId0 = 1 for i in range(len(values)): segment = self.symmetryOp.findFirstSegment(chainCode=codes[i]) if segment and not values[i]: segment.delete() elif values[i] and not segment: chain = self.molSystem.findFirstChain(code=codes[i]) residue = chain.findFirstResidue(seqid=seqId0) if residue: seqId = seqId0 else: residue = chain.sortedResidues()[0] seqId = residue.seqId residue2 = chain.findFirstResidue( seqid=seqId + self.symmetryOp.segmentLength) if not residue2: residue2 = chain.sortedResidues()[-1] self.symmetryOp.segmentLength = (residue2.seqId - seqId) + 1 segment = self.symmetryOp.newSegment(chainCode=codes[i], firstSeqId=seqId) self.symmetryMatrix.keyPressEscape() def setSegments(self, obj): if self.symmetryOp and obj: segments = self.symmetryOp.sortedSegments() values = self.setSegmentMulti.get() for i in range(len(values)): seqCode = values[i] chain = self.molSystem.findFirstChain( code=segments[i].chainCode) residue = chain.findFirstResidue(seqCode=seqCode) if residue: seqId = residue.seqId if segments[i].firstSeqId != seqId: segments[i].delete() segments[i] = self.symmetryOp.newSegment( chainCode=chain.code, firstSeqId=seqId) self.symmetryMatrix.keyPressEscape() def selectSymmetry(self, obj, row, col): self.symmetryOp = obj def addSymmOp(self): if self.molSystem: if not self.symmetrySet: self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet( ) if not self.symmetrySet: objGen = self.project.newMolSystemSymmetrySet self.symmetrySet = objGen(symmetrySetId=1, molSystem=self.molSystem) segLen = len(self.molSystem.findFirstChain().residues) symmetry = self.symmetrySet.newSymmetry(segmentLength=segLen) def removeSymmOp(self): if self.symmetryOp: self.symmetryOp.delete() def toggleSingleMolecule(self, boolean): self.singleMolecule = not boolean self.updateMolSystems() self.updateMolecules() def setMolecules(self, molecules): self.molecules = molecules if self.symmetrySet: for symmetryOp in self.symmetrySet.symmetries: for segment in symmetryOp.segments: chain = self.molSystem.findFirstChain( code=segment.chainCode) if chain and (chain.molecule not in molecules): segment.delete() def selectMolecule(self, index, name): self.setMolecules(self.getMolecules()[index]) self.updateSymmetries() def getMolecules(self): counts = {} moleculesList = [] for chain in self.molSystem.chains: molecule = chain.molecule counts[molecule] = counts.get(molecule, 0) + 1 molecules = counts.keys() if self.singleMolecule: for molecule in counts: if counts[molecule] > 1: moleculesList.append([ molecule, ]) elif molecules: molecules = counts.keys() n = len(molecules) moleculesList.append([ molecules[0], ]) if n > 1: moleculesList.append([ molecules[1], ]) moleculesList.append([molecules[0], molecules[1]]) if n > 2: moleculesList.append([ molecules[2], ]) moleculesList.append([molecules[1], molecules[2]]) moleculesList.append( [molecules[0], molecules[1], molecules[2]]) if n > 3: moleculesList.append([ molecules[3], ]) moleculesList.append([molecules[0], molecules[3]]) moleculesList.append([molecules[1], molecules[3]]) moleculesList.append([molecules[2], molecules[3]]) moleculesList.append( [molecules[0], molecules[1], molecules[3]]) moleculesList.append( [molecules[0], molecules[2], molecules[3]]) moleculesList.append( [molecules[1], molecules[2], molecules[3]]) moleculesList.append( [molecules[0], molecules[1], molecules[2], molecules[3]]) return moleculesList def updateMolecules(self): names = [] index = -1 moleculesList = self.getMolecules() if moleculesList: if self.molecules not in moleculesList: self.setMolecules(moleculesList[0]) self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet( ) index = moleculesList.index(self.molecules) names = [] for molecules in moleculesList: names.append(','.join([mol.name for mol in molecules])) else: self.molecules = [] self.moleculePulldown.setup(names, index) def selectMolSystem(self, index, name): self.molSystem = self.getMolSystems()[index] self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet() self.updateSymmetries() def getMolSystems(self): molSystems = [] for molSystem in self.project.sortedMolSystems(): n = len(molSystem.chains) if self.singleMolecule and (n > 1): molSystems.append(molSystem) elif n > 0: molSystems.append(molSystem) return molSystems def updateMolSystems(self): names = [] index = -1 molSystems = self.getMolSystems() if molSystems: if self.molSystem not in molSystems: self.molSystem = molSystems[0] index = molSystems.index(self.molSystem) names = [ms.code for ms in molSystems] else: self.molSystem = None self.molSystemPulldown.setup(names, index) def updateSymmetriesAfter(self, obj=None): if self.waiting: return else: self.waiting = True self.after_idle(self.updateSymmetries) def updateSymmetries(self): textMatrix = [] objectList = [] if self.symmetrySet: for symmetryOp in self.symmetrySet.symmetries: chains = [] segments = [] length = symmetryOp.segmentLength for segment in symmetryOp.sortedSegments(): code = segment.chainCode chain = self.molSystem.findFirstChain(code=code) if chain: chains.append(code) seqId = segment.firstSeqId residue1 = chain.findFirstResidue(seqId=seqId) residue2 = chain.findFirstResidue(seqId=seqId + length - 1) segments.append( '%s:%d-%d' % (code, residue1.seqCode, residue2.seqCode)) datum = [ symmetryOp.serial, symmetryOp.symmetryCode, length, '\n'.join(chains), '\n'.join(segments) ] objectList.append(symmetryOp) textMatrix.append(datum) self.symmetryMatrix.update(objectList=objectList, textMatrix=textMatrix) self.waiting = False def destroy(self): self.notify(self.unregisterNotify) BasePopup.destroy(self)
def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) guiFrame.grid_rowconfigure(1, weight=1) frame = LabelFrame(guiFrame, text='Options') frame.grid(row=0, column=0, sticky='ew') frame.grid_columnconfigure(5, weight=1) label = Label(frame, text='MolSystem:') label.grid(row=0, column=0, sticky='w') self.molSystemPulldown = PulldownMenu(frame, callback=self.selectMolSystem) self.molSystemPulldown.grid(row=0, column=1, sticky='w') self.molLabel = Label(frame, text='Molecule:') self.molLabel.grid(row=0, column=2, sticky='w') self.moleculePulldown = PulldownMenu(frame, callback=self.selectMolecule) self.moleculePulldown.grid(row=0, column=3, sticky='w') label = Label(frame, text='Same Molecule Symmetry:') label.grid(row=0, column=4, sticky='w') self.molSelect = CheckButton(frame, callback=self.toggleSingleMolecule) self.molSelect.grid(row=0, column=5, sticky='w') self.molSelect.set(self.singleMolecule) frame = LabelFrame(guiFrame, text='Symmetry Operations') frame.grid(row=1, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) self.symmCodePulldown = PulldownMenu(self, callback=self.setSymmCode, do_initial_callback=False) self.segLengthEntry = IntEntry(self, returnCallback=self.setSegLength, width=6) self.setChainMulti = MultiWidget(self, CheckButton, callback=self.setChains, minRows=0, useImages=False) self.setSegmentMulti = MultiWidget(self, IntEntry, callback=self.setSegments, minRows=0, useImages=False) editWidgets = [ None, self.symmCodePulldown, self.segLengthEntry, self.setChainMulti, self.setSegmentMulti ] editGetCallbacks = [ None, self.getSymmCode, self.getSegLength, self.getChains, self.getSegments ] editSetCallbacks = [ None, self.setSymmCode, self.setSegLength, self.setChains, self.setSegments ] headings = [ '#', 'Symmetry\nType', 'Segment\nLength', 'Chains', 'Segment\nPositions' ] self.symmetryMatrix = ScrolledMatrix(frame, headingList=headings, callback=self.selectSymmetry, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.symmetryMatrix.grid(row=0, column=0, sticky='nsew') texts = ['Add Symmetry Op', 'Remove Symmetrey Op'] commands = [self.addSymmOp, self.removeSymmOp] buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, expands=True) buttonList.grid(row=2, column=0, sticky='ew') self.updateMolSystems() self.updateMolecules() self.updateSymmetriesAfter() self.notify(self.registerNotify)
class IsotopeSchemeEditor(BasePopup): """ **Create and Edit Per-residue Reference Isotope Schemes** This system allows the user to create schemes that describe particular patterns of atomic isotope labelling in terms of combinations of isotopically labelled forms of residues. Once constructed, these schemes may then be applied to a molecule of known residue sequence to gauge the levels of spin-active isotope incorporation in an NMR experiment. This information is useful in several places withing Analysis, including giving more intelligent assignment options and in the generation of distance restraints by matching peak positions to chemical shifts. Although the schemes may be used directly they are typically used as reference information for configuring the `Isotope Labelling`_ system; where isotope labelling patterns are tied to particular molecules and experiments. Because all of the different isotope labelled versions (isotopomers) of each residue type are described independently, a scheme can be used to estimate the specific amounts of incorporation present at multiple atom sites at the same time. For example, although a residue type may have significant levels of 13C at the CA and CB positions on average, there may be no form of the residue where CA and CB are labelled at the same time, and thus CA-CB correlations would not be observed in NMR. This popup window is divided into three main tabs, the first describes the overall schemes that are available; that would be applied to a molecule in a given situation. The second tab details the residue isotopomer components within the selected scheme, i.e. which labelled residue forms are present. The last tab displays isotopomer labelling in a graphical, three-dimensional way. If any isotope labelling schemes have been created or edited the user may immediately save these to disk via the [Save Schemes] button to the right of the tabs, although these will naturally be saved when the main CCPN project is. **Reference Schemes** This table lists all of the reference isotope schemes that are available to the project. A number of standard schemes are included by default, as part of the main CCPN installation. However, the user is free to create new schemes, either from a completely blank description or by copying and modifying one of the existing schemes. By selecting on a isttope scheme row in the table the scheme is selected to be active for the whole popup and the user can see the contents of the scheme via the other two tabs. It should be noted that the user cannot edit the standard schemes provided by CCPN, given that these are stored with the software. Any new or copied schemes that the user creates will be stored inside the current CCPN project. If a new scheme should be made available to multiple projects, its XML file can be copied into the main CCPN installation, if the user has appropriate write access. **Isotopomers** The middle tab allows the user to view, and where appropriate edit, the isotope labelling descriptions for the residues within the current scheme (selected in the pulldown menu at the top). An isotope scheme is constructed by specifying one or more isotopomers for each residue type. Each isotopomer represents a different way of incorporating spin-active atom labels into a given kind of residue. Often there will only be one labelled form of a residue, and hence one isotopomer. However, with some kinds of isotope enrichment, for example using glycerol 13C labelled at the C2 position, connected labelled and unlabelled atom sites can be incorporated in alternative ways, resulting in distinct forms of labelling patterns that are not the result of a pure random mix. Knowing which labels are present at the same time, in the same isotopomer form, can be very important for determining which NMR correlations are possible. In general use when looking through the default, immutable reference schemes that come with CCPN the user can scroll through the isotopomer versions of each residue in the upper table. By clicking on one of these rows the lower table is filled with details of the amount of each kind of isotope (on average) at each atom site. For the lower "Atom Labels" table only one kind of chemical element is shown at a time, but the user may switch to a different one via the "Chemical Element" pulldown. **Editing Isotopomers** When dealing with copied or new isotope schemes the user is allowed to edit all aspects of the scheme. With a completely new scheme there will be no isotopomer records to start with and it is common practice to fill in a standard set of isotopomers, one for each residue type, made with a base level of isotope incorporation. To set this base level the user can use [Set Default Abundances] to manually specify values, although the default is to use natural abundance levels, which is appropriate in most circumstances. With the base levels set the [Add Default Abundance Set] will automatically fill-in a starting set of isotopomers for the scheme. Extra isotopomers can be added for a specific type of residue via the [Add New:] function and adjacent pulldown menu or by copying existing ones; whichever is easier. Each isotopomer has an editable weight to enable the user to indicate the relative abundance within a given residue type. Once a new isotopomer specification is created clicking on its row allows the user to specify the isotope labelling pattern in the lower "Atom Labels" table. Here the user selects which kind of chemical element to consider and then double-clicks to edit the "Weighting" columns in the table. The weightings represent the relative abundance of a given nuclear isotope at a given atom site. The weightings could be set as ratios, fractions, or percentages; it is only the relative proportion that is important. For example if a carbon atom site was known to have 5% Carbon-12 and 95% Carbon-13 isotopes then the respective weights could be entered as 1 & 19 or 0.05 & 0.95; whatever is most convenient. For efficient setup of schemes the [Propagate Abundances] function can be used to spread the same levels of incorporation over several atom sites (from the last selected row). **Isotopomer Structure** The last tab is an alternative way of presenting the isotope patterns present within the residues of the current scheme (selected in either of the first two tabs). Here the user selects a residue type in the upper left pulldown menu and then a numbered isotopomer, or an average of all isotopomers, in the right hand pulldown menu. The structural display will show a moveable picture of the residue (in a standard conformation) where unlabelled atom sites are represented with grey spheres, labelled sites with yellow spheres and intermediate incorporation with shades in between. It should be noted that this kind of 3D display is only possible if there is an idealised structure available for a residue type. This data will be present for all of the regular biopolymer residues, but may be missing for more unusual compounds; although a lack of coordinates does not impact upon the isotopomer setup. To move and rotate the three-dimensional residue display the following keyboard controls may be used: * Rotate: Arrow keys * Zoom: Page Up & Page Down keys * Translate: Arrow keys + Control key Or alternatively the following mouse controls: * Rotate: Middle button click & drag * Zoom: Mouse wheel or middle button click + Shift key & drag up/down * Translate: Middle button click & drag + Control key Also an options menu appears when the right mouse button is clicked. .. _`Isotope Labelling`: EditMolLabellingPopup.html """ def __init__(self, parent, project=None, *args, **kw): if not project: self.project = Implementation.MemopsRoot( name='defaultUtilityProject') else: self.project = project self.waiting = False self.waitingAtom = False self.molType = 'protein' self.scheme = None self.isotopomer = None self.isotopomerV = False # Not None self.ccpCodeV = None self.element = 'C' self.atomLabelTuple = None self.isotopes = [x[0] for x in getSortedIsotopes(self.project, 'C')] self.defaultAbun = {} BasePopup.__init__(self, parent=parent, title='Molecule : Reference Isotope Schemes', **kw) def body(self, guiFrame): self.geometry('700x600') guiFrame.expandGrid(0, 0) tipTexts = [ 'A table of all of the reference isotope scheme definitions available to the project', 'A list of the residue isotopomers that comprise the selected isotope labelling scheme', 'A three-dimensional representation of residues and their isotopomer labelling' ] options = ['Reference Schemes', 'Isotopomers', 'Isotopomer Structure'] tabbedFrame = TabbedFrame(guiFrame, options=options, grid=(0, 0), tipTexts=tipTexts) self.tabbedFrame = tabbedFrame frameA, frameB, frameC = tabbedFrame.frames # # Schemes # frameA.expandGrid(0, 0) tipTexts = [ 'A short textual code that identifies the reference isotope scheme in graphical displays', 'The full name for the isotope scheme', 'A detailed description of the isotope scheme including user comments', 'The name of the CCPN data repository in which the isotope scheme is saved; "refData" is in the CCPn installation' ] headingList = ['Code', 'Name', 'Description', 'Save Location'] self.schemeNameEntry = Entry(self, text='', returnCallback=self.setSchemeName, width=20) self.schemeDetailsEntry = Entry(self, text='', returnCallback=self.setSchemeDetails, width=20) editWidgets = [ None, self.schemeNameEntry, self.schemeDetailsEntry, None ] editGetCallbacks = [ None, self.getSchemeName, self.getSchemeDetails, None ] editSetCallbacks = [ None, self.setSchemeName, self.setSchemeDetails, None ] self.schemeMatrix = ScrolledMatrix(frameA, headingList=headingList, callback=self.selectScheme, editWidgets=editWidgets, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, multiSelect=False, grid=(0, 0), tipTexts=tipTexts) self.schemeMatrix.doEditMarkExtraRules = self.schemeEditRules tipTexts = [ 'Make a new reference isotope scheme definition based on a copy of the scheme currently selected', 'Delete the selected isotope scheme', 'Make a new, blank isotope scheme' ] texts = ['Copy', 'Delete', 'New'] commands = [self.copyScheme, self.removeScheme, self.makeNewScheme] self.schemeButtons = ButtonList(frameA, texts=texts, commands=commands, grid=(1, 0), tipTexts=tipTexts) # # Isotopomers # frameB.expandGrid(3, 0) row = 0 frame = Frame(frameB, grid=(row, 0)) frame.expandGrid(0, 2) tipText = 'Selects which of the available isotope schemes to view/edit' label = Label(frame, text='Reference Scheme:', grid=(0, 0)) self.schemePulldown = PulldownList(frame, callback=self.setLabellingScheme, grid=(0, 1), tipText=tipText) row += 1 div = LabelDivider(frameB, text='Isotopomers', grid=(row, 0)) row += 1 frame = Frame(frameB, grid=(row, 0)) frame.expandGrid(1, 2) self.isotopomerFrame = frame self.abundanceWidget = MultiWidget(self, FloatEntry, relief='raised', borderwidth=2, callback=self.setDefaultAbundances, useImages=False) tipText = 'Opens a panel that allows you to set the basis/default abundances for C, H & N isotopes; used as the starting point for new isotopomer definitions' self.abundanceButton = Button(frame, text='Set Default\nAbundances', borderwidth=1, command=self.enterDefaultAbundances, grid=(0, 0), tipText=tipText) tipText = 'Sets the basis/default abundances for C, H & N isotopes to their natural abundance proportions' button = Button(frame, text='Set Natural\nAbundance Default', borderwidth=1, command=self.resetDefaultAbundance, grid=(0, 1), sticky='ew', tipText=tipText) label = Label(frame, text='Molecule Type:', grid=(0, 2), sticky='e') entries = standardResidueCcpCodes.keys() entries.sort() entries.reverse() tipText = 'Selects which type of bio-polymer to define residue isotopomer labelling for' self.molTypePulldown = PulldownList(frame, callback=self.setMolType, texts=entries, grid=(0, 3), tipText=tipText) row += 1 tipTexts = [ 'The CCPN code that identifies the kind of residue the isotopomer relates to', 'The number of the particular isotopomer (isotope pattern) within its residue type', 'The fraction of the total residues, of its kind, that the isotopomer make up' ] headingList = ['Ccp Code', 'Variant', 'Weight'] self.isotopomerWeightEntry = FloatEntry( self, text='', returnCallback=self.setIsotopomerWeight, width=6) editWidgets = [None, None, self.isotopomerWeightEntry] editGetCallbacks = [None, None, self.getIsotopomerWeight] editSetCallbacks = [None, None, self.setIsotopomerWeight] self.isotopomerMatrix = ScrolledMatrix( frameB, tipTexts=tipTexts, headingList=headingList, callback=self.selectIsotopomer, editWidgets=editWidgets, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, multiSelect=True, grid=(row, 0)) self.isotopomerMatrix.doEditMarkExtraRules = self.isotopomerEditRules row += 1 frame = Frame(frameB, grid=(row, 0), sticky='ew') frame.expandGrid(0, 0) tipTexts = [ 'Delete the selected residue isotopomers from the current isotope scheme', 'Make a new residue isotopomer definition by copying the details of the last selected isotopomer', 'Add a complete set of isotopomers to the isotope scheme, one for each residue type, based on the states default isotope abundances', 'For all residue isotopomers in the scheme, set the labelling of one kind of atom (the user is prompted) to its default isotopic incorporation ', 'Add a new residue isotopomer definition that uses the default isotopic incorporation' ] texts = [ 'Delete\nSelected', 'Copy\nSelected', 'Add Default\nAbundance Set', 'Set Atom Type\nTo Default', 'Add\nNew:' ] commands = [ self.removeIsotopomers, self.duplicateResidues, self.addDefaultIsotopomers, self.setAtomTypeDefault, self.addNewIsotopomer ] self.isotopomerButtons = ButtonList(frame, texts=texts, commands=commands, grid=(0, 0), tipTexts=tipTexts) tipText = 'Selects which kind of residue isotopomer may be added to the current isotope scheme' self.ccpCodePulldown = PulldownList(frame, callback=None, grid=(0, 1), sticky='e', tipText=tipText) row += 1 div = LabelDivider(frameB, text='Atom Labels', grid=(row, 0)) row += 1 frame = Frame(frameB, grid=(row, 0)) frame.expandGrid(1, 3) label = Label(frame, text='Chemical Element:', grid=(0, 0)) tipText = 'Selects which kind of atoms to select from the selected residue isotopomer; to display isotopic incorporation in the below table' self.elementPulldown = PulldownList(frame, callback=self.changeChemElement, grid=(0, 1), tipText=tipText) self.updateChemElements() label = Label(frame, text='Water Exchangeable Atoms:', grid=(0, 2)) tipText = 'Sets whether to show atoms considered as being "water exchangeable"; their isotopic labelling will rapidly equilibrate with aqueous solvent' self.exchangeCheck = CheckButton(frame, callback=self.updateAtomLabelsAfter, grid=(0, 3), selected=False, tipText=tipText) row += 1 # Tip texts set on update headingList = [ 'Atom\nName', 'Weighting\n13C' 'Weighting\n12C', '%12C', '%13C' ] self.atomLabelTupleWeightEntry = FloatEntry( self, text='', width=6, returnCallback=self.setAtomLabelWeight) self.atomsMatrix = ScrolledMatrix(frameB, headingList=headingList, callback=self.selectAtomLabel, multiSelect=True, grid=(row, 0)) self.atomsMatrix.doEditMarkExtraRules = self.atomsEditRules row += 1 tipTexts = [ 'For the selected atom sites, in the current isotopomer, set their isotopic incorporation to the default values', 'Spread the isotopic incorporation values from the last selected atom site to all selected atoms sites' ] texts = ['Reset Selected to Default Abundance', 'Propagate Abundances'] commands = [self.setAtomLabelsDefault, self.propagateAbundances] self.atomButtons = ButtonList(frameB, texts=texts, commands=commands, grid=(row, 0), tipTexts=tipTexts) # # View Frame # frameC.expandGrid(1, 0) row = 0 frame = Frame(frameC, grid=(row, 0), sticky='ew') frame.grid_columnconfigure(3, weight=1) label = Label(frame, text='Residue Type:', grid=(0, 0)) tipText = 'Selects which kind of residue, within the current isotope scheme, to show isotopomer structures for' self.viewCcpCodePulldown = PulldownList( frame, callback=self.selectViewCcpcode, grid=(0, 1), tipText=tipText) label = Label(frame, text='Isotopomer:', grid=(0, 2)) tipText = 'Selects which kind of isotopomer (labelling pattern) to display, from the selected residue type.' self.viewIsotopomerPulldown = PulldownList( frame, callback=self.selectViewIsotopomer, grid=(0, 3), tipText=tipText) row += 1 self.viewIsotopomerFrame = ViewIsotopomerFrame(frameC, None, grid=(row, 0)) # # Main # tipTexts = [ 'Save all changes to the reference isotope scheme to disk; the saves ALL changes to the CCPN installation for all projects to use', ] texts = ['Save Schemes'] commands = [self.saveSchemes] self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, texts=texts, commands=commands, helpUrl=self.help_url, grid=(0, 0), sticky='e', tipTexts=tipTexts) self.updateChemElements() self.updateCcpCodes() self.updateSchemes() self.administerNotifiers(self.registerNotify) def atomsEditRules(self, atomLabel, row, col): if self.scheme: return isSchemeEditable(self.scheme) else: return False def isotopomerEditRules(self, isotopomer, row, col): if self.scheme: return isSchemeEditable(self.scheme) else: return False def schemeEditRules(self, scheme, row, col): return isSchemeEditable(scheme) def administerNotifiers(self, notifyFunc): for func in ('__init__', 'delete', 'setLongName', 'setDetails'): for clazz in ('ccp.molecule.ChemCompLabel.LabelingScheme', ): notifyFunc(self.updateSchemes, clazz, func) for func in ('__init__', 'delete', 'setWeight'): notifyFunc(self.updateIsotopomersAfter, 'ccp.molecule.ChemCompLabel.Isotopomer', func) notifyFunc(self.updateAtomLabelsAfter, 'ccp.molecule.ChemCompLabel.AtomLabel', func) def getCcpCodeIsotopomers(self, ccpCode): chemCompLabel = self.scheme.findFirstChemCompLabel( molType=self.molType, ccpCode=ccpCode) if chemCompLabel: isotopomers = list(chemCompLabel.isotopomers) else: isotopomers = [] return isotopomers def selectViewCcpcode(self, ccpCode): if ccpCode != self.ccpCodeV: self.ccpCodeV = ccpCode self.isotopomerV = False self.updateViewIsotopomerPulldown() def selectViewIsotopomer(self, isotopomer): self.isotopomerV = isotopomer if isotopomer is None: isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV) else: isotopomers = [ isotopomer, ] self.viewIsotopomerFrame.setIsotopomers(isotopomers) def updateViewCcpCodePulldown(self): if self.scheme: codes = self.getCcpCodes(self.molType) if self.ccpCodeV not in codes: self.ccpCodeV = codes[0] self.isotopomerV = False # Not None self.updateViewIsotopomerPulldown() index = codes.index(self.ccpCodeV) else: codes = [] index = 0 self.viewCcpCodePulldown.setup(codes, codes, index) def updateViewIsotopomerPulldown(self): index = 0 isotopomers = [] names = [] if self.scheme: isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV) names = ['%d' % i.serial for i in isotopomers] isotopomers.insert(0, None) names.insert(0, '<All>') if self.isotopomerV not in isotopomers: self.isotopomerV = None isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV) self.viewIsotopomerFrame.setIsotopomers(isotopomers) self.viewIsotopomerPulldown.setup(names, isotopomers, index) def updateButtons(self): buttonsA = self.schemeButtons.buttons buttonsB = self.isotopomerButtons.buttons buttonsC = self.atomButtons.buttons if self.scheme: buttonsA[0].enable() isEditable = isSchemeEditable(self.scheme) if isEditable: buttonsA[1].enable() else: buttonsA[1].disable() buttonsB[2].enable() buttonsB[3].enable() self.bottomButtons.buttons[0].enable() if isEditable: if self.isotopomer: for button in buttonsB: button.enable() for button in buttonsC: button.enable() else: buttonsB[0].disable() buttonsB[1].disable() buttonsB[3].disable() buttonsC[0].disable() buttonsC[1].disable() buttonsB[2].enable() buttonsB[4].enable() else: for button in buttonsB: button.disable() for button in buttonsC: button.disable() else: buttonsA[0].disable() buttonsA[1].disable() for button in buttonsB: button.disable() for button in buttonsC: button.disable() self.bottomButtons.buttons[0].disable() def resetDefaultAbundance(self): self.defaultAbun = {} def setDefaultAbundances(self, values): self.abundanceWidget.place_forget() if values is not None: i = 0 for element in elementSymbols: # TBD getAllIsotopes for code, isotope in getSortedIsotopes(self.project, element): self.defaultAbun[isotope] = values[i] i += 1 def enterDefaultAbundances(self): x = self.isotopomerFrame.winfo_x() y = self.isotopomerFrame.winfo_y() x0 = self.abundanceButton.winfo_x() y0 = self.abundanceButton.winfo_y() values = [] options = [] for element in elementSymbols: # TBD getAllIsotopes for code, isotope in getSortedIsotopes(self.project, element): options.append(code + ':') values.append( self.defaultAbun.get(isotope, 100.0 * isotope.abundance)) N = len(values) self.abundanceWidget.maxRows = N self.abundanceWidget.minRows = N self.abundanceWidget.set(values=values, options=options) self.abundanceWidget.place(x=x + x0, y=y + y0) def selectAtomLabel(self, obj, row, col): self.atomLabelTuple = (obj, col) def setMolType(self, molType): if molType != self.molType: self.molType = molType self.isotopomer = None self.updateCcpCodes() self.updateIsotopomers() def getCcpCodes(self, molType): codes = [] for code in standardResidueCcpCodes[molType]: codes.append(code) codes.sort() return codes def updateCcpCodes(self): codes = self.getCcpCodes(self.molType) if self.isotopomer: index = codes.index(self.isotopomer.ccpCode) else: index = 0 self.ccpCodePulldown.setup(codes, codes, index) def setIsotopomerWeight(self, event): value = self.isotopomerWeightEntry.get() if value is not None: self.isotopomer.setWeight(abs(value)) def getIsotopomerWeight(self, isotopomer): if isotopomer: self.isotopomerWeightEntry.set(isotopomer.weight) def setSchemeName(self, event): text = self.schemeNameEntry.get() if text: text = text.strip() or None else: text = None self.scheme.setLongName(text) def getSchemeName(self, scheme): if scheme: self.schemeNameEntry.set(scheme.longName) def getSchemeDetails(self, scheme): if scheme: self.schemeDetailsEntry.set(scheme.details) def setSchemeDetails(self, event): text = self.schemeDetailsEntry.get() if text: text = text.strip() or None else: text = None self.scheme.setDetails(text) def updateSchemes(self, obj=None): textMatrix = [] objectList = [] for labelingScheme in self.project.sortedLabelingSchemes(): repository = labelingScheme.findFirstActiveRepository() if repository: saveLocation = repository.name else: saveLocation = None line = [ labelingScheme.name, labelingScheme.longName, labelingScheme.details, saveLocation ] textMatrix.append(line) objectList.append(labelingScheme) self.schemeMatrix.update(textMatrix=textMatrix, objectList=objectList) self.updateSchemePulldown() self.updateIsotopomers() def updateSchemePulldown(self): scheme = self.scheme schemes = self.project.sortedLabelingSchemes() names = [ls.longName or ls.name for ls in schemes] if names: if scheme not in schemes: scheme = schemes[0] index = schemes.index(scheme) else: index = 0 scheme = None self.setLabellingScheme(scheme) self.schemePulldown.setup(names, schemes, index) def copyScheme(self): if self.scheme: name = askString('Input text', 'New Scheme Code:', '', parent=self) scheme = self.project.findFirstLabelingScheme(name=name) if scheme: showWarning('Failure', 'Scheme name already in use') return if name: newScheme = copySubTree(self.scheme, self.project, topObjectParameters={'name': name}) else: showWarning('Failure', 'No name specified') else: showWarning('Failure', 'No scheme selected to copy') def removeScheme(self): if self.scheme and isSchemeEditable(self.scheme): self.scheme.delete() self.scheme = None def makeNewScheme(self): name = askString('Input text', 'New Scheme Code:', '', parent=self) if name: scheme = self.project.findFirstLabelingScheme(name=name) if scheme: showWarning('Failure', 'Scheme name already in use') else: scheme = self.project.newLabelingScheme(name=name) self.scheme = scheme else: showWarning('Failure', 'No name specified') def setLabellingScheme(self, scheme): if scheme is not self.scheme: self.scheme = scheme self.isotopomerV = False self.isotopomer = None self.updateIsotopomers() def selectScheme(self, object, row, col): self.setLabellingScheme(object) self.updateSchemePulldown() def open(self): BasePopup.open(self) self.updateSchemes() def saveSchemes(self): schemes = [x for x in self.project.labelingSchemes if x.isModified] if schemes: for scheme in schemes: scheme.save() showInfo('Notice', 'Successfully saved %d schemes' % len(schemes)) self.updateSchemes() else: showWarning('Notice', 'No modified schemes to save') def addNewIsotopomer(self): if self.scheme: ccpCode = self.ccpCodePulldown.getObject() chemCompLabel = self.getChemCompLabel(self.molType, ccpCode) self.makeIsotopomer(chemCompLabel) def makeIsotopomer(self, chemCompLabel, weight=1.0): isotopomer = chemCompLabel.newIsotopomer(weight=weight) chemComp = chemCompLabel.chemComp for chemAtom in chemComp.chemAtoms: if chemAtom.elementSymbol: chemElement = chemAtom.chemElement for isotope in chemElement.isotopes: code = '%d%s' % (isotope.massNumber, chemAtom.elementSymbol) weight = self.defaultAbun.get(isotope, 100.0 * isotope.abundance) isotopomer.newAtomLabel(name=chemAtom.name, subType=chemAtom.subType, isotopeCode=code, weight=weight) return isotopomer def getChemCompLabel(self, molType, ccpCode): chemCompLabel = None if self.scheme: chemCompLabel = self.scheme.findFirstChemCompLabel(molType=molType, ccpCode=ccpCode) if not chemCompLabel: chemCompLabel = self.scheme.newChemCompLabel(molType=molType, ccpCode=ccpCode) return chemCompLabel def selectIsotopomer(self, obj, row, col): self.isotopomer = obj self.updateChemElements() self.updateAtomLabels() def updateIsotopomersAfter(self, obj=None): if self.waiting: return else: self.waiting = True self.after_idle(self.updateIsotopomers) def updateIsotopomers(self): self.updateViewCcpCodePulldown() self.updateViewIsotopomerPulldown() textMatrix = [] objectList = [] if self.scheme: chemCompLabels = [(label.ccpCode, label) for label in self.scheme.chemCompLabels] chemCompLabels.sort() for key, chemCompLabel in chemCompLabels: if chemCompLabel.molType == self.molType: for isotopomer in chemCompLabel.sortedIsotopomers(): line = [ chemCompLabel.ccpCode, isotopomer.serial, isotopomer.weight ] textMatrix.append(line) objectList.append(isotopomer) self.isotopomerMatrix.update(textMatrix=textMatrix, objectList=objectList) self.updateAtomLabelsAfter() self.waiting = False def setAtomTypeDefault(self): if self.scheme: atomName = askString( 'Query', 'Specify atom name to set\ndefault abundance for', 'H', parent=self) if not atomName: return atomLabels = [] for chemCompLabel in self.scheme.chemCompLabels: if chemCompLabel.molType == self.molType: for isotopomer in chemCompLabel.isotopomers: # Multiple because of isotopes and subTypes atomLabels += isotopomer.findAllAtomLabels( name=atomName) if atomLabels: for atomLabel in atomLabels: isotope = atomLabel.isotope weight = self.defaultAbun.get(isotope, 100.0 * isotope.abundance) atomLabel.weight = weight else: data = (atomName, self.scheme.name) msg = 'Atom name %s does not match any atoms in %s scheme isotopomers' % data showWarning('Failure', msg) def addDefaultIsotopomers(self): if self.scheme: codes = self.getCcpCodes(self.molType) for ccpCode in codes: chemCompLabel = self.getChemCompLabel(self.molType, ccpCode) if not chemCompLabel.isotopomers: self.makeIsotopomer(chemCompLabel) def removeIsotopomers(self): isotopomers = self.isotopomerMatrix.currentObjects if isotopomers: for isotopomer in isotopomers: isotopomer.delete() self.isotopomer = None def duplicateResidues(self): isotopomers = self.isotopomerMatrix.currentObjects for isotopomer in isotopomers: chemCompLabel = isotopomer.chemCompLabel new = copySubTree(isotopomer, chemCompLabel) def updateChemElements(self): if self.isotopomer: chemCompLabel = self.isotopomer.chemCompLabel elementDict = {} for chemAtom in chemCompLabel.chemComp.chemAtoms: symbol = chemAtom.elementSymbol if symbol: elementDict[symbol] = True names = elementDict.keys() names.sort() else: names = ['C', 'N', 'H'] if self.element not in names: index = 0 else: index = names.index(self.element) self.elementPulldown.setup(names, names, index) def updateAtomLabelsAfter(self, obj=None): if self.waitingAtom: return else: self.waitingAtom = True self.after_idle(self.updateAtomLabels) def updateAtomLabels(self): element = self.elementPulldown.getText() textMatrix = [] objectList = [] headingList = [ 'Atom Name', ] tipTexts = [ 'The name of the atom within its residue, for which to set isotopic abundances, within the selected isotopomer', ] isotopeCodes = [x[0] for x in getSortedIsotopes(self.project, element)] headingList.extend(['Weighting\n%s' % x for x in isotopeCodes]) tip = 'The amount of %s isotope incorporation; can be a ratio, percentage or fraction (the value used is relative to the sum of all weights)' tipTexts.extend([tip % x for x in isotopeCodes]) tip = 'The percentage %s isotope incorporation, calculated using stated weights' headingList.extend(['%%%s' % x for x in isotopeCodes]) tipTexts.extend([tip % x for x in isotopeCodes]) editWidgets = [ None, ] editGetCallbacks = [ None, ] editSetCallbacks = [ None, ] editWidgets.extend( [self.atomLabelTupleWeightEntry for x in isotopeCodes]) editGetCallbacks.extend( [self.getAtomLabelWeight for x in isotopeCodes]) editSetCallbacks.extend( [self.setAtomLabelWeight for x in isotopeCodes]) editWidgets.extend([None for x in isotopeCodes]) editGetCallbacks.extend([None for x in isotopeCodes]) editSetCallbacks.extend([None for x in isotopeCodes]) doExchangeable = self.exchangeCheck.get() if self.isotopomer: atomDict = {} for atomLabel in self.isotopomer.sortedAtomLabels(): if atomLabel.chemAtom.elementSymbol == element: if (not doExchangeable) and ( atomLabel.chemAtom.waterExchangeable): continue name = atomLabel.name subType = atomLabel.subType atomDict[(name, subType)] = True atomNames = atomDict.keys() atomNames = greekSortAtomNames(atomNames) for atomName, subType in atomNames: if subType == 1: name = atomName else: name = '%s:%d' % (atomName, subType) line = [ name, ] atomLabels = [] sumWeights = 0.0 for isotope in isotopeCodes: atomLabel = self.isotopomer.findFirstAtomLabel( name=atomName, subType=subType, isotopeCode=isotope) atomLabels.append(atomLabel) if atomLabel: weight = atomLabel.weight sumWeights += weight line.append(weight) else: line.append(0.0) if sumWeights: for atomLabel in atomLabels: line.append(100.0 * atomLabel.weight / sumWeights) else: for atomLabel in atomLabels: line.append(None) textMatrix.append(line) objectList.append(atomLabels) self.atomsMatrix.update(textMatrix=textMatrix, objectList=objectList, headingList=headingList, tipTexts=tipTexts, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.waitingAtom = False self.updateButtons() def setAtomLabelWeight(self, event): value = self.atomLabelTupleWeightEntry.get() if value is not None: atomLabels, col = self.atomLabelTuple chemAtom = None for label in atomLabels: if label: chemAtom = label.chemAtom break atomLabel = atomLabels[col - 1] if chemAtom and (atomLabel is None): isotopeCode, isotope = getSortedIsotopes( self.project, chemAtom.elementSymbol)[col - 1] atomLabel = self.isotopomer.newAtomLabel( name=chemAtom.name, subType=chemAtom.subType, isotopeCode=isotopeCode, weight=value) atomLabel.setWeight(value) def setAtomLabelsDefault(self): atomLabelTuples = self.atomsMatrix.currentObjects for atomLabels in atomLabelTuples: for atomLabel in atomLabels: isotope = atomLabel.isotope weight = self.defaultAbun.get(isotope, 100.0 * isotope.abundance) atomLabel.weight = weight def propagateAbundances(self): atomLabels, col = self.atomLabelTuple atomLabelTuples = self.atomsMatrix.currentObjects weightDict = {} for atomLabel in atomLabels: weightDict[atomLabel.isotope] = atomLabel.weight for atomLabels0 in atomLabelTuples: if atomLabels0 != atomLabels: for atomLabel in atomLabels0: atomLabel.weight = weightDict[atomLabel.isotope] def getAtomLabelWeight(self, null): atomLabels, col = self.atomLabelTuple if atomLabels and (col > 0): atomLabel = atomLabels[col - 1] if atomLabel is None: weight = 0.0 else: weight = atomLabel.weight self.atomLabelTupleWeightEntry.set(weight) def changeChemElement(self, name): self.element = name self.isotopes = [x[0] for x in getSortedIsotopes(self.project, name)] self.updateAtomLabels() def destroy(self): self.administerNotifiers(self.unregisterNotify) BasePopup.destroy(self)
def body(self, guiFrame): self.geometry('700x600') guiFrame.expandGrid(0, 0) tipTexts = [ 'A table of all of the reference isotope scheme definitions available to the project', 'A list of the residue isotopomers that comprise the selected isotope labelling scheme', 'A three-dimensional representation of residues and their isotopomer labelling' ] options = ['Reference Schemes', 'Isotopomers', 'Isotopomer Structure'] tabbedFrame = TabbedFrame(guiFrame, options=options, grid=(0, 0), tipTexts=tipTexts) self.tabbedFrame = tabbedFrame frameA, frameB, frameC = tabbedFrame.frames # # Schemes # frameA.expandGrid(0, 0) tipTexts = [ 'A short textual code that identifies the reference isotope scheme in graphical displays', 'The full name for the isotope scheme', 'A detailed description of the isotope scheme including user comments', 'The name of the CCPN data repository in which the isotope scheme is saved; "refData" is in the CCPn installation' ] headingList = ['Code', 'Name', 'Description', 'Save Location'] self.schemeNameEntry = Entry(self, text='', returnCallback=self.setSchemeName, width=20) self.schemeDetailsEntry = Entry(self, text='', returnCallback=self.setSchemeDetails, width=20) editWidgets = [ None, self.schemeNameEntry, self.schemeDetailsEntry, None ] editGetCallbacks = [ None, self.getSchemeName, self.getSchemeDetails, None ] editSetCallbacks = [ None, self.setSchemeName, self.setSchemeDetails, None ] self.schemeMatrix = ScrolledMatrix(frameA, headingList=headingList, callback=self.selectScheme, editWidgets=editWidgets, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, multiSelect=False, grid=(0, 0), tipTexts=tipTexts) self.schemeMatrix.doEditMarkExtraRules = self.schemeEditRules tipTexts = [ 'Make a new reference isotope scheme definition based on a copy of the scheme currently selected', 'Delete the selected isotope scheme', 'Make a new, blank isotope scheme' ] texts = ['Copy', 'Delete', 'New'] commands = [self.copyScheme, self.removeScheme, self.makeNewScheme] self.schemeButtons = ButtonList(frameA, texts=texts, commands=commands, grid=(1, 0), tipTexts=tipTexts) # # Isotopomers # frameB.expandGrid(3, 0) row = 0 frame = Frame(frameB, grid=(row, 0)) frame.expandGrid(0, 2) tipText = 'Selects which of the available isotope schemes to view/edit' label = Label(frame, text='Reference Scheme:', grid=(0, 0)) self.schemePulldown = PulldownList(frame, callback=self.setLabellingScheme, grid=(0, 1), tipText=tipText) row += 1 div = LabelDivider(frameB, text='Isotopomers', grid=(row, 0)) row += 1 frame = Frame(frameB, grid=(row, 0)) frame.expandGrid(1, 2) self.isotopomerFrame = frame self.abundanceWidget = MultiWidget(self, FloatEntry, relief='raised', borderwidth=2, callback=self.setDefaultAbundances, useImages=False) tipText = 'Opens a panel that allows you to set the basis/default abundances for C, H & N isotopes; used as the starting point for new isotopomer definitions' self.abundanceButton = Button(frame, text='Set Default\nAbundances', borderwidth=1, command=self.enterDefaultAbundances, grid=(0, 0), tipText=tipText) tipText = 'Sets the basis/default abundances for C, H & N isotopes to their natural abundance proportions' button = Button(frame, text='Set Natural\nAbundance Default', borderwidth=1, command=self.resetDefaultAbundance, grid=(0, 1), sticky='ew', tipText=tipText) label = Label(frame, text='Molecule Type:', grid=(0, 2), sticky='e') entries = standardResidueCcpCodes.keys() entries.sort() entries.reverse() tipText = 'Selects which type of bio-polymer to define residue isotopomer labelling for' self.molTypePulldown = PulldownList(frame, callback=self.setMolType, texts=entries, grid=(0, 3), tipText=tipText) row += 1 tipTexts = [ 'The CCPN code that identifies the kind of residue the isotopomer relates to', 'The number of the particular isotopomer (isotope pattern) within its residue type', 'The fraction of the total residues, of its kind, that the isotopomer make up' ] headingList = ['Ccp Code', 'Variant', 'Weight'] self.isotopomerWeightEntry = FloatEntry( self, text='', returnCallback=self.setIsotopomerWeight, width=6) editWidgets = [None, None, self.isotopomerWeightEntry] editGetCallbacks = [None, None, self.getIsotopomerWeight] editSetCallbacks = [None, None, self.setIsotopomerWeight] self.isotopomerMatrix = ScrolledMatrix( frameB, tipTexts=tipTexts, headingList=headingList, callback=self.selectIsotopomer, editWidgets=editWidgets, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, multiSelect=True, grid=(row, 0)) self.isotopomerMatrix.doEditMarkExtraRules = self.isotopomerEditRules row += 1 frame = Frame(frameB, grid=(row, 0), sticky='ew') frame.expandGrid(0, 0) tipTexts = [ 'Delete the selected residue isotopomers from the current isotope scheme', 'Make a new residue isotopomer definition by copying the details of the last selected isotopomer', 'Add a complete set of isotopomers to the isotope scheme, one for each residue type, based on the states default isotope abundances', 'For all residue isotopomers in the scheme, set the labelling of one kind of atom (the user is prompted) to its default isotopic incorporation ', 'Add a new residue isotopomer definition that uses the default isotopic incorporation' ] texts = [ 'Delete\nSelected', 'Copy\nSelected', 'Add Default\nAbundance Set', 'Set Atom Type\nTo Default', 'Add\nNew:' ] commands = [ self.removeIsotopomers, self.duplicateResidues, self.addDefaultIsotopomers, self.setAtomTypeDefault, self.addNewIsotopomer ] self.isotopomerButtons = ButtonList(frame, texts=texts, commands=commands, grid=(0, 0), tipTexts=tipTexts) tipText = 'Selects which kind of residue isotopomer may be added to the current isotope scheme' self.ccpCodePulldown = PulldownList(frame, callback=None, grid=(0, 1), sticky='e', tipText=tipText) row += 1 div = LabelDivider(frameB, text='Atom Labels', grid=(row, 0)) row += 1 frame = Frame(frameB, grid=(row, 0)) frame.expandGrid(1, 3) label = Label(frame, text='Chemical Element:', grid=(0, 0)) tipText = 'Selects which kind of atoms to select from the selected residue isotopomer; to display isotopic incorporation in the below table' self.elementPulldown = PulldownList(frame, callback=self.changeChemElement, grid=(0, 1), tipText=tipText) self.updateChemElements() label = Label(frame, text='Water Exchangeable Atoms:', grid=(0, 2)) tipText = 'Sets whether to show atoms considered as being "water exchangeable"; their isotopic labelling will rapidly equilibrate with aqueous solvent' self.exchangeCheck = CheckButton(frame, callback=self.updateAtomLabelsAfter, grid=(0, 3), selected=False, tipText=tipText) row += 1 # Tip texts set on update headingList = [ 'Atom\nName', 'Weighting\n13C' 'Weighting\n12C', '%12C', '%13C' ] self.atomLabelTupleWeightEntry = FloatEntry( self, text='', width=6, returnCallback=self.setAtomLabelWeight) self.atomsMatrix = ScrolledMatrix(frameB, headingList=headingList, callback=self.selectAtomLabel, multiSelect=True, grid=(row, 0)) self.atomsMatrix.doEditMarkExtraRules = self.atomsEditRules row += 1 tipTexts = [ 'For the selected atom sites, in the current isotopomer, set their isotopic incorporation to the default values', 'Spread the isotopic incorporation values from the last selected atom site to all selected atoms sites' ] texts = ['Reset Selected to Default Abundance', 'Propagate Abundances'] commands = [self.setAtomLabelsDefault, self.propagateAbundances] self.atomButtons = ButtonList(frameB, texts=texts, commands=commands, grid=(row, 0), tipTexts=tipTexts) # # View Frame # frameC.expandGrid(1, 0) row = 0 frame = Frame(frameC, grid=(row, 0), sticky='ew') frame.grid_columnconfigure(3, weight=1) label = Label(frame, text='Residue Type:', grid=(0, 0)) tipText = 'Selects which kind of residue, within the current isotope scheme, to show isotopomer structures for' self.viewCcpCodePulldown = PulldownList( frame, callback=self.selectViewCcpcode, grid=(0, 1), tipText=tipText) label = Label(frame, text='Isotopomer:', grid=(0, 2)) tipText = 'Selects which kind of isotopomer (labelling pattern) to display, from the selected residue type.' self.viewIsotopomerPulldown = PulldownList( frame, callback=self.selectViewIsotopomer, grid=(0, 3), tipText=tipText) row += 1 self.viewIsotopomerFrame = ViewIsotopomerFrame(frameC, None, grid=(row, 0)) # # Main # tipTexts = [ 'Save all changes to the reference isotope scheme to disk; the saves ALL changes to the CCPN installation for all projects to use', ] texts = ['Save Schemes'] commands = [self.saveSchemes] self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, texts=texts, commands=commands, helpUrl=self.help_url, grid=(0, 0), sticky='e', tipTexts=tipTexts) self.updateChemElements() self.updateCcpCodes() self.updateSchemes() self.administerNotifiers(self.registerNotify)