def destroy(self): for func in notify_funcs: Implementation.unregisterNotify(self.setColors, 'ccpnmr.Analysis.Color', func) PulldownList.destroy(self)
def __init__(self, parent, selected=None, isOpenGL=False, callback=None, *args, **kw): self.isOpenGL = isOpenGL PulldownList.__init__(self, parent, callback, *args, **kw) texts = [] cats = [] if isOpenGL: index = 0 # Helvetica 10 for name in glNames: for size in glSizes[name]: text = '%s %d' % (name, size) texts.append(text) cats.append(name) else: index = 2 # Helvetica 10 for name in tkNames: for size in tkSizes: text = '%s %d' % (name, size) texts.append(text) cats.append(name) if selected in texts: index = texts.index(selected) PulldownList.setup(self, texts, texts, index, categories=cats)
def body(self, guiFrame): guiFrame.grid_rowconfigure(0, weight=1) guiFrame.grid_columnconfigure(1, weight=1) row = 0 if self.message: label = Label(guiFrame, text=self.message, gridSpan=(1, 2), grid=(row, 0)) row += 1 if self.label: label = Label(guiFrame, text=self.label, grid=(row, 0)) self.itemMenu = PulldownList(guiFrame, texts=self.entries, objects=self.entries, index=self.default, grid=(row, 1)) row += 1 texts = [self.select_text, 'Cancel'] commands = [self.ok, self.cancel] buttons = ButtonList(guiFrame, texts=texts, commands=commands, gridSpan=(1, 2), grid=(row, 0))
def body(self, master): # # Popup window # row = 0 if self.topText: label = Label(master, text= self.topText) label.grid(row=row, column=0, columnspan = 2, sticky=Tkinter.EW) row = row + 1 label = Label(master, text= self.text) label.grid(row=row, column=0, sticky=Tkinter.EW) self.menu = PulldownList(master, texts = self.selectionList, index = self.selectedIndex) self.menu.grid(row=row, column=1, sticky=Tkinter.E, ipadx = 20) row = row + 1 texts = [ 'OK' ] commands = [ self.ok ] # This calls 'ok' in BasePopup, this then calls 'apply' in here if self.dismissButton: buttons = createDismissHelpButtonList(master, texts=texts, commands=commands, dismiss_text = self.dismissText, help_url=self.help_url) else: buttons = createHelpButtonList(master, texts=texts, commands=commands, help_url=self.help_url) buttons.grid(row=row, column=0, columnspan = 3)
class CreateAxisPopup(BasePopup): def __init__(self, parent, **kw): self.axisType = None BasePopup.__init__(self, parent=parent, title='Create window axis', modal=True, transient=False, **kw) def body(self, master): row = 0 label = Label(master, text='Axis type: ', grid=(row, 0)) tipText = 'Selects what type of measurement is displayed along the window axis' self.type_list = PulldownList(master, tipText=tipText, grid=(row, 1)) row += 1 tipTexts = ['Make an axis of the selected type in the window & close this popup'] texts = [ 'Create' ] commands = [ self.ok ] buttons = UtilityButtonList(master, texts=texts, doClone=False, grid=(row, 0), commands=commands, helpUrl=self.help_url, gridSpan=(1,2), tipTexts=tipTexts) self.administerNotifiers(self.registerNotify) self.update() def administerNotifiers(self, notifyFunc): for func in ('__init__', 'delete', 'setName'): notifyFunc(self.update, 'ccpnmr.Analysis.AxisType', func) def destroy(self): self.administerNotifiers(self.unregisterNotify) BasePopup.destroy(self) def update(self, *extra): axisType = self.axisType axisTypes = self.parent.parent.getAxisTypes() names = [x.name for x in axisTypes] if axisTypes: if axisType not in axisTypes: self.axisType = axisType = axisTypes[0] index = axisTypes.index(axisType) else: index = 0 self.axisType = None self.type_list.setup(names, axisTypes, index) def apply(self): self.axisType = self.type_list.getObject() return True
def body(self, master): self.geometry('600x130') master.grid_columnconfigure(1, weight=1) for n in range(5): master.grid_rowconfigure(n, weight=1) row = 0 label = Label(master, text='Spectrum: ') label.grid(row=row, column=0, sticky='e') tipText = 'The spectrum for which the contour file is being added' self.expt_spectrum = PulldownList(master, callback=self.updateContourDir, tipText=tipText) self.expt_spectrum.grid(row=row, column=1, sticky='w') row = row + 1 tipText = 'The location of the directory where contour files are stored on disk' label = Label(master, text='Contour dir: ') label.grid(row=row, column=0, sticky='e') self.dir_label = Label(master, text='', tipText=tipText) self.dir_label.grid(row=row, column=1, sticky='w') row = row + 1 label = Label( master, text= '(file will be copied into Contour dir if it is not already in there)' ) label.grid(row=row, column=1, sticky='w') row = row + 1 tipText = 'Browse for a file store contour data' button = Button(master, text='File name: ', command=self.selectFile, tipText=tipText) button.grid(row=row, column=0, sticky='e') tipText = 'Enter the name of the file to store contour data' self.file_entry = Entry(master, tipText=tipText) self.file_entry.grid(row=row, column=1, sticky='ew') row = row + 1 texts = ['Add File'] commands = [self.addFile] tipTexts = [ 'Use the selected contour file in the current project, copying it to the contour directory if required', ] self.buttons = UtilityButtonList(master, texts=texts, doClone=False, tipTexts=tipTexts, commands=commands, helpUrl=self.help_url) self.buttons.grid(row=row, column=0, columnspan=2, sticky='ew') self.curateNotifiers(self.registerNotify) self.updateSpectrum()
def __init__(self, parent, getColors, extra_label='', *args, **kw): self.getColors = getColors self.extra_label = extra_label PulldownList.__init__(self, parent, *args, **kw) for func in notify_funcs: Implementation.registerNotify(self.setColors, 'ccpnmr.Analysis.Color', func) self.setColors()
def body(self, guiFrame): '''Describes where all the GUI element are.''' self.geometry('400x500') guiFrame.expandGrid(0, 0) tableFrame = Frame(guiFrame) tableFrame.grid( row=0, column=0, sticky='nsew', ) tableFrame.expandGrid(0, 0) buttonFrame = Frame(guiFrame) buttonFrame.grid( row=1, column=0, sticky='nsew', ) headingList = ['Spinsystem Number', 'Assignment', 'Residue Type Probs'] self.table = ScrolledMatrix(tableFrame, headingList=headingList, callback=self.updateSpinSystemSelection, multiSelect=True) self.table.grid(row=0, column=0, sticky='nsew') texts = ['Add Prob'] commands = [self.addProb] self.AddProbButton = ButtonList(buttonFrame, commands=commands, texts=texts) self.AddProbButton.grid(row=0, column=0, sticky='nsew') texts = ['Remove Prob'] commands = [self.removeProb] self.AddProbButton = ButtonList(buttonFrame, commands=commands, texts=texts) self.AddProbButton.grid(row=0, column=2, sticky='nsew') selectCcpCodes = sorted(self.chemCompDict.keys()) tipText = 'select ccpCode' self.selectCcpCodePulldown = PulldownList(buttonFrame, texts=selectCcpCodes, grid=(0, 1), tipText=tipText) selectCcpCodes = ['All Residue Types'] tipText = 'select ccpCode' self.selectCcpCodeRemovePulldown = PulldownList(buttonFrame, texts=selectCcpCodes, index=0, grid=(0, 3), tipText=tipText) self.updateTable()
def body(self, master): row = 0 label = Label(master, text='Axis type: ', grid=(row, 0)) tipText = 'Selects what type of measurement is displayed along the window axis' self.type_list = PulldownList(master, tipText=tipText, grid=(row, 1)) row += 1 tipTexts = ['Make an axis of the selected type in the window & close this popup'] texts = [ 'Create' ] commands = [ self.ok ] buttons = UtilityButtonList(master, texts=texts, doClone=False, grid=(row, 0), commands=commands, helpUrl=self.help_url, gridSpan=(1,2), tipTexts=tipTexts) self.administerNotifiers(self.registerNotify) self.update()
def __init__(self, parent, callback=None, *args, **kw): fkey_entries = ['F%d' % (n + 1) for n in range(12)] misc_entries = [ \ 'Home', 'End', 'Prior', 'Next', 'Up', 'Down', 'Right', 'Left', 'Delete', ] # remove 0-9 because used for spectrum shortcuts texts = [no_keysym] categories = [ None, ] objects = [ None, ] for category, sublabels in ( ('a-z', string.lowercase[:26]), ('A-Z', string.uppercase[:26]), #('0-9', string.digits), ('F keys', fkey_entries), ('Misc', misc_entries)): for text in sublabels: texts.append(text) objects.append(text) categories.append(category) PulldownList.__init__(self, parent, callback=callback, texts=texts, objects=objects, categories=categories, *args, **kw)
def body(self): '''Sets up the body of this view.''' frame = self.frame frame.grid_rowconfigure(2, weight=1) frame.grid_columnconfigure(0, weight=1) headingList = [ '#', 'Spectrum', 'Peak List', 'use?', 'labelling scheme' ] tipTexts = [ 'Row number', 'spectrum name', 'which peak list to use', 'use this spectrum?', 'Which labelling scheme belongs to this spectrum?' ] self.autoLabellingPulldown = PulldownList(self.guiParent, self.setAutoLabellingScheme) self.autoPeakListPulldown = PulldownList(self.guiParent, self.setAutoPeakList) editWidgets = [ None, None, self.autoPeakListPulldown, None, self.autoLabellingPulldown ] editGetCallbacks = [ None, None, self.getAutoPeakLists, self.changeUse, self.getAutoLabellingSchemes ] editSetCallbacks = [None, None, None, None, None] self.displayTable = ScrolledMatrix(frame, headingList=headingList, callback=self.selectAutoSpec, editWidgets=editWidgets, multiSelect=False, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, tipTexts=tipTexts) self.displayTable.grid(row=2, column=0, sticky='nsew')
def __init__(self, parent, browser=None, **kw): self.browserList = getBrowserList() if not browser: browser = getDefaultBrowser() if self.browserList: if (not browser) or (browser not in self.browserList): browser = self.browserList[0] self.browser = browser PulldownList.__init__(self, parent, **kw) if self.browserList: self.setup(self.browserList, self.browserList, self.browserList.index(self.browser)) self.callback = self.setWebBrowser
def body(self, guiFrame): guiFrame.grid_rowconfigure(0, weight=1) guiFrame.grid_columnconfigure(0, weight=1) row = 0 frame = LabelFrame(guiFrame, text='Matched Peak Groups') frame.grid_rowconfigure(0, weight=1) frame.grid_columnconfigure(0, weight=1) frame.grid(row=row, sticky='nsew') headingList, tipTexts = self.getHeadingList() self.scrolledMatrix = ScrolledMatrix(frame, initialRows=15, multiSelect=True, headingList=headingList, tipTexts=tipTexts, grid=(0,0), gridSpan=(1,3)) tipTexts = ['Remove the selected peak groups from the table', 'Show 1D positional ruler lines for the selected groups', 'Remove any ruler lines previously added for peak group', 'Display selected peak groups within strips of selected window'] texts = ['Remove\nGroups','Show\nRulers', 'Delete\nRulers','Display Groups\nIn Strips'] commands = [self.removeGroups,self.addRulers, self.removeRulers,self.stripGroups] self.buttons = ButtonList(frame, texts=texts, commands=commands, tipTexts=tipTexts) self.buttons.grid(row=1, column=0, sticky='ew') tipText = 'Selects the spectrum window in which to display strips & ruler lines' label = Label(frame, text='Target window:', grid=(1,1)) self.windowPulldown = PulldownList(frame, callback=None, grid=(1,2), tipText=tipText) row+= 1 bottomButtons = UtilityButtonList(guiFrame, helpUrl=self.help_url, expands=True, doClone=False) bottomButtons.grid(row = row, sticky = 'ew') self.update() for func in ('__init__', 'delete', 'setName'): self.registerNotify(self.updateWindowsAfter, 'ccpnmr.Analysis.SpectrumWindow', func)
def __init__(self, guiParent, dataText, dataObjects, dataValues, helpText, selectionText, **kw): Frame.__init__(self, guiParent, **kw) label = Label(self, text=dataText + ':', grid=(0, 0)) self.selectionList = PulldownList(self, objects=dataObjects, texts=dataValues, grid=(0, 1)) label = Label(self, text=helpText, grid=(1, 0), gridSpan=(1, 2)) label = Label(self, text=selectionText + ':', grid=(2, 0)) self.selectionEntry = Entry(self, grid=(2, 1))
def body(self, master): master.grid_columnconfigure(1, weight=1) row = 0 label = Label(master, text='Panel name: ', grid=(row, 0)) tipText = 'Short text name for the new axis panel, e.g. "N2"' self.name_entry = Entry(master, width=15, grid=(row, 1), tipText=tipText) row += 1 label = Label(master, text='Axis type:', grid=(row, 0)) tipText = 'The type of axis (isotope, time, sampled etc.) represented by panel type' self.types_list = PulldownList(master, grid=(row, 1), tipText=tipText) row += 1 tipTexts = [ 'Create a new panel type object with the selected options & close the popup' ] texts = ['Create'] commands = [self.ok] buttons = UtilityButtonList(master, texts=texts, commands=commands, doClone=False, closeText='Cancel', helpUrl=self.help_url, grid=(row, 0), gridSpan=(1, 2), tipTexts=tipTexts) master.grid_rowconfigure(row, weight=1) self.administerNotifiers(self.registerNotify) self.update()
def body(self): '''Sets up the body of this view.''' frame = self.frame frame.grid_rowconfigure(2, weight=1) frame.grid_columnconfigure(0, weight=1) headingList = [ '#', 'Spectrum', 'Peak List', 'use?', 'labelling scheme'] tipTexts = ['Row number', 'spectrum name', 'which peak list to use', 'use this spectrum?', 'Which labelling scheme belongs to this spectrum?'] self.autoLabellingPulldown = PulldownList( self.guiParent, self.setAutoLabellingScheme) self.autoPeakListPulldown = PulldownList( self.guiParent, self.setAutoPeakList) editWidgets = [None, None, self.autoPeakListPulldown, None, self.autoLabellingPulldown] editGetCallbacks = [None, None, self.getAutoPeakLists, self.changeUse, self.getAutoLabellingSchemes] editSetCallbacks = [None, None, None, None, None] self.displayTable = ScrolledMatrix(frame, headingList=headingList, callback=self.selectAutoSpec, editWidgets=editWidgets, multiSelect=False, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, tipTexts=tipTexts) self.displayTable.grid(row=2, column=0, sticky='nsew')
def body(self, guiParent): self.geometry('320x120') analysisProject = self.analysisProject guiParent.expandGrid(5,3) guiParent.expandGrid(5,4) row = 0 div = LabelDivider(guiParent, text='Multi-dimensional Marks', grid=(row,0), gridSpan=(1,4)) buttons = UtilityButtonList(guiParent, doClone=False, helpUrl=self.help_url) buttons.grid(row=row, column=4, sticky='w') row += 1 label = Label(guiParent, text='Maximum marks: ', grid=(row,0)) values = range(1, self.maxAllowedMarks+1) entries = [ str(x) for x in values] value = analysisProject.maxMarks tipText = 'Sets the maximum number of multi-dimensional cross-marks that the user can add to spectrum window displays' self.marks_menu = PulldownList(guiParent, callback=self.setMaxMarks, grid=(row,1), texts=entries, objects=values, index=value-1, tipText=tipText) label = Label(guiParent, text=' Mark colour: ', grid=(row,2)) tipText = 'Sets the line colour of the multi-dimensional cross-marks, excepting those that go through peak centers' self.marksSchemePulldown = PulldownList(guiParent, callback=self.setMarksColor, grid=(row,3), tipText=tipText) row += 1 label = Label(guiParent, text='(Non-peak marks only)', grid=(row,2), gridSpan=(1,2)) row += 1 div = LabelDivider(guiParent, text='1-dimensional Rulers', grid=(row,0), gridSpan=(1,5)) row += 1 label = Label(guiParent, text='Maximum rulers: ', grid=(row,0)) values = range(1, self.maxAllowedRulers+1) entries = [ str(x) for x in values] value = analysisProject.maxRulers tipText = 'Sets the maximum number of 1-dimensional ruler lines that the user can add to spectrum window displays' self.rulers_menu = PulldownList(guiParent, callback=self.setMaxRulers, grid=(row,1), texts=entries, objects=values, index=value-1, tipText=tipText) label = Label(guiParent, text=' Ruler colour: ', grid=(row,2)) tipText = 'Sets the line colour of the 1-dimensional ruler lines' self.rulersSchemePulldown = PulldownList(guiParent, callback=self.setRulersColor, grid=(row,3), tipText=tipText) self.updateSchemePulldowns()
def body(self, guiFrame): '''Describes where all the GUI element are.''' self.geometry('400x500') guiFrame.expandGrid(0, 0) tableFrame = Frame(guiFrame) tableFrame.grid(row=0, column=0, sticky='nsew', ) tableFrame.expandGrid(0, 0) buttonFrame = Frame(guiFrame) buttonFrame.grid(row=1, column=0, sticky='nsew', ) headingList = ['Spinsystem Number', 'Assignment', 'Residue Type Probs'] self.table = ScrolledMatrix(tableFrame, headingList=headingList, callback=self.updateSpinSystemSelection, multiSelect=True) self.table.grid(row=0, column=0, sticky='nsew') texts = ['Add Prob'] commands = [self.addProb] self.AddProbButton = ButtonList(buttonFrame, commands=commands, texts=texts) self.AddProbButton.grid(row=0, column=0, sticky='nsew') texts = ['Remove Prob'] commands = [self.removeProb] self.AddProbButton = ButtonList(buttonFrame, commands=commands, texts=texts) self.AddProbButton.grid(row=0, column=2, sticky='nsew') selectCcpCodes = sorted(self.chemCompDict.keys()) tipText = 'select ccpCode' self.selectCcpCodePulldown = PulldownList(buttonFrame, texts=selectCcpCodes, grid=(0, 1), tipText=tipText) selectCcpCodes = ['All Residue Types'] tipText = 'select ccpCode' self.selectCcpCodeRemovePulldown = PulldownList(buttonFrame, texts=selectCcpCodes, index=0, grid=(0, 3), tipText=tipText) self.updateTable()
def __init__(self, parent, file_types=None, directory=None, single_callback=None, double_callback=None, select_dir_callback=None, change_dir_callback=None, should_change_dir_callback=None, prompt=None, show_file=True, file='', multiSelect=False, default_dir=None, getRowColor=None, getExtraCell=None, extraHeadings=None, extraJustifies=None, displayExtra=True, manualFileFilter=False, extraTipTexts=None, *args, **kw): if file_types is None: file_types = [FileType("All", ["*"])] if manualFileFilter: self.manualFilter = FileType("Manual") file_types.append(self.manualFilter) else: self.manualFilter = None if directory is None: directory = normalisePath(os.getcwd()) if extraHeadings is None: extraHeadings = () else: extraHeadings = tuple(extraHeadings) if extraJustifies is None: extraJustifies = () else: extraJustifies = tuple(extraJustifies) if extraHeadings or extraJustifies: assert len(extraHeadings) == len(extraJustifies) assert getExtraCell self.extraHeadings = extraHeadings self.extraJustifies = extraJustifies self.extraTipTexts = extraTipTexts or [] self.displayExtra = displayExtra Frame.__init__(self, parent, *args, **kw) self.file_types = file_types self.fileType = file_types[0] self.single_callback = single_callback self.double_callback = double_callback self.select_dir_callback = select_dir_callback self.change_dir_callback = change_dir_callback self.should_change_dir_callback = should_change_dir_callback self.show_file = show_file self.directory = None self.historyBack = [] self.historyFwd = [] self.determineDir(directory) self.default_dir = default_dir self.getRowColor = getRowColor self.getExtraCell = getExtraCell self.grid_columnconfigure(0, weight=1) row = 0 if prompt: label = Label(self, text=prompt, grid=(row, 0)) row += 1 self.grid_rowconfigure(row, weight=1) if show_file: headings = ('Name', 'Size', 'Date') justifies = ('left', 'right', 'right') tipTexts = [ 'Name of file, directory or link', 'Size of file in bytes', 'Date of last modification' ] else: headings = ('Directory', ) justifies = ('left', ) tipTexts = ['Name of directory'] self.normalHeadings = headings self.normalJustifies = justifies self.normalTipTexts = tipTexts headings = headings + extraHeadings justifies = justifies + extraJustifies tipTexts += [None] * len(extraHeadings) self.fileList = ScrolledMatrix(self, headingList=headings, justifyList=justifies, initialRows=10, callback=self.singleCallback, doubleCallback=self.doubleCallback, tipTexts=tipTexts, multiSelect=multiSelect, grid=(row, 0)) row += 1 tipTexts = [ 'Go to previous location in history', 'Go forward in location history', 'Go up one directory level', 'Go to root directory', 'Go to home directory', 'Make a new directory', 'Refresh directory listing' ] texts = ['Back', 'Forward', 'Up', 'Top', 'Home', 'New', 'Refresh'] commands = [ self.backDir, self.fwdDir, self.upDir, self.topDir, self.homeDir, self.createDir, self.updateFileList ] if self.default_dir: texts.append('Default') commands.append(self.setDefaultDir) tipTexts.append('Set the current directory as the default') self.icons = [] for name in ICON_NAMES: icon = Tkinter.PhotoImage( file=os.path.join(GFX_DIR, name + '.gif')) self.icons.append(icon) self.buttons = ButtonList(self, texts=texts, commands=commands, images=self.icons, grid=(row, 0), tipTexts=tipTexts) if show_file: row += 1 self.file_entry = LabeledEntry(self, label='File name', label_width=10, entry_width=40, returnCallback=self.setSelectedFile) self.file_entry.grid(row=row, column=0, sticky=Tkinter.EW) else: self.file_entry = None row += 1 self.directory_entry = LabeledEntry(self, label='Directory', entry=directory, label_width=10, entry_width=40, returnCallback=self.entryDir) self.directory_entry.grid(row=row, column=0, sticky=Tkinter.EW) row += 1 subFrame = Frame(self, grid=(row, 0)) subFrame.expandGrid(None, 6) if show_file: label = Label(subFrame, text='File type:', grid=(0, 0)) type_labels = self.determineTypeLabels() self.fileType_menu = PulldownList( subFrame, callback=self.typeCallback, texts=type_labels, objects=self.file_types, grid=(0, 1), tipText='Restrict listed files to selected suffix') label = Label(subFrame, text=' Show hidden:', grid=(0, 2)) self.hidden_checkbutton = CheckButton( subFrame, text='', selected=False, callback=self.updateFileList, grid=(0, 3), tipText='Show hidden files beginning with "." etc.') label = Label(subFrame, text='Dir path:', grid=(0, 4)) self.pathMenu = PulldownList( subFrame, callback=self.dirCallback, objects=range(len(self.dirs)), texts=self.dirs, index=len(self.dirs) - 1, indent=' ', prefix=dirsep, grid=(0, 5), tipText='Directory navigation to current location') if show_file and self.manualFilter is not None: row += 1 self.manual_filter_entry = LabeledEntry( self, label='Manual Select', entry=defaultFilter, label_width=13, entry_width=40, returnCallback=self.entryFilter, tipText= 'Path specification with wildcards to select multiple files') self.manual_filter_entry.grid(row=row, column=0, sticky=Tkinter.EW) self.updateFileList() self.updateButtons() if file: self.setFile(file)
class FileSelect(Frame): def __init__(self, parent, file_types=None, directory=None, single_callback=None, double_callback=None, select_dir_callback=None, change_dir_callback=None, should_change_dir_callback=None, prompt=None, show_file=True, file='', multiSelect=False, default_dir=None, getRowColor=None, getExtraCell=None, extraHeadings=None, extraJustifies=None, displayExtra=True, manualFileFilter=False, extraTipTexts=None, *args, **kw): if file_types is None: file_types = [FileType("All", ["*"])] if manualFileFilter: self.manualFilter = FileType("Manual") file_types.append(self.manualFilter) else: self.manualFilter = None if directory is None: directory = normalisePath(os.getcwd()) if extraHeadings is None: extraHeadings = () else: extraHeadings = tuple(extraHeadings) if extraJustifies is None: extraJustifies = () else: extraJustifies = tuple(extraJustifies) if extraHeadings or extraJustifies: assert len(extraHeadings) == len(extraJustifies) assert getExtraCell self.extraHeadings = extraHeadings self.extraJustifies = extraJustifies self.extraTipTexts = extraTipTexts or [] self.displayExtra = displayExtra Frame.__init__(self, parent, *args, **kw) self.file_types = file_types self.fileType = file_types[0] self.single_callback = single_callback self.double_callback = double_callback self.select_dir_callback = select_dir_callback self.change_dir_callback = change_dir_callback self.should_change_dir_callback = should_change_dir_callback self.show_file = show_file self.directory = None self.historyBack = [] self.historyFwd = [] self.determineDir(directory) self.default_dir = default_dir self.getRowColor = getRowColor self.getExtraCell = getExtraCell self.grid_columnconfigure(0, weight=1) row = 0 if prompt: label = Label(self, text=prompt, grid=(row, 0)) row += 1 self.grid_rowconfigure(row, weight=1) if show_file: headings = ('Name', 'Size', 'Date') justifies = ('left', 'right', 'right') tipTexts = [ 'Name of file, directory or link', 'Size of file in bytes', 'Date of last modification' ] else: headings = ('Directory', ) justifies = ('left', ) tipTexts = ['Name of directory'] self.normalHeadings = headings self.normalJustifies = justifies self.normalTipTexts = tipTexts headings = headings + extraHeadings justifies = justifies + extraJustifies tipTexts += [None] * len(extraHeadings) self.fileList = ScrolledMatrix(self, headingList=headings, justifyList=justifies, initialRows=10, callback=self.singleCallback, doubleCallback=self.doubleCallback, tipTexts=tipTexts, multiSelect=multiSelect, grid=(row, 0)) row += 1 tipTexts = [ 'Go to previous location in history', 'Go forward in location history', 'Go up one directory level', 'Go to root directory', 'Go to home directory', 'Make a new directory', 'Refresh directory listing' ] texts = ['Back', 'Forward', 'Up', 'Top', 'Home', 'New', 'Refresh'] commands = [ self.backDir, self.fwdDir, self.upDir, self.topDir, self.homeDir, self.createDir, self.updateFileList ] if self.default_dir: texts.append('Default') commands.append(self.setDefaultDir) tipTexts.append('Set the current directory as the default') self.icons = [] for name in ICON_NAMES: icon = Tkinter.PhotoImage( file=os.path.join(GFX_DIR, name + '.gif')) self.icons.append(icon) self.buttons = ButtonList(self, texts=texts, commands=commands, images=self.icons, grid=(row, 0), tipTexts=tipTexts) if show_file: row += 1 self.file_entry = LabeledEntry(self, label='File name', label_width=10, entry_width=40, returnCallback=self.setSelectedFile) self.file_entry.grid(row=row, column=0, sticky=Tkinter.EW) else: self.file_entry = None row += 1 self.directory_entry = LabeledEntry(self, label='Directory', entry=directory, label_width=10, entry_width=40, returnCallback=self.entryDir) self.directory_entry.grid(row=row, column=0, sticky=Tkinter.EW) row += 1 subFrame = Frame(self, grid=(row, 0)) subFrame.expandGrid(None, 6) if show_file: label = Label(subFrame, text='File type:', grid=(0, 0)) type_labels = self.determineTypeLabels() self.fileType_menu = PulldownList( subFrame, callback=self.typeCallback, texts=type_labels, objects=self.file_types, grid=(0, 1), tipText='Restrict listed files to selected suffix') label = Label(subFrame, text=' Show hidden:', grid=(0, 2)) self.hidden_checkbutton = CheckButton( subFrame, text='', selected=False, callback=self.updateFileList, grid=(0, 3), tipText='Show hidden files beginning with "." etc.') label = Label(subFrame, text='Dir path:', grid=(0, 4)) self.pathMenu = PulldownList( subFrame, callback=self.dirCallback, objects=range(len(self.dirs)), texts=self.dirs, index=len(self.dirs) - 1, indent=' ', prefix=dirsep, grid=(0, 5), tipText='Directory navigation to current location') if show_file and self.manualFilter is not None: row += 1 self.manual_filter_entry = LabeledEntry( self, label='Manual Select', entry=defaultFilter, label_width=13, entry_width=40, returnCallback=self.entryFilter, tipText= 'Path specification with wildcards to select multiple files') self.manual_filter_entry.grid(row=row, column=0, sticky=Tkinter.EW) self.updateFileList() self.updateButtons() if file: self.setFile(file) def updateDisplayExtra(self, displayExtra): self.displayExtra = displayExtra self.updateFileList() def isRootDirectory(self, directory=''): if not directory: directory = self.directory if directory: return os.path.dirname(directory) == directory return True # arbitrary def updateButtons(self): buttons = self.buttons.buttons isRoot = self.isRootDirectory if self.historyBack: buttons[0].enable() else: buttons[0].disable() if self.historyFwd: buttons[1].enable() else: buttons[1].disable() if self.directory and not isRoot(self.directory): buttons[2].enable() buttons[3].enable() else: buttons[2].disable() buttons[3].disable() homeDir = self.getHomeDir() if homeDir and os.path.isdir(homeDir): buttons[4].enable() else: buttons[4].disable() def backDir(self): if self.historyBack: self.historyFwd.insert(0, self.directory) dirName = self.historyBack.pop() self.changeDir(dirName, addHistory=False) def fwdDir(self): if self.historyFwd: self.historyBack.append(self.directory) dirName = self.historyFwd.pop(0) self.changeDir(dirName, addHistory=False) def topDir(self): if self.directory: isRoot = self.isRootDirectory dirName = self.directory while not isRoot(dirName): dirName = joinPath(dirName, os.pardir) self.changeDir(dirName) def homeDir(self): homeDir = self.getHomeDir() if homeDir: self.changeDir(homeDir) def getHomeDir(self): return os.environ.get('HOME') or os.environ.get('HOMEPATH') def upDir(self): self.changeDir(joinPath(self.directory, os.pardir)) def setDefaultDir(self): self.changeDir(self.default_dir) def createDir(self): from memops.gui.DataEntry import askString msg = 'Enter new sub-directory name' dirName = askString('New directory', msg, parent=self) if dirName: dirName = joinPath(self.directory, dirName) if os.path.exists(dirName): msg = 'Directory "%s" already exists' % dirName showError('Directory exists', msg, parent=self) else: os.mkdir(dirName) self.updateFileList() def determineTypeLabels(self): type_labels = [] for t in self.file_types: s = t.message + ' (' + ', '.join(t.filters) + ')' type_labels.append(s) return type_labels def setFileTypes(self, file_types): self.file_types = file_types if self.fileType not in file_types: self.fileType = file_types[0] if self.show_file: ind = self.file_types.index(self.fileType) type_labels = self.determineTypeLabels() self.fileType_menu.setup(type_labels, self.file_types, ind) self.updateFileList() def determineDir(self, directory): directory = normalisePath(directory) assert os.path.isdir(directory), '"%s" is not a directory' % directory self.prev_directory = self.directory if not os.path.isabs(directory): if self.directory is None: # first time around directory = joinPath(normalisePath(os.getcwd()), directory) else: directory = joinPath(self.directory, directory) self.directory = directory self.dirs = self.directory.split(dirsep) def setSelectedFile(self, *event): file = self.file_entry.getEntry() try: self.fileList.selectObject(file) except: showError('Some err', 'some err') def entryDir(self, *event): dirName = self.directory_entry.getEntry() try: self.changeDir(dirName) except: showError('Not a directory', '"' + dirName + '" is not a directory.') def entryFilter(self, *event): filterString = self.manual_filter_entry.getEntry() filters = [str.strip(x) for x in filterString.split(',')] self.manualFilter.filters = filters self.fileType = self.manualFilter self.setFileTypes( self.file_types) # to trigger update after filter change self.updateFileList() self.manual_filter_entry.setEntry(filterString) def changeDir(self, dirName, addHistory=True): if not os.path.isdir(dirName): return if self.should_change_dir_callback: if not self.should_change_dir_callback(dirName): return oldDir = self.directory self.determineDir(dirName) self.updateFileList() self.directory_entry.setEntry(self.directory) if self.change_dir_callback: self.change_dir_callback(self.directory) nDirs = len(self.dirs) self.pathMenu.setup(self.dirs, range(nDirs), index=nDirs - 1) if addHistory: if oldDir and (self.directory != oldDir): self.historyBack.append(oldDir) self.historyFwd = [] self.updateButtons() def getEntryInfo(self, entry): file = joinPath(self.directory, entry) if os.path.islink(file): # plain arrow: u' \u2192 ' entry = entry + u' \u21D2 ' + unicode(os.readlink(file), 'utf-8') size = None color = '#E0D0C0' elif os.path.isdir(file): if not self.isRootDirectory(entry): entry = entry + dirsep size = None color = '#C0D0C0' else: color = '#C0C0D0' if self.show_file: try: size = str(os.path.getsize(file)) except: size = None else: size = None try: fileTime = self.fileTime(file) except: fileTime = '' return (entry, size, fileTime, color) def getDrives(self): if isWindowsOS(): #import win32api #drives = win32api.GetLogicalDriveStrings() #drives = drives.split('\x00') #drives = [normalisePath(drive) for drive in drives if drive] #drives.sort() # 19 Mar 2012: do not use win32api because not standard from ctypes import windll import string drives = [] bitmask = windll.kernel32.GetLogicalDrives() for letter in string.ascii_uppercase: if bitmask & 1: drives.append(letter) bitmask >>= 1 drives = [drive + ':\\' for drive in drives] drives = [normalisePath(drive) for drive in drives] else: drives = [] return drives def updateFileList(self, *extra): try: if self.directory: directory = self.directory else: directory = dirsep entries = self.getFilterFiles(directory) except OSError, e: showError('OS Error', str(e)) if self.prev_directory: self.directory = None self.changeDir(self.prev_directory) return if self.directory: if self.isRootDirectory(): entries[:0] = [ drive for drive in self.getDrives() if drive not in self.directory ] else: entries[:0] = [os.pardir ] # add parent directory at front of list # DJOD: Not elegant, but robust !?! showHidden = self.hidden_checkbutton.getSelected() show_ent = [] for entry in entries: if not showHidden: if not entry.startswith('.'): show_ent.append(entry) else: show_ent.append(entry) # if not show_ent.__contains__('.'): # show_ent.append('.') if not show_ent.__contains__('..'): show_ent.insert(0, '..') entries = show_ent textMatrix = [] colorMatrix = [] for entryActual in entries: (entry, size, fileTime, color) = self.getEntryInfo(entryActual) fullEntry = joinPath(directory, entryActual) if self.getRowColor: color = self.getRowColor(fullEntry) if self.displayExtra and self.getExtraCell: data = self.getExtraCell(fullEntry) headingList = self.normalHeadings + self.extraHeadings justifyList = self.normalJustifies + self.extraJustifies tipTexts = self.normalTipTexts + self.extraTipTexts else: data = () headingList = self.normalHeadings justifyList = self.normalJustifies tipTexts = self.normalTipTexts # in case we had sorted on a now removed line : self.fileList.lastSortLine = None if self.show_file: text = [entry, size, fileTime] else: text = [ entry, ] text = text + list(data) textMatrix.append(text) numCols = len(headingList) colorMatrix.append(numCols * [color]) self.fileList.update(objectList=entries, textMatrix=textMatrix, colorMatrix=colorMatrix, headingList=headingList, justifyList=justifyList, tipTexts=tipTexts)
class AssignMentTransferTab(object): '''the tab in the GUI where assignments can be transferred in bulk to the ccpn analysis project. A difference is made between two types of assignments: 1) spin systems to residues, which also implies resonanceSets to atomSets. 2) resonances to peak dimensions. The user is able to configure which assignments should be transferred to the project. Attributes: guiParent: gui object this tab is part of. frame: the frame in which this element lives. dataModel(src.cython.malandro.DataModel): dataModel object describing the assignment proposed by the algorithm. selectedSolution (int): The index of the solution/run that is used asa the template to make the assignments. resonanceToDimension (bool): True if resonances should be assigned to peak dimensions. False if not. spinSystemToResidue (bool): True if spin system to residue assignment should be carried out. minScore (float): The minimal score of a spin system assignment to a residue to be allowed to transfer this assignment to the project intra (bool): True if intra-residual peaks should be assigned. sequential (bool): True if sequential peaks should be assigned. noDiagonal (bool): If True, purely diagonal peaks are ignored during the transfer of assignments. allSpectra (bool): If True, all spectra will be assigned. If False, one specified spectrum will be assigned. spectrum (src.cython.malandro.Spectrum): The spectrum that should be assigned. ''' def __init__(self, parent, frame): '''Init. args: parent: the guiElement that this tab is part of. frame: the frame this part of the GUI lives in. ''' self.guiParent = parent self.frame = frame # Buttons and fields, # will be set in body(): self.peaksCheckButton = None self.residuesCheckButton = None self.intraCheckButton = None self.sequentialCheckButton = None self.noDiagonalCheckButton = None self.spinSystemTypeSelect = None self.minScoreEntry = None self.solutionNumberEntry = None self.spectrumSelect = None self.spectraPullDown = None self.assignedResidueStrategySelect = None self.transferButton = None # Settings that determine how assignments # are transferred to the analysis project: self.minScore = 80.0 self.dataModel = None self.spectrum = None self.selectedSolution = 1 self.body() self.resonanceToDimension = True self.spinSystemToResidue = True self.intra = True self.sequential = True self.noDiagonal = True self.allSpectra = True self.spinSystemType = 0 self.strategy = 0 def body(self): '''Describes the body of this tab. It consists out of a number of radio buttons, check buttons and number entries that allow the user to indicate which assignments should be transferred. ''' # self.frame.expandColumn(0) self.frame.expandGrid(8, 0) self.frame.expandGrid(8, 1) typeOfAssignmentFrame = LabelFrame( self.frame, text='type of assignment') typeOfAssignmentFrame.grid(row=0, column=0, sticky='nesw') # typeOfAssignmentFrame.expandGrid(0,5) peakSelectionFrame = LabelFrame( self.frame, text='which peaks to assign') peakSelectionFrame.grid(row=0, column=1, sticky='nesw', rowspan=2) spinSystemSelectionFrame = LabelFrame(self.frame, text='Which spin-systems to use') spinSystemSelectionFrame.grid(row=2, column=0, sticky='nesw') tipText = 'What to do when a residue has already a spin system assigned to it.' assignedResidueFrame = LabelFrame(self.frame, text='if residue already has spin-system', tipText=tipText) assignedResidueFrame.grid(row=2, column=1, sticky='nesw') spectrumSelectionFrame = LabelFrame(self.frame, text='spectra') spectrumSelectionFrame.grid(row=1, column=0, sticky='nesw') row = 0 Label(typeOfAssignmentFrame, text='Resonances to Peak Dimensions', grid=(row, 0)) self.peaksCheckButton = CheckButton(typeOfAssignmentFrame, selected=True, grid=(row, 1)) row += 1 Label(typeOfAssignmentFrame, text='SpinSystems to Residues', grid=(row, 0)) self.residuesCheckButton = CheckButton( typeOfAssignmentFrame, selected=True, grid=(row, 1)) row = 0 Label(peakSelectionFrame, text='Intra-Residual', grid=(row, 0)) self.intraCheckButton = CheckButton( peakSelectionFrame, selected=True, grid=(row, 1)) row += 1 Label(peakSelectionFrame, text='Sequential', grid=(row, 0)) self.sequentialCheckButton = CheckButton( peakSelectionFrame, selected=True, grid=(row, 1)) row += 1 Label(peakSelectionFrame, text='Do not assign diagonal peaks', grid=(row, 0)) self.noDiagonalCheckButton = CheckButton( peakSelectionFrame, selected=True, grid=(row, 1)) entries = ['Only assigned spin systems', 'All that have a score of at least: ', 'User Defined', 'Solution number:'] tipTexts = ['Only assign resonances of spin systems that already have a sequential assignment for the assignment of peak dimensions. Spin system to residue assignment is not relevant in this case.', 'Assign all spin systems that have a score of at least a given percentage. 50% or lower is not possible, because than spin systems might have to be assigned to more than 1 residue, which is impossible.', "As defined in the lower row of buttons in the 'results' tab.", 'One of the single solutions of the annealing.'] self.spinSystemTypeSelect = RadioButtons(spinSystemSelectionFrame, entries=entries, grid=(0, 0), select_callback=None, direction=VERTICAL, gridSpan=(4, 1), tipTexts=tipTexts) tipText = 'The minimal amount of colabelling the different nuclei should have in order to still give rise to a peak.' self.minScoreEntry = FloatEntry(spinSystemSelectionFrame, grid=(1, 1), width=7, text=str(self.minScore), returnCallback=self.changeMinScore, tipText=tipText) self.minScoreEntry.bind('<Leave>', self.changeMinScore, '+') self.solutionNumberEntry = IntEntry(spinSystemSelectionFrame, grid=(3, 1), width=7, text=1, returnCallback=self.solutionUpdate, tipText=tipText) self.solutionNumberEntry.bind('<Leave>', self.solutionUpdate, '+') #self.solutionPullDown = PulldownList(spinSystemSelectionFrame, None, grid=(3,1), sticky='w') entries = ['all spectra', 'only:'] tipTexts = ['Assign peaks in all the spectra that where selected before the annealing ran.', 'Only assign peaks in one particular spectrum. You can of course repeat this multiple times for different spectra.'] self.spectrumSelect = RadioButtons(spectrumSelectionFrame, entries=entries, grid=(0, 0), select_callback=None, direction=VERTICAL, gridSpan=(2, 1), tipTexts=tipTexts) self.spectraPullDown = PulldownList(spectrumSelectionFrame, self.changeSpectrum, grid=(1, 1), sticky='w') entries = ['skip this residue', 'de-assign old spin system from residue', 'assign, but never merge', 'warn to merge'] tipTexts = ["Don't assign the new spin system to the residue. The residue is not skipped when the old spin system does not contain any resonances", "De-assign old spin system from residue, unless the old spin system is a spin system without any resonances.", "Don't merge any spin systems, merging can be performed later if nescesary in the Resonance --> SpinSystems window.", "Ask to merge individually for each spin system, this might result in clicking on a lot of popups."] self.assignedResidueStrategySelect = RadioButtons(assignedResidueFrame, entries=entries, grid=(0, 0), select_callback=None, direction=VERTICAL, gridSpan=(2, 1), tipTexts=tipTexts) texts = ['Transfer Assignments'] commands = [self.transferAssignments] self.transferButton = ButtonList( self.frame, commands=commands, texts=texts) self.transferButton.grid(row=5, column=0, sticky='nsew', columnspan=2) def update(self): '''Update the nescesary elements in the tab. Is called when the algorithm has produced possible assignments. The only thing that has to be updated in practice in this tab is the pulldown with spectra. ''' self.dataModel = self.guiParent.connector.results self.updateSpectra() def setDataModel(self, dataModel): '''Here the dataModel, which is the dataModel containing the suggested assignments body the algorithm, can be set. ''' self.dataModel = dataModel self.update() def updateSpectra(self, *opt): '''Updates the spectra shown in the spectra pulldown. These are only the spectra that were used by the algorithm. All other spectra in the project are not relevant since for those no simulated peaks have been matched to real peaks. ''' if not self.dataModel: return spectrum = self.spectrum spectra = self.dataModel.getSpectra() if spectra: names = [spectrum.name for spectrum in spectra] index = 0 if self.spectrum not in spectra: self.spectrum = spectra[0] else: index = spectra.index(self.spectrum) self.spectraPullDown.setup(names, spectra, index) def changeSpectrum(self, spectrum): '''Select a spectum to be assigned.''' self.spectrum = spectrum def solutionUpdate(self, event=None, value=None): '''Select a solution. A solution is a one to one mapping of spin systems to residues produced by one run of the algorithm. args: event: event object, this is one of the values the number entry calls his callback function with. value: the index of the solution/run. ''' if not self.dataModel: return Nsolutions = len(self.dataModel.chain.residues[0].solutions) if value is None: value = self.solutionNumberEntry.get() if value == self.selectedSolution: return else: self.selectedSolution = value if value < 1: self.solutionNumberEntry.set(1) self.selectedSolution = 1 elif value > Nsolutions: self.selectedSolution = Nsolutions self.solutionNumberEntry.set(self.selectedSolution) else: self.solutionNumberEntry.set(self.selectedSolution) def fetchOptions(self): '''Fetches user set options from the gui in one go and stores them in their corresponding instance variables. ''' self.resonanceToDimension = self.peaksCheckButton.get() self.spinSystemToResidue = self.residuesCheckButton.get() self.intra = self.intraCheckButton.get() self.sequential = self.sequentialCheckButton.get() self.noDiagonal = self.noDiagonalCheckButton.get() self.spinSystemType = self.spinSystemTypeSelect.getIndex() self.strategy = ['skip', 'remove', 'noMerge', None][ self.assignedResidueStrategySelect.getIndex()] self.allSpectra = [True, False][self.spectrumSelect.getIndex()] def changeMinScore(self, event=None): '''Set the minimal score for which a spin system to residue assignment gets transferred to the ccpn analysis project. ''' newMinScore = self.minScoreEntry.get() if self.minScore != newMinScore: if newMinScore <= 50.0: self.minScore = 51.0 self.minScoreEntry.set(51.0) elif newMinScore > 100.0: self.minScore = 100.0 self.minScoreEntry.set(100.0) else: self.minScore = newMinScore def transferAssignments(self): '''Transfer assignments to project depending on the settings from the GUI. ''' self.fetchOptions() if not self.dataModel or (not self.resonanceToDimension and not self.spinSystemToResidue): return strategy = self.strategy lookupSpinSystem = [self.getAssignedSpinSystem, self.getBestScoringSpinSystem, self.getUserDefinedSpinSystem, self.getSelectedSolutionSpinSystem][self.spinSystemType] residues = self.dataModel.chain.residues spinSystemSequence = [lookupSpinSystem(res) for res in residues] ccpnSpinSystems = [] ccpnResidues = [] # if self.spinSystemType == 0 it means that it for sure already # assigned like this if self.spinSystemToResidue and not self.spinSystemType == 0: for spinSys, res in zip(spinSystemSequence, residues): if spinSys and res: ccpnSpinSystems.append(spinSys.getCcpnResonanceGroup()) ccpnResidues.append(res.getCcpnResidue()) assignSpinSystemstoResidues(ccpnSpinSystems, ccpnResidues, strategy=strategy, guiParent=self.guiParent) if self.resonanceToDimension: allSpectra = self.allSpectra if self.intra: for residue, spinSystem in zip(residues, spinSystemSequence): if not spinSystem: continue intraLink = residue.getIntraLink(spinSystem) for pl in intraLink.getPeakLinks(): peak = pl.getPeak() if not allSpectra and peak.getSpectrum() is not self.spectrum: continue if not peak: continue resonances = pl.getResonances() if self.noDiagonal and len(set(resonances)) < len(resonances): continue for resonance, dimension in zip(resonances, peak.getDimensions()): ccpnResonance = resonance.getCcpnResonance() ccpnDimension = dimension.getCcpnDimension() assignResToDim(ccpnDimension, ccpnResonance) if self.sequential: for residue, spinSystemA, spinSystemB in zip(residues, spinSystemSequence, spinSystemSequence[1:]): if not spinSystemA or not spinSystemB: continue link = residue.getLink(spinSystemA, spinSystemB) for pl in link.getPeakLinks(): peak = pl.getPeak() if not allSpectra and peak.getSpectrum() is not self.spectrum: continue if not peak: continue resonances = pl.getResonances() if self.noDiagonal and len(set(resonances)) < len(resonances): continue for resonance, dimension in zip(resonances, peak.getDimensions()): ccpnResonance = resonance.getCcpnResonance() ccpnDimension = dimension.getCcpnDimension() assignResToDim(ccpnDimension, ccpnResonance) self.guiParent.resultsTab.update() def getAssignedSpinSystem(self, residue): '''Get the spinSystem that is assigned in the project to a residue. args: residue (src.cython.malandro.Residue) return: spinSystem (src.cython.malandro.SpinSystem) ''' ccpCode = residue.ccpCode seqCode = residue.getSeqCode() spinSystems = self.dataModel.getSpinSystems()[ccpCode] ccpnResidue = residue.getCcpnResidue() if ccpnResidue: assignedResonanceGroups = ccpnResidue.getResonanceGroups() if len(assignedResonanceGroups) > 1: print 'There is more than one spin system assigned to residue %s, did not know which one to use to assign peaks. Therefor this residue is skipped.' % (seqCode) return assignedResonanceGroup = ccpnResidue.findFirstResonanceGroup() if assignedResonanceGroup: for spinSystem in spinSystems: if spinSystem.getSerial() == assignedResonanceGroup.serial: # Just checking to make sure, analysis project could # have changed if not self.skipResidue(residue, spinSystem): return spinSystem def getBestScoringSpinSystem(self, residue): '''Get the spinSystem that scores the highest, i.e. is assigned in most of the runs to the given residue. args: residue (src.cython.malandro.Residue) return: spinSystem (src.cython.malandro.SpinSystem) ''' solutions = residue.solutions weigth = 1.0 / len(solutions) score, bestSpinSystem = max([(solutions.count(solution) * weigth * 100.0, solution) for solution in solutions]) if score >= self.minScore and not bestSpinSystem.getIsJoker() and not self.skipResidue(residue, bestSpinSystem): return bestSpinSystem return None def getUserDefinedSpinSystem(self, residue): '''Get the spinSystem that is defined by the user (probably in the resultsTab) as the correct assignment of the given residue. args: residue (src.cython.malandro.Residue) return: spinSystem (src.cython.malandro.SpinSystem) ''' userDefinedSpinSystem = residue.userDefinedSolution if userDefinedSpinSystem and not userDefinedSpinSystem.getIsJoker() and not self.skipResidue(residue, userDefinedSpinSystem): return userDefinedSpinSystem return None def getSelectedSolutionSpinSystem(self, residue): '''I a solution corresponding to one specific run of the algorithm is defined, return which spinSystem in that run got assigned to the given residue. args: residue (src.cython.malandro.Residue) return: spinSystem (src.cython.malandro.SpinSystem) ''' solutions = residue.solutions spinSystem = solutions[self.selectedSolution - 1] if not spinSystem.getIsJoker() and not self.skipResidue(residue, spinSystem): return spinSystem return None def skipResidue(self, residue, spinSystem): '''One strategy is to skip all residues that already have a spin system assignment. If that is the case determine whether to skip the given residue. args: residue (src.cython.malandro.Residue) spinSystem (src.cython.malandro.SpinSystem) return: boolean, True if residue should be skipped. ''' if self.strategy == 0: assignedGroups = residue.getCcpnResidue().getResonanceGroups() assignedSerials = set([spinSys.serial for spinSys in assignedGroups]) if assignedSerials and spinSystem.getSerial() not in assignedSerials: return True return False
def body(self): '''Describes the body of this tab. It consists out of a number of radio buttons, check buttons and number entries that allow the user to indicate which assignments should be transferred. ''' # self.frame.expandColumn(0) self.frame.expandGrid(8, 0) self.frame.expandGrid(8, 1) typeOfAssignmentFrame = LabelFrame( self.frame, text='type of assignment') typeOfAssignmentFrame.grid(row=0, column=0, sticky='nesw') # typeOfAssignmentFrame.expandGrid(0,5) peakSelectionFrame = LabelFrame( self.frame, text='which peaks to assign') peakSelectionFrame.grid(row=0, column=1, sticky='nesw', rowspan=2) spinSystemSelectionFrame = LabelFrame(self.frame, text='Which spin-systems to use') spinSystemSelectionFrame.grid(row=2, column=0, sticky='nesw') tipText = 'What to do when a residue has already a spin system assigned to it.' assignedResidueFrame = LabelFrame(self.frame, text='if residue already has spin-system', tipText=tipText) assignedResidueFrame.grid(row=2, column=1, sticky='nesw') spectrumSelectionFrame = LabelFrame(self.frame, text='spectra') spectrumSelectionFrame.grid(row=1, column=0, sticky='nesw') row = 0 Label(typeOfAssignmentFrame, text='Resonances to Peak Dimensions', grid=(row, 0)) self.peaksCheckButton = CheckButton(typeOfAssignmentFrame, selected=True, grid=(row, 1)) row += 1 Label(typeOfAssignmentFrame, text='SpinSystems to Residues', grid=(row, 0)) self.residuesCheckButton = CheckButton( typeOfAssignmentFrame, selected=True, grid=(row, 1)) row = 0 Label(peakSelectionFrame, text='Intra-Residual', grid=(row, 0)) self.intraCheckButton = CheckButton( peakSelectionFrame, selected=True, grid=(row, 1)) row += 1 Label(peakSelectionFrame, text='Sequential', grid=(row, 0)) self.sequentialCheckButton = CheckButton( peakSelectionFrame, selected=True, grid=(row, 1)) row += 1 Label(peakSelectionFrame, text='Do not assign diagonal peaks', grid=(row, 0)) self.noDiagonalCheckButton = CheckButton( peakSelectionFrame, selected=True, grid=(row, 1)) entries = ['Only assigned spin systems', 'All that have a score of at least: ', 'User Defined', 'Solution number:'] tipTexts = ['Only assign resonances of spin systems that already have a sequential assignment for the assignment of peak dimensions. Spin system to residue assignment is not relevant in this case.', 'Assign all spin systems that have a score of at least a given percentage. 50% or lower is not possible, because than spin systems might have to be assigned to more than 1 residue, which is impossible.', "As defined in the lower row of buttons in the 'results' tab.", 'One of the single solutions of the annealing.'] self.spinSystemTypeSelect = RadioButtons(spinSystemSelectionFrame, entries=entries, grid=(0, 0), select_callback=None, direction=VERTICAL, gridSpan=(4, 1), tipTexts=tipTexts) tipText = 'The minimal amount of colabelling the different nuclei should have in order to still give rise to a peak.' self.minScoreEntry = FloatEntry(spinSystemSelectionFrame, grid=(1, 1), width=7, text=str(self.minScore), returnCallback=self.changeMinScore, tipText=tipText) self.minScoreEntry.bind('<Leave>', self.changeMinScore, '+') self.solutionNumberEntry = IntEntry(spinSystemSelectionFrame, grid=(3, 1), width=7, text=1, returnCallback=self.solutionUpdate, tipText=tipText) self.solutionNumberEntry.bind('<Leave>', self.solutionUpdate, '+') #self.solutionPullDown = PulldownList(spinSystemSelectionFrame, None, grid=(3,1), sticky='w') entries = ['all spectra', 'only:'] tipTexts = ['Assign peaks in all the spectra that where selected before the annealing ran.', 'Only assign peaks in one particular spectrum. You can of course repeat this multiple times for different spectra.'] self.spectrumSelect = RadioButtons(spectrumSelectionFrame, entries=entries, grid=(0, 0), select_callback=None, direction=VERTICAL, gridSpan=(2, 1), tipTexts=tipTexts) self.spectraPullDown = PulldownList(spectrumSelectionFrame, self.changeSpectrum, grid=(1, 1), sticky='w') entries = ['skip this residue', 'de-assign old spin system from residue', 'assign, but never merge', 'warn to merge'] tipTexts = ["Don't assign the new spin system to the residue. The residue is not skipped when the old spin system does not contain any resonances", "De-assign old spin system from residue, unless the old spin system is a spin system without any resonances.", "Don't merge any spin systems, merging can be performed later if nescesary in the Resonance --> SpinSystems window.", "Ask to merge individually for each spin system, this might result in clicking on a lot of popups."] self.assignedResidueStrategySelect = RadioButtons(assignedResidueFrame, entries=entries, grid=(0, 0), select_callback=None, direction=VERTICAL, gridSpan=(2, 1), tipTexts=tipTexts) texts = ['Transfer Assignments'] commands = [self.transferAssignments] self.transferButton = ButtonList( self.frame, commands=commands, texts=texts) self.transferButton.grid(row=5, column=0, sticky='nsew', columnspan=2)
class EditMarksPopup(BasePopup): """ **Setup Spectrum Marker and Ruler Line Options** This popup window is used to specify how many marker and ruler lines may be added by the user to spectrum windows, and what colours these will be. A marker line is a multi-dimensional cross mark that is typically added to the spectrum display with the "m" key, using the mouse cursor location as the center point. A mark of this kind gives a cross that is displayed on a spectrum window (in the plane of the screen), although the same lines will be visible in other spectra that show the relevant frequency/ppm range. A mark will also place lines in any orthogonal (z) positions of the spectrum view; these will not be visible in the window to which the mark was first added but will be seen in any windows that show orthogonal view views of the marked point. A ruler is a single line that is added to the spectrum window displays, typically using the "h" key for a horizontal line and the "v" key for a vertical line. A ruler only places a single line in the plane of the screen at the mouse cursor location. A ruler may be visible in more than one spectrum window, but only if the view is in the right range and for axes that share the same "Panel Type"; a sub-division of axis types that are otherwise specified in terms of isotope. The panel type for a window axis is set via the main Windows_ table. This system allows the user to specify the maximum number of marks and rulers that may be displayed on the screen at any one time. It should be noted that this setting only applies to marks and rulers that are directly added by the user, others may be added by various tools throughout Analysis. When adding marks or rulers to a spectrum window, if the limit is reached then adding another will remove the oldest mark/ruler. Naturally, if the limit is set to one, then the mark or ruler is always replaced. By decreasing the maximum limit the oldest will be removed, although the usual way of removing (all) marks and rulers is via the "n" key after clicking in a spectrum window. Marks and rulers that are added by the user may use a colour scheme, such that each subsequent addition uses the next colour from the scheme. .. _Windows: EditWindowPopup.html """ maxAllowedMarks = 30 maxAllowedRulers = 30 def __init__(self, parent, *args, **kw): BasePopup.__init__(self, parent=parent, title='Window : Marks and Rulers', **kw) def body(self, guiParent): self.geometry('320x120') analysisProject = self.analysisProject guiParent.expandGrid(5,3) guiParent.expandGrid(5,4) row = 0 div = LabelDivider(guiParent, text='Multi-dimensional Marks', grid=(row,0), gridSpan=(1,4)) buttons = UtilityButtonList(guiParent, doClone=False, helpUrl=self.help_url) buttons.grid(row=row, column=4, sticky='w') row += 1 label = Label(guiParent, text='Maximum marks: ', grid=(row,0)) values = range(1, self.maxAllowedMarks+1) entries = [ str(x) for x in values] value = analysisProject.maxMarks tipText = 'Sets the maximum number of multi-dimensional cross-marks that the user can add to spectrum window displays' self.marks_menu = PulldownList(guiParent, callback=self.setMaxMarks, grid=(row,1), texts=entries, objects=values, index=value-1, tipText=tipText) label = Label(guiParent, text=' Mark colour: ', grid=(row,2)) tipText = 'Sets the line colour of the multi-dimensional cross-marks, excepting those that go through peak centers' self.marksSchemePulldown = PulldownList(guiParent, callback=self.setMarksColor, grid=(row,3), tipText=tipText) row += 1 label = Label(guiParent, text='(Non-peak marks only)', grid=(row,2), gridSpan=(1,2)) row += 1 div = LabelDivider(guiParent, text='1-dimensional Rulers', grid=(row,0), gridSpan=(1,5)) row += 1 label = Label(guiParent, text='Maximum rulers: ', grid=(row,0)) values = range(1, self.maxAllowedRulers+1) entries = [ str(x) for x in values] value = analysisProject.maxRulers tipText = 'Sets the maximum number of 1-dimensional ruler lines that the user can add to spectrum window displays' self.rulers_menu = PulldownList(guiParent, callback=self.setMaxRulers, grid=(row,1), texts=entries, objects=values, index=value-1, tipText=tipText) label = Label(guiParent, text=' Ruler colour: ', grid=(row,2)) tipText = 'Sets the line colour of the 1-dimensional ruler lines' self.rulersSchemePulldown = PulldownList(guiParent, callback=self.setRulersColor, grid=(row,3), tipText=tipText) self.updateSchemePulldowns() def updateSchemePulldowns(self): profile = self.analysisProfile indexR = 0 indexM = 0 schemes = getHueSortedColorSchemes(profile) colors = [list(s.colors) for s in schemes] names = [s.name for s in schemes] if profile.marksColor not in schemes: profile.marksColor = schemes[0] if profile.rulersColor not in schemes: profile.rulersColor = schemes[0] indexM = schemes.index(profile.marksColor) indexR = schemes.index(profile.rulersColor) self.marksSchemePulldown.setup(names, schemes, indexM, colors=colors) self.rulersSchemePulldown.setup(names, schemes, indexR, colors=colors) def setMaxMarks(self, value): self.analysisProject.maxMarks = value def setMarksColor(self, scheme): profile = self.analysisProfile profile.marksColor = scheme setNonPeakMarkColor(self.project) def setMaxRulers(self, value): self.analysisProject.maxRulers = value def setRulersColor(self, scheme): profile = self.analysisProfile profile.rulersColor = scheme setRulerColor(self.project)
class AnnealingSettingsTab(object): '''This class describes the tab in the GUI where the user can change setting that govern the monte carlo / annleaing procedure. This also includes which information from the ccpn analysis project is used and which information is ignored. This includes: * present sequential assignments * tentative assignments * amino acid type information * whether to include untyped spin systems * assignments to peak dimensions ALso the chain can be selected here. Furthermore the user can set the temperature regime of the annealing, the amount of times the procedure is repeated to obtain statistics. The fraction of peaks that is left out in each run to diversify the results, the treshhold score for amino acid typing and the treshhold collabelling for a peak to be expected. ''' def __init__(self, parent, frame): '''Init. args: parent: the guiElement that this tab is part of. frame: the frame this part of the GUI lives in. ''' self.guiParent = parent self.frame = frame self.project = parent.project self.nmrProject = parent.nmrProject self.minIsoFrac = 0.1 self.leavePeaksOutFraction = 0.0 self.minTypeScore = 1.0 self.chain = None self.amountOfRepeats = 10 self.amountOfSteps = 10000 self.acceptanceConstantList = [0.0, 0.01, 0.015, 0.022, 0.033, 0.050, 0.075, 0.113, 0.170, 0.256, 0.384, 0.576, 0.864, 1.297, 1.946, 2.919, 4.378, 6.568, 9.852, 14.77, 22.16, 33.25] self.energyDataSets = [[]] self.residues = [] self.body() def body(self): '''describes the body of this tab. It bascically consists of some field to fill out for the user at the top and a ScrolledGraph that shows the progess of the annealing procedure a the bottom. ''' frame = self.frame # frame.expandGrid(13,0) frame.expandGrid(15, 1) row = 0 text = 'Calculate Assignment Suggestions' command = self.runCalculations self.startButton = Button(frame, command=command, text=text) self.startButton.grid(row=row, column=0, sticky='nsew', columnspan=2) row += 1 Label(frame, text='Amount of runs: ', grid=(row, 0)) tipText = 'The amount of times the whole optimization procedure is performed, each result is safed' self.repeatEntry = IntEntry(frame, grid=(row, 1), width=7, text=10, returnCallback=self.updateRepeatEntry, tipText=tipText, sticky='nsew') self.repeatEntry.bind('<Leave>', self.updateRepeatEntry, '+') row += 1 Label(frame, text='Temperature regime: ', grid=(row, 0)) tipText = 'This list of numbers govern the temperature steps during the annealing, every number represents 1/(kb*t), where kb is the Boltzmann constant and t the temperature of one step.' self.tempEntry = Entry(frame, text=map(str, self.acceptanceConstantList), width=64, grid=(row, 1), isArray=True, returnCallback=self.updateAcceptanceConstantList, tipText=tipText, sticky='nsew') row += 1 Label(frame, text='Amount of attempts per temperature:', grid=(row, 0)) tipText = 'The amount of attempts to switch the position of two spinsystems in the sequence are performed for each temperature point' self.NAStepEntry = IntEntry(frame, grid=(row, 1), width=7, text=10000, returnCallback=self.updateStepEntry, tipText=tipText, sticky='nsew') self.NAStepEntry.bind('<Leave>', self.updateStepEntry, '+') row += 1 Label(frame, text='Fraction of peaks to leave out:', grid=(row, 0)) tipText = 'In each run a fraction of the peaks can be left out of the optimization, thereby increasing the variability in the outcome and reducing false negatives. In each run this will be different randomly chosen sub-set of all peaks. 0.1 (10%) can be a good value.' self.leaveOutPeaksEntry = FloatEntry(frame, grid=(row, 1), width=7, text=0.0, returnCallback=self.updateLeavePeaksOutEntry, tipText=tipText, sticky='nsew') self.leaveOutPeaksEntry.bind( '<Leave>', self.updateLeavePeaksOutEntry, '+') row += 1 Label(frame, text='Minmal amino acid typing score:', grid=(row, 0)) tipText = 'If automatic amino acid typing is selected, a cut-off value has to set. Every amino acid type that scores higher than the cut-off is taken as a possible type. This is the same score as can be found under resonance --> spin systems --> predict type. Value should be between 0 and 100' self.minTypeScoreEntry = FloatEntry(frame, grid=(row, 1), width=7, text=1.0, returnCallback=self.updateMinTypeScoreEntry, tipText=tipText, sticky='nsew') self.minTypeScoreEntry.bind( '<Leave>', self.updateMinTypeScoreEntry, '+') row += 1 Label(frame, text='Minimal colabelling fraction:', grid=(row, 0)) tipText = 'The minimal amount of colabelling the different nuclei should have in order to still give rise to a peak.' self.minLabelEntry = FloatEntry(frame, grid=(row, 1), width=7, text=0.1, returnCallback=self.updateMinLabelEntry, tipText=tipText, sticky='nsew') self.minLabelEntry.bind('<Leave>', self.updateMinLabelEntry, '+') row += 1 Label(frame, text='Use sequential assignments:', grid=(row, 0)) tipText = 'When this option is select the present sequential assignments will be kept in place' self.useAssignmentsCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Use tentative assignments:', grid=(row, 0)) tipText = 'If a spin system has tentative assignments this can be used to narrow down the amount of possible sequential assignments.' self.useTentativeCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Use amino acid types:', grid=(row, 0)) tipText = 'Use amino acid types of the spin systems. If this option is not checked the spin systems are re-typed, only resonance names and frequencies are used' self.useTypeCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Include untyped spin systems:', grid=(row, 0)) tipText = 'Also include spin system that have no type information. Amino acid typing will be done on the fly.' self.useAlsoUntypedSpinSystemsCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Use dimensional assignments:', grid=(row, 0)) tipText = 'If one or more dimensions of a peak is already assigned, assume that this assignment is the only option. If not the check the program will consider all possibilities for the assignment of the dimension.' self.useDimensionalAssignmentsCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Chain:', grid=(row, 0)) self.molPulldown = PulldownList( frame, callback=self.changeMolecule, grid=(row, 1)) self.updateChains() row += 1 Label(frame, text='Residue ranges: ', grid=(row, 0)) tipText = 'Which residues should be included. Example: "10-35, 62-100, 130".' self.residueRangeEntry = Entry(frame, text=None, width=64, grid=(row, 1), isArray=True, returnCallback=self.updateResidueRanges, tipText=tipText, sticky='nsew') self.updateResidueRanges(fromChain=True) row += 1 self.energyPlot = ScrolledGraph(frame, symbolSize=2, width=600, height=200, title='Annealing', xLabel='temperature step', yLabel='energy') self.energyPlot.grid(row=row, column=0, columnspan=2, sticky='nsew') def runCalculations(self): '''Run all calculations. Also triggers the disabling of some buttons and fields. ''' self.startButton.disable() self.disableIllegalButtonsAfterPrecalculations() self.guiParent.connector.runAllCalculations() self.startButton.configure(text='More runs') self.startButton.enable() def disableIllegalButtonsAfterPrecalculations(self): '''Disable buttons and field the user can not alter any longer after the model is set up and the 'pre-calculations' have finished. This is done because this part of the calculation should only be run once. All settings that would be changed after this point will not have any influence. ''' illegalButtons = [self.minTypeScoreEntry, self.minLabelEntry, self.useAlsoUntypedSpinSystemsCheck, self.useAssignmentsCheck, self.useTypeCheck, self.useDimensionalAssignmentsCheck, self.useTentativeCheck] for illegalButton in illegalButtons: illegalButton.configure(state='disabled') self.molPulldown.disable() def getChainName(self, chain): '''Get the name for a chain. args: chain: ccpn analysis chain object returns: chain name ''' return '%s:%s (%s)' % (chain.molSystem.code, chain.code, chain.molecule.molType) def getChains(self): '''Get all chains present in the project. returns: list of ccpn analysis chain objects ''' chains = [] if self.project: for molSystem in self.project.sortedMolSystems(): for chain in molSystem.sortedChains(): if chain.residues: chains.append(chain) return chains def updateChains(self, *opt): '''Updates the list of chains if a new one is added to or deleted from the project. Updates the pull down list where a chain can be selected. ''' index = 0 texts = [] chains = self.getChains() chain = self.chain if chains: if chain not in chains: chain = chains[0] texts = [self.getChainName(c) for c in chains] index = chains.index(chain) else: chain = None self.molPulldown.setup(texts, chains, index) if chain is not self.chain: self.chain = chain def changeMolecule(self, chain): '''Select a molecular chain.''' if chain is not self.chain: self.chain = chain self.updateResidueRanges(fromChain=True) def updateStepEntry(self, event=None): '''Update the value and entry that sets the amount of steps per temperature point. ''' value = self.NAStepEntry.get() if value == self.amountOfSteps: return if value < 1: self.NAStepEntry.set(1) self.amountOfSteps = 1 else: self.amountOfSteps = value self.NAStepEntry.set(value) def updateRepeatEntry(self, event=None): '''Update the value and entry of that sets the amount of times the whole annealing procedure is repeated in order to obtain statistics. ''' value = self.repeatEntry.get() if value == self.amountOfRepeats: return if value < 1: self.repeatEntry.set(1) self.amountOfRepeats = 1 else: self.amountOfRepeats = value self.repeatEntry.set(value) def updateMinTypeScoreEntry(self, event=None): '''Updates the value and the entry for the treshhold value for amino acid typing. ''' value = self.minTypeScoreEntry.get() if value == self.minTypeScore: return if value < 0: self.minTypeScoreEntry.set(0.0) self.minTypeScore = 0.0 elif value > 100: self.minTypeScoreEntry.set(100.0) self.minTypeScore = 100.0 else: self.minTypeScoreEntry.set(value) self.minTypeScore = value def updateMinLabelEntry(self, event=None): '''Updates the minimum colabelling fraction for which a peak is expected to be present in the spectra. ''' value = self.minLabelEntry.get() if value == self.minIsoFrac: return if value < 0: self.minIsoFrac = 0.0 self.minLabelEntry.set(0.0) elif value > 1: self.minIsoFrac = 1.0 self.minLabelEntry.set(1.0) else: self.minIsoFrac = value self.minLabelEntry.set(value) def updateLeavePeaksOutEntry(self, event=None): '''Updates the value and entry of the fraction of peaks that should be left out in each run in order to diversify the results. ''' value = self.leaveOutPeaksEntry.get() if value == self.leavePeaksOutFraction: return if value < 0: self.leavePeaksOutFraction = 0.0 self.leaveOutPeaksEntry.set(0.0) elif value > 1: self.leavePeaksOutFraction = 1.0 self.leaveOutPeaksEntry.set(1.0) else: self.leavePeaksOutFraction = value self.leaveOutPeaksEntry.set(value) def updateAcceptanceConstantList(self, event=None): '''Updates the list with constants that are used during the monte carlo procedure to decide whether a changed is accepted or not. ''' acList = self.tempEntry.get() newList = [] for constant in acList: try: number = float(constant) newList.append(number) except ValueError: string = constant + \ ' in temperature constants is not a number.' showWarning('Not A Number', string, parent=self.guiParent) return False self.acceptanceConstantList = newList return True def updateResidueRanges(self, event=None, fromChain=False): self.residues = set() subRanges = self.residueRangeEntry.get() if not subRanges or fromChain: self.residues = set(self.chain.residues) residues = self.chain.sortedResidues() text = '{}-{}'.format(residues[0].seqCode, residues[-1].seqCode) self.residueRangeEntry.set(text=text) return for subRange in subRanges: indeces = subRange.split('-') start = int(indeces[0]) stop = int(indeces[-1]) + 1 for seqCode in range(start, stop): residue = self.chain.findFirstResidue(seqCode=seqCode) if not residue: showWarning('Residue out of range.', 'There is no residue at position {}'.format(seqCode), parent=self.guiParent) self.residues = set() return self.residues.add(residue) def addEnergyPoint(self, energy, time): '''Adds a point to the graph that shows the progress of the annealling procedure. args: energy: the y-value time: the x-value ''' point = (time, energy * -1) # This means one run has finished if len(self.energyDataSets[-1]) / (len(self.acceptanceConstantList) + 1): self.energyDataSets.append([point]) else: self.energyDataSets[-1].append(point) colors = colorSeries Ncolors = len(colors) NdataSets = len(self.energyDataSets) colorList = (NdataSets / Ncolors) * colors + \ colors[:NdataSets % Ncolors] self.energyPlot.update(dataSets=self.energyDataSets, dataColors=colorList) # Forcing the graph to draw, eventhough calculations # are still running. Only do this with high numbers of # steps, otherwise drawing takes longer than annealling. if self.amountOfSteps >= 100000: self.energyPlot.draw()
def body(self, guiFrame): self.geometry('700x500') guiFrame.expandGrid(1, 0) row = 0 # TOP LEFT FRAME frame = LabelFrame(guiFrame, text='Options') frame.grid(row=row, column=0, sticky='nsew') frame.columnconfigure(5, weight=1) label = Label(frame, text='Chain') label.grid(row=0, column=0, sticky='w') self.chainPulldown = PulldownList( frame, callback=self.changeChain, tipText='Choose the molecular system chain to make predictions for' ) self.chainPulldown.grid(row=0, column=1, sticky='w') label = Label(frame, text='Shift List') label.grid(row=0, column=2, sticky='w') self.shiftListPulldown = PulldownList( frame, callback=self.changeShiftList, tipText='Select the shift list to take input chemical shifts from') self.shiftListPulldown.grid(row=0, column=3, sticky='w') row += 1 # BOTTOM LEFT FRAME frame = LabelFrame(guiFrame, text='Secondary Structure Predictions') frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) tipTexts = ('Residue number in chain', 'Residue type code', 'Current stored secondary structure code', 'Predicted secondary structure code') + SEC_STRUC_TIPS headingList = ('Res\nNum', 'Res\nType', 'Current\nSS', 'Predicted\nSS') + SEC_STRUC_KEYS n = len(headingList) editWidgets = n * [None] editGetCallbacks = n * [None] editSetCallbacks = n * [None] self.predictionMatrix = ScrolledMatrix( frame, headingList=headingList, tipTexts=tipTexts, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.predictionMatrix.grid(row=0, column=0, sticky='nsew') row += 1 tipTexts = [ 'Run the D2D method to predict secondary structure', 'Store the secondary structure predictions in the CCPN project' ] texts = [ 'Run D2D Prediction!', 'Commit Predicted\nSecondary Structure' ] commands = [self.runD2D, self.storeSecondaryStructure] self.buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, help_url=self.help_url, expands=True, tipTexts=tipTexts) self.buttonList.grid(row=row, column=0, columnspan=2, sticky='ew') self.update() self.notify(self.registerNotify)
def body(self, guiFrame): self.geometry("500x500") self.nameEntry = Entry(self, text='', returnCallback=self.setName, width=12) self.detailsEntry = Entry(self, text='', returnCallback=self.setDetails, width=16) self.valueEntry = FloatEntry(self, text='', returnCallback=self.setValue, width=10) self.errorEntry = FloatEntry(self, text='', returnCallback=self.setError, width=8) self.conditionNamesPulldown = PulldownList(self, callback=self.setConditionName, texts=self.getConditionNames()) self.unitPulldown = PulldownList(self, callback=self.setUnit, texts=self.getUnits()) self.experimentPulldown = PulldownList(self, callback=self.setExperiment) guiFrame.grid_columnconfigure(0, weight=1) row = 0 frame = Frame(guiFrame, grid=(row, 0)) frame.expandGrid(None,0) div = LabelDivider(frame, text='Current Series', grid=(0, 0)) utilButtons = UtilityButtonList(frame, helpUrl=self.help_url, grid=(0,1)) row += 1 frame0 = Frame(guiFrame, grid=(row, 0)) frame0.expandGrid(0,0) tipTexts = ['The serial number of the experiment series, but left blank if the series as actually a pseudo-nD experiment (with a sampled non-frequency axis)', 'The name of the experiment series, which may be a single pseudo-nD experiment', 'The number of separate experiments (and hence spectra) present in the series', 'The kind of quantity that varies for different experiments/planes within the NMR series, e.g. delay time, temperature, ligand concentration etc.', 'The number of separate points, each with a separate experiment/plane and parameter value, in the series'] headingList = ['#','Name','Experiments','Parameter\nVaried','Num\nPoints'] editWidgets = [None, self.nameEntry, None, self.conditionNamesPulldown, None] editGetCallbacks = [None, self.getName, None, self.getConditionName, None] editSetCallbacks = [None, self.setName, None, self.setConditionName, None] self.seriesMatrix = ScrolledMatrix(frame0, tipTexts=tipTexts, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, editWidgets=editWidgets, headingList=headingList, callback=self.selectExpSeries, deleteFunc=self.deleteExpSeries, grid=(0,0), gridSpan=(None, 3)) tipTexts = ['Make a new, blank NMR series specification in the CCPN project', 'Delete the selected NMR series from the project, although any component experiments remain. Note you cannot delete pseudo-nD series; delete the actual experiment instead', 'Colour the spectrum contours for each experiment in the selected series (not pseudo-nD) using a specified scheme'] texts = ['Add Series','Delete Series', 'Auto Colour Spectra'] commands = [self.addExpSeries,self.deleteExpSeries, self.autoColorSpectra] self.seriesButtons = ButtonList(frame0, texts=texts, commands=commands, grid=(1,0), tipTexts=tipTexts) label = Label(frame0, text='Scheme:', grid=(1,1)) tipText = 'Selects which colour scheme to apply to the contours of (separate) experiments within an NMR series' self.colorSchemePulldown = PulldownList(frame0, grid=(1,2), tipText=tipText) row += 1 div = LabelDivider(guiFrame, text='Experimental Parameters & Conditions', grid=(row, 0)) row += 1 guiFrame.grid_rowconfigure(row, weight=1) frame1 = Frame(guiFrame, grid=(row, 0)) frame1.expandGrid(0,0) tipTexts = ['The kind of experimental parameter that is being used to define the NMR series', 'The experiment that corresponds to the specified parameter value; can be edited from an arbitrary initial experiment', 'The numeric value of the parameter (condition) that relates to the experiment or point in the NMR series', 'The estimated error in value of the condition', 'The measurement unit in which the value of the condition is represented'] headingList = ['Parameter','Experiment','Value','Error','Unit'] editWidgets = [None,self.experimentPulldown,self.valueEntry,self.errorEntry, self.unitPulldown] editGetCallbacks = [None,self.getExperiment, self.getValue, self.getError, self.getUnit] editSetCallbacks = [None,self.setExperiment, self.setValue, self.setError, self.setUnit] self.conditionPointsMatrix = ScrolledMatrix(frame1, grid=(0,0), tipTexts=tipTexts, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, editWidgets=editWidgets, headingList=headingList, callback=self.selectConditionPoint, deleteFunc=self.deleteConditionPoint) self.conditionPointsMatrix.doEditMarkExtraRules = self.conditionTableShow tipTexts = ['Add a new point to the NMR series with an associated parameter value and experiment', 'Remove the selected point from the series, including any associated parameter value', 'For appropriate kinds of NMR series, set or unset a point as representing the plane to use as a reference'] texts = ['Add Series Point','Delete Series Point','Set/Unset Ref Plane'] commands = [self.addConditionPoint,self.deleteConditionPoint,self.setSampledReferencePlane] self.conditionPointsButtons = ButtonList(frame1, texts=texts, commands=commands, tipTexts=tipTexts, grid=(1,0)) self.updateAfter() self.updateColorSchemes() self.administerNotifiers(self.registerNotify)
def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) row = 0 self.scrolledGraph = ScrolledGraph(guiFrame, width=400, height=300, symbolSize=5, symbols=['square', 'circle'], dataColors=['#000080', '#800000'], lineWidths=[0, 1], grid=(row, 0)) #self.scrolledGraph.setZoom(0.7) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') label = Label(frame, text='Fitting Function:', grid=(0, 0)) tipText = 'Selects which form of function to fit to the experimental data' self.methodPulldown = PulldownList(frame, self.changeMethod, grid=(0, 1), tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') tipText = 'The effective equation of the final fitted graph, incorporating all parameters' self.equationLabel = Label(frame, text='Equation:', grid=(0, 0), tipText=tipText) tipText = 'The error in the fit of the selected parameterised function to the experimental data' self.errorLabel = Label(frame, text='Fit Error:', grid=(0, 1), tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') label = Label(frame, text='Include x origin?:', grid=(0, 0)) tipText = 'Whether to include the x=0 point in the drawing' self.xOriginSelect = CheckButton(frame, callback=self.draw, grid=(0, 1), selected=False, tipText=tipText) label = Label(frame, text='Include y origin?:', grid=(0, 2)) tipText = 'Whether to include the y=0 point in the drawing' self.yOriginSelect = CheckButton(frame, callback=self.draw, grid=(0, 3), selected=False, tipText=tipText) label = Label(frame, text='Include y error?:', grid=(0, 4)) tipText = 'Whether to include the y error bars in the drawing (if these exist)' self.yErrorSelect = CheckButton(frame, callback=self.draw, grid=(0, 5), selected=False, tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') label = Label(frame, text='Navigation Window:', grid=(0, 0)) tipText = 'Selects which spectrum window will be used for navigating to peak positions' self.windowPanePulldown = PulldownList(frame, self.changeWindow, grid=(0, 1), tipText=tipText) label = Label(frame, text='Follow in window?:', grid=(0, 2)) tipText = 'Whether to navigate to the position of the reference peak (for the group), in the selected window' self.followSelect = CheckButton(frame, callback=self.windowPaneNavigate, grid=(0, 3), selected=False, tipText=tipText) label = Label(frame, text='Mark Ref Peak?:', grid=(0, 4)) tipText = 'Whether to put a multi-dimensional cross-mark through the reference peak position, so it can be identified in spectra' self.markSelect = CheckButton(frame, callback=None, tipText=tipText, grid=(0, 5), selected=False) row += 1 guiFrame.grid_rowconfigure(row, weight=1) tipTexts = [ 'The number of the data point, in order of increasing X-axis value', 'For each point, the value of the parameter which is varied in the NMR series, e.g. T1, temperature, concentration etc.', 'For each point, the experimental value being fitted, e.g. peak intensity of chemical shift distance', 'The value of the best-fit function at the X-axis location', 'The difference between the experimental (Y-axis) value and the fitted value', 'The error in the experimental (Y-axis) value' ] headingList = ['Point', 'x', 'y', 'Fitted y', u'\u0394', 'y error'] self.scrolledMatrix = ScrolledMatrix(guiFrame, headingList=headingList, callback=self.selectObject, tipTexts=tipTexts, grid=(row, 0)) row += 1 tipTexts = [ 'Remove the selected data point, optionally removing the underlying peak', 'Show a table of spectrum peaks that correspond to the selected data point' ] texts = ['Remove Point', 'Show Peak'] commands = [self.removePoint, self.showObject] if self.prevSetFunction: texts.append('Previous Set') tipTexts.append( 'Move to the previous set of fitted values; the next group of peaks, often corresponding to a different residue or resonance' ) commands.append(self.prevSet) if self.nextSetFunction: tipTexts.append( 'Move to the next set of fitted values; the next group of peaks, often corresponding to a different residue or resonance' ) texts.append('Next Set') commands.append(self.nextSet) bottomButtons = UtilityButtonList(guiFrame, texts=texts, commands=commands, helpUrl=self.help_url, tipTexts=tipTexts, grid=(row, 0), doClone=False) self.removeButton = bottomButtons.buttons[0] for func in ('__init__', 'delete', 'setName'): self.registerNotify(self.updateWindows, 'ccpnmr.Analysis.SpectrumWindow', func) self.update()
def body(self, guiFrame): self.geometry('700x700') guiFrame.expandGrid(0,0) options = ['Peak Lists & Settings','Peak Intensity Comparison'] tabbedFrame = TabbedFrame(guiFrame, options=options, callback=self.changeTab) tabbedFrame.grid(row=0, column=0, sticky='nsew') self.tabbedFrame = tabbedFrame frameA, frameB = tabbedFrame.frames row = 0 frameA.grid_columnconfigure(1, weight=1) frameA.grid_columnconfigure(3, weight=1) frameA.grid_columnconfigure(5, weight=1) frameA.grid_rowconfigure(5, weight=1) tipText = 'Number of reference peaks (no saturation)' self.peaksALabel = Label(frameA, text='Number of Ref Peaks: ', tipText=tipText) self.peaksALabel.grid(row=1,column=0,columnspan=2,sticky='w') tipText = 'Number of NOE saturation peaks' self.peaksBLabel = Label(frameA, text='Number of Sat Peaks: ', tipText=tipText) self.peaksBLabel.grid(row=1,column=2,columnspan=2,sticky='w') tipText = 'Number of peaks in assigned list' self.peaksCLabel = Label(frameA, text='Number of Assign Peaks: ', tipText=tipText) self.peaksCLabel.grid(row=1,column=4,columnspan=2,sticky='w') tipText = 'Selects which peak list is considered the NOE intensity reference (no saturation)' specALabel = Label(frameA, text='Ref Peak List: ') specALabel.grid(row=0,column=0,sticky='w') self.specAPulldown = PulldownList(frameA, callback=self.setRefPeakList, tipText=tipText) self.specAPulldown.grid(row=0,column=1,sticky='w') tipText = 'Selects which peak list is considered as NOE saturated.' specBLabel = Label(frameA, text='Sat Peak List: ') specBLabel.grid(row=0,column=2,sticky='w') self.specBPulldown = PulldownList(frameA, callback=self.setSatPeakList, tipText=tipText) self.specBPulldown.grid(row=0,column=3,sticky='w') tipText = 'Selects a peak list with assignments to use as a positional reference' specCLabel = Label(frameA, text='Assignment Peak List: ') specCLabel.grid(row=0,column=4,sticky='w') self.specCPulldown = PulldownList(frameA, callback=self.setAssignPeakList, tipText=tipText) self.specCPulldown.grid(row=0,column=5,sticky='w') frame0a = Frame(frameA) frame0a.grid(row=2,column=0,columnspan=6,sticky='nsew') frame0a.grid_columnconfigure(9, weight=1) tipText = '1H ppm tolerance for matching assigned peaks to reference & NOE saturation peaks' tolHLabel = Label(frame0a, text='Tolerances: 1H') tolHLabel.grid(row=0,column=0,sticky='w') self.tolHEntry = FloatEntry(frame0a,text='0.02', width=6, tipText=tipText) self.tolHEntry .grid(row=0,column=1,sticky='w') tipText = '15N ppm tolerance for matching assigned peaks to reference & NOE saturation peaks' tolNLabel = Label(frame0a, text=' 15N') tolNLabel .grid(row=0,column=2,sticky='w') self.tolNEntry = FloatEntry(frame0a,text='0.1', width=6, tipText=tipText) self.tolNEntry .grid(row=0,column=3,sticky='w') tipText = 'Whether to peak new peaks in reference & NOE saturated lists (at assignment locations)' label = Label(frame0a, text=' Pick new peaks?', grid=(0,4)) self.pickPeaksSelect = CheckButton(frame0a, tipText=tipText, grid=(0,5), selected=True) tipText = 'Whether to assign peaks in the peaks in the reference & NOE saturation lists, if not already assigned' label = Label(frame0a, text=' Assign peaks?') label.grid(row=0,column=6,sticky='w') self.assignSelect = CheckButton(frame0a, tipText=tipText) self.assignSelect.set(1) self.assignSelect.grid(row=0,column=7,sticky='w') tipText = 'Whether to consider peak height or volume in the heteronuclear NOE calculation' intensLabel = Label(frame0a, text=' Intensity Type:') intensLabel .grid(row=0,column=8,sticky='w') self.intensPulldown = PulldownList(frame0a, texts=['height','volume'], callback=self.setIntensityType, tipText=tipText) self.intensPulldown.grid(row=0,column=9,sticky='w') divider = LabelDivider(frameA, text='Peaks', grid=(3,0), gridSpan=(1,6)) tipTexts = ['Show the selected intensity reference peaks in the below table', 'Show the selected NOE saturation peaks in the below table', 'Show the selected assigned peak list in the below table', 'Show the displayed peaks in a separate peak table, where assignments etc. may be adjusted'] texts = ['Show Ref Peaks','Show Sat Peaks', 'Show Assign Peaks', 'Separate Peak Table'] commands = [self.viewRefPeakList, self.viewSatPeakList, self.viewAssignPeakList, self.viewSeparatePeakTable] self.viewPeaksButtons = ButtonList(frameA, expands=True, tipTexts=tipTexts, texts=texts, commands=commands) self.viewPeaksButtons.grid(row=4,column=0,columnspan=6,sticky='nsew') self.peakTable = PeakTableFrame(frameA, self.guiParent, grid=(5,0), gridSpan=(1,6)) self.peakTable.bottomButtons1.grid_forget() self.peakTable.bottomButtons2.grid_forget() #self.peakTable.topFrame.grid_forget() self.peakTable.topFrame.grid(row=2, column=0, sticky='ew') # Next tab frameB.expandGrid(0,0) tipTexts = ['Row number', 'Assignment annotation for NOE saturation peak', 'Assignment annotation for reference peak (no saturation)', '1H chemical shift of NOE saturation peak', '1H chemical shift of reference peak', '15N chemical shift of NOE saturation peak', '15N chemical shift of reference peak', 'The separation between compared peaks: square root of the sum of ppm differences squared', 'The intensity if the NOE saturation peak', 'The intensity of the reference peak (no saturation)', 'Ratio of peak intensities: saturated over reference', 'Residue(s) for reference peak'] colHeadings = ['#','Sat Peak','Ref Peak','1H shift A', '1H shift B','15N shift A','15N shift B', 'Closeness\nScore','Intensity A','Intensity B', 'Intensity\nRatio','Residue'] self.scrolledMatrix = ScrolledMatrix(frameB, multiSelect=True, headingList=colHeadings, callback=self.selectCell, tipTexts=tipTexts, grid=(0,0), deleteFunc=self.removePair) tipTexts = ['Force a manual update of the table; pair-up NOE saturation and reference peaks according to assigned peak positions', 'Remove the selected rows of peak pairs', 'Show peaks corresponding to the selected row in a table', 'Save the Heteronuclear NOE values in the CCPN project as a data list'] texts = ['Refresh Table','Remove Pairs', 'Show Peak Pair','Create Hetero NOE List'] commands = [self.matchPeaks,self.removePair, self.showPeakPair,self.makeNoeList] self.pairButtons = ButtonList(frameB, tipTexts=tipTexts, grid=(1,0), texts=texts, commands=commands) bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, helpUrl=self.help_url) bottomButtons.grid(row=0, column=0, sticky='e') self.updatePulldowns() self.updateAfter() self.administerNotifiers(self.registerNotify)
class CingFrame(NmrSimRunFrame): def __init__(self, parent, application, *args, **kw): project = application.project simStore = project.findFirstNmrSimStore(application=APP_NAME) or \ project.newNmrSimStore(application=APP_NAME, name=APP_NAME) self.application = application self.residue = None self.structure = None self.serverCredentials = None self.iCingBaseUrl = DEFAULT_URL self.resultsUrl = None self.chain = None self.nmrProject = application.nmrProject self.serverDone = False NmrSimRunFrame.__init__(self, parent, project, simStore, *args, **kw) # # # # # # New Structure Frame # # # # # self.structureFrame.grid_forget() tab = self.tabbedFrame.frames[0] frame = Frame(tab, grid=(1,0)) frame.expandGrid(2,1) div = LabelDivider(frame, text='Structures', grid=(0,0), gridSpan=(1,2)) label = Label(frame, text='Ensemble: ', grid=(1,0)) self.structurePulldown = PulldownList(frame, callback=self.changeStructure, grid=(1,1)) headingList = ['Model','Use'] editWidgets = [None,None] editGetCallbacks = [None,self.toggleModel] editSetCallbacks = [None,None,] self.modelTable = ScrolledMatrix(frame, grid=(2,0), gridSpan=(1,2), callback=self.selectStructModel, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, headingList=headingList) texts = ['Activate Selected','Inactivate Selected'] commands = [self.activateModels, self.disableModels] buttons = ButtonList(frame, texts=texts, commands=commands, grid=(3,0), gridSpan=(1,2)) # # # # # # Submission frame # # # # # # tab = self.tabbedFrame.frames[1] tab.expandGrid(1,0) frame = LabelFrame(tab, text='Server Job Submission', grid=(0,0)) frame.expandGrid(None,2) srow = 0 label = Label(frame, text='iCing URL:', grid=(srow, 0)) urls = [DEFAULT_URL,] self.iCingBaseUrlPulldown = PulldownList(frame, texts=urls, objects=urls, index=0, grid=(srow,1)) srow +=1 label = Label(frame, text='Results File:', grid=(srow, 0)) self.resultFileEntry = Entry(frame, bd=1, text='', grid=(srow,1), width=50) self.setZipFileName() button = Button(frame, text='Choose File', bd=1, sticky='ew', command=self.chooseZipFile, grid=(srow, 2)) srow +=1 label = Label(frame, text='Results URL:', grid=(srow, 0)) self.resultUrlEntry = Entry(frame, bd=1, text='', grid=(srow,1), width=50) button = Button(frame, text='View Results HTML', bd=1, sticky='ew', command=self.viewHtmlResults, grid=(srow, 2)) srow +=1 texts = ['Submit Project!', 'Check Run Status', 'Purge Server Result', 'Download Results'] commands = [self.runCingServer, self.checkStatus, self.purgeCingServer, self.downloadResults] self.buttonBar = ButtonList(frame, texts=texts, commands=commands, grid=(srow, 0), gridSpan=(1,3)) for button in self.buttonBar.buttons[:1]: button.config(bg=CING_BLUE) # # # # # # Residue frame # # # # # # frame = LabelFrame(tab, text='Residue Options', grid=(1,0)) frame.expandGrid(1,1) label = Label(frame, text='Chain: ') label.grid(row=0,column=0,sticky='w') self.chainPulldown = PulldownList(frame, callback=self.changeChain) self.chainPulldown.grid(row=0,column=1,sticky='w') headingList = ['#','Residue','Linking','Decriptor','Use?'] editWidgets = [None,None,None,None,None] editGetCallbacks = [None,None,None,None,self.toggleResidue] editSetCallbacks = [None,None,None,None,None,] self.residueMatrix = ScrolledMatrix(frame, headingList=headingList, multiSelect=True, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, callback=self.selectResidue) self.residueMatrix.grid(row=1, column=0, columnspan=2, sticky = 'nsew') texts = ['Activate Selected','Inactivate Selected'] commands = [self.activateResidues, self.deactivateResidues] self.resButtons = ButtonList(frame, texts=texts, commands=commands,) self.resButtons.grid(row=2, column=0, columnspan=2, sticky='ew') """ # # # # # # Validate frame # # # # # # frame = LabelFrame(tab, text='Validation Options', grid=(2,0)) frame.expandGrid(None,2) srow = 0 self.selectCheckAssign = CheckButton(frame) self.selectCheckAssign.grid(row=srow, column=0,sticky='nw' ) self.selectCheckAssign.set(True) label = Label(frame, text='Assignments and shifts') label.grid(row=srow,column=1,sticky='nw') srow += 1 self.selectCheckResraint = CheckButton(frame) self.selectCheckResraint.grid(row=srow, column=0,sticky='nw' ) self.selectCheckResraint.set(True) label = Label(frame, text='Restraints') label.grid(row=srow,column=1,sticky='nw') srow += 1 self.selectCheckQueen = CheckButton(frame) self.selectCheckQueen.grid(row=srow, column=0,sticky='nw' ) self.selectCheckQueen.set(False) label = Label(frame, text='QUEEN') label.grid(row=srow,column=1,sticky='nw') srow += 1 self.selectCheckScript = CheckButton(frame) self.selectCheckScript.grid(row=srow, column=0,sticky='nw' ) self.selectCheckScript.set(False) label = Label(frame, text='User Python script\n(overriding option)') label.grid(row=srow,column=1,sticky='nw') self.validScriptEntry = Entry(frame, bd=1, text='') self.validScriptEntry.grid(row=srow,column=2,sticky='ew') scriptButton = Button(frame, bd=1, command=self.chooseValidScript, text='Browse') scriptButton.grid(row=srow,column=3,sticky='ew') """ # # # # # # # # # # self.update(simStore) self.administerNotifiers(application.registerNotify) def downloadResults(self): if not self.run: msg = 'No current iCing run' showWarning('Failure', msg, parent=self) return credentials = self.serverCredentials if not credentials: msg = 'No current iCing server job' showWarning('Failure', msg, parent=self) return fileName = self.resultFileEntry.get() if not fileName: msg = 'No save file specified' showWarning('Failure', msg, parent=self) return if os.path.exists(fileName): msg = 'File %s already exists. Overwite?' % fileName if not showOkCancel('Query', msg, parent=self): return url = self.iCingBaseUrl iCingUrl = self.getServerUrl(url) logText = iCingRobot.iCingFetch(credentials, url, iCingUrl, fileName) print logText msg = 'Results saved to file %s\n' % fileName msg += 'Purge results from iCing server?' if showYesNo('Query',msg, parent=self): self.purgeCingServer() def getServerUrl(self, baseUrl): iCingUrl = os.path.join(baseUrl, 'icing/serv/iCingServlet') return iCingUrl def viewHtmlResults(self): resultsUrl = self.resultsUrl if not resultsUrl: msg = 'No current iCing results URL' showWarning('Failure', msg, parent=self) return webBrowser = WebBrowser(self.application, popup=self.application) webBrowser.open(self.resultsUrl) def runCingServer(self): if not self.project: return run = self.run if not run: msg = 'No CING run setup' showWarning('Failure', msg, parent=self) return structure = self.structure if not structure: msg = 'No structure ensemble selected' showWarning('Failure', msg, parent=self) return ensembleText = getModelsString(run) if not ensembleText: msg = 'No structural models selected from ensemble' showWarning('Failure', msg, parent=self) return residueText = getResiduesString(structure) if not residueText: msg = 'No active residues selected in structure' showWarning('Failure', msg, parent=self) return url = self.iCingBaseUrlPulldown.getObject() url.strip() if not url: msg = 'No iCing server URL specified' showWarning('Failure', msg, parent=self) self.iCingBaseUrl = None return msg = 'Submit job now? You will be informed when the job is done.' if not showOkCancel('Confirm', msg, parent=self): return self.iCingBaseUrl = url iCingUrl = self.getServerUrl(url) self.serverCredentials, results, tarFileName = iCingRobot.iCingSetup(self.project, userId='ccpnAp', url=iCingUrl) if not results: # Message already issued on failure self.serverCredentials = None self.resultsUrl = None self.update() return else: credentials = self.serverCredentials os.unlink(tarFileName) entryId = iCingRobot.iCingProjectName(credentials, iCingUrl).get(iCingRobot.RESPONSE_RESULT) baseUrl, htmlUrl, logUrl, zipUrl = iCingRobot.getResultUrls(credentials, entryId, url) self.resultsUrl = htmlUrl # Save server data in this run for persistence setRunParameter(run, iCingRobot.FORM_USER_ID, self.serverCredentials[0][1]) setRunParameter(run, iCingRobot.FORM_ACCESS_KEY, self.serverCredentials[1][1]) setRunParameter(run, ICING_BASE_URL, url) setRunParameter(run, HTML_RESULTS_URL, htmlUrl) self.update() run.inputStructures = structure.sortedModels() # select residues from the structure's chain #iCingRobot.iCingResidueSelection(credentials, iCingUrl, residueText) # Select models from ensemble #iCingRobot.iCingEnsembleSelection(credentials, iCingUrl, ensembleText) # Start the actual run self.serverDone = False iCingRobot.iCingRun(credentials, iCingUrl) # Fetch server progress occasionally, report when done # this function will call itself again and again self.after(CHECK_INTERVAL, self.timedCheckStatus) self.update() def timedCheckStatus(self): if not self.serverCredentials: return if self.serverDone: return status = iCingRobot.iCingStatus(self.serverCredentials, self.getServerUrl(self.iCingBaseUrl)) if not status: #something broke, already warned return result = status.get(iCingRobot.RESPONSE_RESULT) if result == iCingRobot.RESPONSE_DONE: self.serverDone = True msg = 'CING run is complete!' showInfo('Completion', msg, parent=self) return self.after(CHECK_INTERVAL, self.timedCheckStatus) def checkStatus(self): if not self.serverCredentials: return status = iCingRobot.iCingStatus(self.serverCredentials, self.getServerUrl(self.iCingBaseUrl)) if not status: #something broke, already warned return result = status.get(iCingRobot.RESPONSE_RESULT) if result == iCingRobot.RESPONSE_DONE: msg = 'CING run is complete!' showInfo('Completion', msg, parent=self) self.serverDone = True return else: msg = 'CING job is not done.' showInfo('Processing', msg, parent=self) self.serverDone = False return def purgeCingServer(self): if not self.project: return if not self.run: msg = 'No CING run setup' showWarning('Failure', msg, parent=self) return if not self.serverCredentials: msg = 'No current iCing server job' showWarning('Failure', msg, parent=self) return url = self.iCingBaseUrl results = iCingRobot.iCingPurge(self.serverCredentials, self.getServerUrl(url)) if results: showInfo('Info','iCing server results cleared') self.serverCredentials = None self.iCingBaseUrl = None self.serverDone = False deleteRunParameter(self.run, iCingRobot.FORM_USER_ID) deleteRunParameter(self.run, iCingRobot.FORM_ACCESS_KEY) deleteRunParameter(self.run, HTML_RESULTS_URL) else: showInfo('Info','Purge failed') self.update() def chooseZipFile(self): fileTypes = [ FileType('Zip', ['*.zip']), ] popup = FileSelectPopup(self, file_types=fileTypes, file=self.resultFileEntry.get(), title='Results zip file location', dismiss_text='Cancel', selected_file_must_exist=False) fileName = popup.getFile() if fileName: self.resultFileEntry.set(fileName) popup.destroy() def setZipFileName(self): zipFile = '%s_CING_report.zip' % self.project.name self.resultFileEntry.set(zipFile) def selectStructModel(self, model, row, col): self.model = model def selectResidue(self, residue, row, col): self.residue = residue def deactivateResidues(self): for residue in self.residueMatrix.currentObjects: residue.useInCing = False self.updateResidues() def activateResidues(self): for residue in self.residueMatrix.currentObjects: residue.useInCing = True self.updateResidues() def activateModels(self): if self.run: for model in self.modelTable.currentObjects: if model not in self.run.inputStructures: self.run.addInputStructure(model) self.updateModels() def disableModels(self): if self.run: for model in self.modelTable.currentObjects: if model in self.run.inputStructures: self.run.removeInputStructure(model) self.updateModels() def toggleModel(self, *opt): if self.model and self.run: if self.model in self.run.inputStructures: self.run.removeInputStructure(self.model) else: self.run.addInputStructure(self.model) self.updateModels() def toggleResidue(self, *opt): if self.residue: self.residue.useInCing = not self.residue.useInCing self.updateResidues() def updateResidues(self): if self.residue and (self.residue.topObject is not self.structure): self.residue = None textMatrix = [] objectList = [] colorMatrix = [] if self.chain: chainCode = self.chain.code for residue in self.chain.sortedResidues(): msResidue = residue.residue if not hasattr(residue, 'useInCing'): residue.useInCing = True if residue.useInCing: colors = [None, None, None, None, CING_BLUE] use = 'Yes' else: colors = [None, None, None, None, None] use = 'No' datum = [residue.seqCode, msResidue.ccpCode, msResidue.linking, msResidue.descriptor, use,] textMatrix.append(datum) objectList.append(residue) colorMatrix.append(colors) self.residueMatrix.update(objectList=objectList, textMatrix=textMatrix, colorMatrix=colorMatrix) def updateChains(self): index = 0 names = [] chains = [] chain = self.chain if self.structure: chains = self.structure.sortedCoordChains() names = [chain.code for chain in chains] if chains: if chain not in chains: chain = chains[0] index = chains.index(chain) self.changeChain(chain) self.chainPulldown.setup(names, chains, index) def updateStructures(self): index = 0 names = [] structures = [] structure = self.structure if self.run: model = self.run.findFirstInputStructure() if model: structure = model.structureEnsemble structures0 = [(s.ensembleId, s) for s in self.project.structureEnsembles] structures0.sort() for eId, structure in structures0: name = '%s:%s' % (structure.molSystem.code, eId) structures.append(structure) names.append(name) if structures: if structure not in structures: structure = structures[-1] index = structures.index(structure) self.changeStructure(structure) self.structurePulldown.setup(names, structures, index) def updateModels(self): textMatrix = [] objectList = [] colorMatrix = [] if self.structure and self.run: used = self.run.inputStructures for model in self.structure.sortedModels(): if model in used: colors = [None, CING_BLUE] use = 'Yes' else: colors = [None, None] use = 'No' datum = [model.serial,use] textMatrix.append(datum) objectList.append(model) colorMatrix.append(colors) self.modelTable.update(objectList=objectList, textMatrix=textMatrix, colorMatrix=colorMatrix) def changeStructure(self, structure): if self.project and (self.structure is not structure): self.project.currentEstructureEnsemble = structure self.structure = structure if self.run: self.run.inputStructures = structure.sortedModels() self.updateModels() self.updateChains() def changeChain(self, chain): if self.project and (self.chain is not chain): self.chain = chain self.updateResidues() def chooseValidScript(self): # Prepend default Cyana file extension below fileTypes = [ FileType('Python', ['*.py']), ] popup = FileSelectPopup(self, file_types = fileTypes, title='Python file', dismiss_text='Cancel', selected_file_must_exist = True) fileName = popup.getFile() self.validScriptEntry.set(fileName) popup.destroy() def updateAll(self, project=None): if project: self.project = project self.nmrProject = project.currentNmrProject simStore = project.findFirstNmrSimStore(application='CING') or \ project.newNmrSimStore(application='CING', name='CING') else: simStore = None if not self.project: return self.setZipFileName() if not self.project.currentNmrProject: name = self.project.name self.nmrProject = self.project.newNmrProject(name=name) else: self.nmrProject = self.project.currentNmrProject self.update(simStore) def update(self, simStore=None): NmrSimRunFrame.update(self, simStore) run = self.run urls = [DEFAULT_URL,] index = 0 if run: userId = getRunParameter(run, iCingRobot.FORM_USER_ID) accessKey = getRunParameter(run, iCingRobot.FORM_ACCESS_KEY) if userId and accessKey: self.serverCredentials = [(iCingRobot.FORM_USER_ID, userId), (iCingRobot.FORM_ACCESS_KEY, accessKey)] url = getRunParameter(run, ICING_BASE_URL) if url: htmlUrl = getRunParameter(run, HTML_RESULTS_URL) self.iCingBaseUrl = url self.resultsUrl = htmlUrl # May be None self.resultUrlEntry.set(self.resultsUrl) if self.iCingBaseUrl and self.iCingBaseUrl not in urls: index = len(urls) urls.append(self.iCingBaseUrl) self.iCingBaseUrlPulldown.setup(urls, urls, index) self.updateButtons() self.updateStructures() self.updateModels() self.updateChains() def updateButtons(self, event=None): buttons = self.buttonBar.buttons if self.project and self.run: buttons[0].enable() if self.resultsUrl and self.serverCredentials: buttons[1].enable() buttons[2].enable() buttons[3].enable() else: buttons[1].disable() buttons[2].disable() buttons[3].disable() else: buttons[0].disable() buttons[1].disable() buttons[2].disable() buttons[3].disable()
class editResidueTypePopup(BasePopup): ''' The main popup that is shown when the macro is loaded. ''' def __init__(self, parent, *args, **kw): self.font = 'Helvetica 10' self.sFont = 'Helvetica %d' self.project = parent.project self.guiParent = parent self.chemCompDict = {} self.createChemCompDict() self.waiting = False BasePopup.__init__(self, parent, title="Residue Type Probabilities", **kw) def open(self): self.updateAfter() BasePopup.open(self) def body(self, guiFrame): '''Describes where all the GUI element are.''' self.geometry('400x500') guiFrame.expandGrid(0, 0) tableFrame = Frame(guiFrame) tableFrame.grid(row=0, column=0, sticky='nsew', ) tableFrame.expandGrid(0, 0) buttonFrame = Frame(guiFrame) buttonFrame.grid(row=1, column=0, sticky='nsew', ) headingList = ['Spinsystem Number', 'Assignment', 'Residue Type Probs'] self.table = ScrolledMatrix(tableFrame, headingList=headingList, callback=self.updateSpinSystemSelection, multiSelect=True) self.table.grid(row=0, column=0, sticky='nsew') texts = ['Add Prob'] commands = [self.addProb] self.AddProbButton = ButtonList(buttonFrame, commands=commands, texts=texts) self.AddProbButton.grid(row=0, column=0, sticky='nsew') texts = ['Remove Prob'] commands = [self.removeProb] self.AddProbButton = ButtonList(buttonFrame, commands=commands, texts=texts) self.AddProbButton.grid(row=0, column=2, sticky='nsew') selectCcpCodes = sorted(self.chemCompDict.keys()) tipText = 'select ccpCode' self.selectCcpCodePulldown = PulldownList(buttonFrame, texts=selectCcpCodes, grid=(0, 1), tipText=tipText) selectCcpCodes = ['All Residue Types'] tipText = 'select ccpCode' self.selectCcpCodeRemovePulldown = PulldownList(buttonFrame, texts=selectCcpCodes, index=0, grid=(0, 3), tipText=tipText) self.updateTable() def updateSpinSystemSelection(self, obj, row, col): '''Called after selectin a row in the table.''' self.updateRemoveCcpCodePullDown() def updateRemoveCcpCodePullDown(self): '''Updates the pulldown showing all current residueTypeProbs for a resonanceGroup that can be removed. ''' removeCcpCodes = [] for spinSystem in self.table.currentObjects: removeCcpCodes.extend([typeProp.possibility.ccpCode for typeProp in spinSystem.getResidueTypeProbs()]) removeCcpCodes = ['All Residue Types'] + list(set(removeCcpCodes)) self.selectCcpCodeRemovePulldown.setup(texts=removeCcpCodes, objects=removeCcpCodes, index=0) def getSpinSystems(self): '''Get resonanceGroups (spin systems) in the project.''' return self.nmrProject.resonanceGroups def addProb(self): '''Add the residue type selected in the selectCcpCodePulldown as an residueTypeProb. ''' ccpCode = self.selectCcpCodePulldown.object for spinSystem in self.table.currentObjects: if ccpCode not in [typeProp.possibility.ccpCode for typeProp in spinSystem.getResidueTypeProbs()]: chemComp = self.chemCompDict.get(ccpCode) spinSystem.newResidueTypeProb(possibility=chemComp) self.updateTable() self.updateRemoveCcpCodePullDown() def removeProb(self): '''Removes the residueTypeProb selected in the selectCcpCodeRemovePulldown from the selected resonanceGroup. ''' ccpCode = self.selectCcpCodeRemovePulldown.object for spinSystem in self.table.currentObjects: residueTypeProbs = spinSystem.getResidueTypeProbs() for typeProb in residueTypeProbs: if ccpCode == 'All Residue Types' or ccpCode == typeProb.possibility.ccpCode: typeProb.delete() self.updateTable() self.updateRemoveCcpCodePullDown() def createChemCompDict(self): '''Make a list of all amino acid types present in any of the molecular chains present in the project. ''' chains = self.getChains() for chain in chains: for residue in chain.sortedResidues(): if residue.ccpCode not in self.chemCompDict: self.chemCompDict[residue.ccpCode] = residue.chemCompVar.chemComp def getChains(self): '''Get all molecular chains stored in the project.''' chains = [] if self.project: for molSystem in self.project.sortedMolSystems(): for chain in molSystem.sortedChains(): if chain.residues: chains.append(chain) return chains def updateTable(self): '''Update the whole table.''' objectList = [] data = [] for spinSystem in self.getSpinSystems(): objectList.append(spinSystem) residueTypeProbs = spinSystem.getResidueTypeProbs() spinSystemInfo = self.getStringDescriptionOfSpinSystem(spinSystem) probString = '' for typeProp in residueTypeProbs: probString += typeProp.possibility.ccpCode + ' ' data.append([spinSystem.serial, spinSystemInfo, probString]) self.table.update(objectList=objectList, textMatrix=data) def getStringDescriptionOfSpinSystem(self, spinsys): '''Get a simple identifier for the assignment status of a resonanceGroup. ''' spinSystemInfo = '' if spinsys.residue: spinSystemInfo += str(spinsys.residue.seqCode) + ' ' + spinsys.residue.ccpCode elif spinsys.residueProbs: for residueProb in spinsys.residueProbs: res = residueProb.possibility spinSystemInfo += '{} {}? /'.format(res.seqCode, res.ccpCode) spinSystemInfo = spinSystemInfo[:-1] elif spinsys.ccpCode: spinSystemInfo += spinsys.ccpCode return spinSystemInfo
class SpectrumSelectionTab(object): '''Class describing the tab containing a big table with all the spectra. The user can select which spectra from the project to use with the assignment algorithm. For each spectrum a peak list and a labelling scheme can be selected. ''' def __init__(self, parent, frame): '''Init. args: parent: the guiElement that this tab is part of. frame: the frame this part of the GUI lives in. ''' self.guiParent = parent self.frame = frame self.project = parent.project self.nmrProject = parent.nmrProject self.specConfigList = [] self.displayTable = None self.selectedAutoSpec = None self.autoLabellingPulldown = None self.autoPeakListPulldown = None self.body() self.updateSpecSelection() # self.setupSpectrumSettings() self.updateAutoMatrix() def body(self): '''Sets up the body of this view.''' frame = self.frame frame.grid_rowconfigure(2, weight=1) frame.grid_columnconfigure(0, weight=1) headingList = [ '#', 'Spectrum', 'Peak List', 'use?', 'labelling scheme'] tipTexts = ['Row number', 'spectrum name', 'which peak list to use', 'use this spectrum?', 'Which labelling scheme belongs to this spectrum?'] self.autoLabellingPulldown = PulldownList( self.guiParent, self.setAutoLabellingScheme) self.autoPeakListPulldown = PulldownList( self.guiParent, self.setAutoPeakList) editWidgets = [None, None, self.autoPeakListPulldown, None, self.autoLabellingPulldown] editGetCallbacks = [None, None, self.getAutoPeakLists, self.changeUse, self.getAutoLabellingSchemes] editSetCallbacks = [None, None, None, None, None] self.displayTable = ScrolledMatrix(frame, headingList=headingList, callback=self.selectAutoSpec, editWidgets=editWidgets, multiSelect=False, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, tipTexts=tipTexts) self.displayTable.grid(row=2, column=0, sticky='nsew') def updateSpecSelection(self): '''Update the list with spectrum settings. This function can be called to initialize this list or to update it when some spectra are added in the project. ''' # TODO: also implement what has to happen # when spectra get deleted from the project. presentSpectrumSettings = set([specSetting.ccpnSpectrum for specSetting in self.specConfigList]) for expt in self.nmrProject.sortedExperiments(): for spec in expt.sortedDataSources(): if spec.dataType == 'processed' and spec not in presentSpectrumSettings: newSpectrumSetting = SpectrumSettings() newSpectrumSetting.ccpnSpectrum = spec newSpectrumSetting.peakList = spec.getActivePeakList() self.specConfigList.append(newSpectrumSetting) def getLabellingSchemes(self): '''Returns all labellinSchemes in the project''' return [True, None, ] + self.project.sortedLabelingSchemes() def setAutoLabellingScheme(self, scheme): '''Select a labelling scheme for the selected spectrum. ''' self.selectedAutoSpec.setupLabellingScheme(scheme) self.updateAutoMatrix() def getAutoLabellingSchemes(self, notifyScheme=None): '''Sets up the the pulldown lists with labelling schemes used for the pulldown lists. ''' #names = [] #index = 0 # #scheme = self.selectedAutoSpec.labellingScheme #schemes = self.getLabellingSchemes() # # # if schemes: # names = ['Automatic from sample','<None>'] + [sc.name for sc in schemes[2:]] # # index = schemes.index(scheme) names = ['Automatic from sample'] schemes = [True] index = 0 self.autoLabellingPulldown.setup(names, schemes, index) def setAutoPeakList(self, peakList): '''Select a peakList for the selected spectrum.''' self.selectedAutoSpec.setupPeakList(peakList) self.updateAutoMatrix() def selectAutoSpec(self, obj, *args, **kwargs): '''Set the selection of a spectrum in the table. args: obj: (SpectrumSettings) the spectrum that should be selected. ''' self.selectedAutoSpec = obj def getAutoPeakLists(self, *args, **kwargs): '''Set up the the autoPeakListPulldown for the selected spectrum. ''' names = [] index = 0 peakList = self.selectedAutoSpec.peakList peakLists = self.selectedAutoSpec.ccpnSpectrum.sortedPeakLists() if peakLists: names = [str(pl.serial) for pl in peakLists] index = peakLists.index(peakList) self.autoPeakListPulldown.setup(names, peakLists, index) def changeUse(self, *args): '''Toggle whether a spectrum is used in the procedure or not. ''' if self.selectedAutoSpec.used is False: self.selectedAutoSpec.changeSpectrumUse(True) elif self.selectedAutoSpec.used is True: self.selectedAutoSpec.changeSpectrumUse(False) self.updateAutoMatrix() def updateAutoMatrix(self): '''Update the whole table.''' textMatrix = [] colorMatrix = [] spectra = self.specConfigList for i, spectrum in enumerate(spectra): dataSource = spectrum.ccpnSpectrum expt = dataSource.experiment name = '%s:%s' % (expt.name, dataSource.name) peakListName = str(spectrum.peakList.serial) if spectrum.labellingScheme is None: schemeName = 'None' elif spectrum.labellingScheme is True: schemeName = 'Automatic from sample' else: schemeName = spectrum.labellingScheme.name datum = [i + 1, name, peakListName, spectrum.used and 'Yes' or 'No', schemeName] textMatrix.append(datum) hexColors = dataSource.analysisSpectrum.posColors hexColor = hexColors[int(0.7 * len(hexColors))] if spectrum.used: colorMatrix.append([hexColor, hexColor, hexColor, hexColor, hexColor]) else: colorMatrix.append([hexColor, None, None, None, None]) self.displayTable.update(textMatrix=textMatrix, objectList=spectra, colorMatrix=colorMatrix) def update(self, *args): '''update the view''' self.updateSpecSelection() self.updateAutoMatrix()
def __init__(self, parent, application, *args, **kw): project = application.project simStore = project.findFirstNmrSimStore(application=APP_NAME) or \ project.newNmrSimStore(application=APP_NAME, name=APP_NAME) self.application = application self.residue = None self.structure = None self.serverCredentials = None self.iCingBaseUrl = DEFAULT_URL self.resultsUrl = None self.chain = None self.nmrProject = application.nmrProject self.serverDone = False NmrSimRunFrame.__init__(self, parent, project, simStore, *args, **kw) # # # # # # New Structure Frame # # # # # self.structureFrame.grid_forget() tab = self.tabbedFrame.frames[0] frame = Frame(tab, grid=(1,0)) frame.expandGrid(2,1) div = LabelDivider(frame, text='Structures', grid=(0,0), gridSpan=(1,2)) label = Label(frame, text='Ensemble: ', grid=(1,0)) self.structurePulldown = PulldownList(frame, callback=self.changeStructure, grid=(1,1)) headingList = ['Model','Use'] editWidgets = [None,None] editGetCallbacks = [None,self.toggleModel] editSetCallbacks = [None,None,] self.modelTable = ScrolledMatrix(frame, grid=(2,0), gridSpan=(1,2), callback=self.selectStructModel, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, headingList=headingList) texts = ['Activate Selected','Inactivate Selected'] commands = [self.activateModels, self.disableModels] buttons = ButtonList(frame, texts=texts, commands=commands, grid=(3,0), gridSpan=(1,2)) # # # # # # Submission frame # # # # # # tab = self.tabbedFrame.frames[1] tab.expandGrid(1,0) frame = LabelFrame(tab, text='Server Job Submission', grid=(0,0)) frame.expandGrid(None,2) srow = 0 label = Label(frame, text='iCing URL:', grid=(srow, 0)) urls = [DEFAULT_URL,] self.iCingBaseUrlPulldown = PulldownList(frame, texts=urls, objects=urls, index=0, grid=(srow,1)) srow +=1 label = Label(frame, text='Results File:', grid=(srow, 0)) self.resultFileEntry = Entry(frame, bd=1, text='', grid=(srow,1), width=50) self.setZipFileName() button = Button(frame, text='Choose File', bd=1, sticky='ew', command=self.chooseZipFile, grid=(srow, 2)) srow +=1 label = Label(frame, text='Results URL:', grid=(srow, 0)) self.resultUrlEntry = Entry(frame, bd=1, text='', grid=(srow,1), width=50) button = Button(frame, text='View Results HTML', bd=1, sticky='ew', command=self.viewHtmlResults, grid=(srow, 2)) srow +=1 texts = ['Submit Project!', 'Check Run Status', 'Purge Server Result', 'Download Results'] commands = [self.runCingServer, self.checkStatus, self.purgeCingServer, self.downloadResults] self.buttonBar = ButtonList(frame, texts=texts, commands=commands, grid=(srow, 0), gridSpan=(1,3)) for button in self.buttonBar.buttons[:1]: button.config(bg=CING_BLUE) # # # # # # Residue frame # # # # # # frame = LabelFrame(tab, text='Residue Options', grid=(1,0)) frame.expandGrid(1,1) label = Label(frame, text='Chain: ') label.grid(row=0,column=0,sticky='w') self.chainPulldown = PulldownList(frame, callback=self.changeChain) self.chainPulldown.grid(row=0,column=1,sticky='w') headingList = ['#','Residue','Linking','Decriptor','Use?'] editWidgets = [None,None,None,None,None] editGetCallbacks = [None,None,None,None,self.toggleResidue] editSetCallbacks = [None,None,None,None,None,] self.residueMatrix = ScrolledMatrix(frame, headingList=headingList, multiSelect=True, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, callback=self.selectResidue) self.residueMatrix.grid(row=1, column=0, columnspan=2, sticky = 'nsew') texts = ['Activate Selected','Inactivate Selected'] commands = [self.activateResidues, self.deactivateResidues] self.resButtons = ButtonList(frame, texts=texts, commands=commands,) self.resButtons.grid(row=2, column=0, columnspan=2, sticky='ew') """ # # # # # # Validate frame # # # # # # frame = LabelFrame(tab, text='Validation Options', grid=(2,0)) frame.expandGrid(None,2) srow = 0 self.selectCheckAssign = CheckButton(frame) self.selectCheckAssign.grid(row=srow, column=0,sticky='nw' ) self.selectCheckAssign.set(True) label = Label(frame, text='Assignments and shifts') label.grid(row=srow,column=1,sticky='nw') srow += 1 self.selectCheckResraint = CheckButton(frame) self.selectCheckResraint.grid(row=srow, column=0,sticky='nw' ) self.selectCheckResraint.set(True) label = Label(frame, text='Restraints') label.grid(row=srow,column=1,sticky='nw') srow += 1 self.selectCheckQueen = CheckButton(frame) self.selectCheckQueen.grid(row=srow, column=0,sticky='nw' ) self.selectCheckQueen.set(False) label = Label(frame, text='QUEEN') label.grid(row=srow,column=1,sticky='nw') srow += 1 self.selectCheckScript = CheckButton(frame) self.selectCheckScript.grid(row=srow, column=0,sticky='nw' ) self.selectCheckScript.set(False) label = Label(frame, text='User Python script\n(overriding option)') label.grid(row=srow,column=1,sticky='nw') self.validScriptEntry = Entry(frame, bd=1, text='') self.validScriptEntry.grid(row=srow,column=2,sticky='ew') scriptButton = Button(frame, bd=1, command=self.chooseValidScript, text='Browse') scriptButton.grid(row=srow,column=3,sticky='ew') """ # # # # # # # # # # self.update(simStore) self.administerNotifiers(application.registerNotify)
class CalcHeteroNoePopup(BasePopup): """ **Calculate Heteronuclear NOE Values From Peak Intensities** The purpose of this popup window is to calculate the heteronuclear NOE for amide resonances based upon a comparison of the peak intensities in spectra that derive from an NOE saturated experiment and an unsaturated (reference) experiment. The basic idea of this tool is that three peak lists are chosen, two of which are for heteronuclear NOE experiments (H,N axes); unsaturated reference and saturated, and one which is the source of assignments and peak locations. This last "Assignment" peak list may be the same as one of the NOE peak lists, but may also be entirely separate. The "Assignment" peak list is used to specify which peak assignments and locations should be used for the calculation of the heteronuclear NOE values, and thus can be used to specify only a subset of the resonances for measurement. For example, it is common to copy an HQSC peak list for use as the "Assignment" peak list but remove overlapped and NH2 peaks so that the NOE values are only calculated for separated backbone amides. The calculation process involves taking each of these assigned peaks and finding peaks with the same assignment in the NOE peak lists, or if that fails finding peaks with a similar position (within the stated tolerances); new peaks may be picked if the "Pick new peaks?" option is set. The first "Peak Lists & Settings" tab allows the user to choose the peak lists and various options that will be used in the peak-finding and NOE calculation. The "Peaks" table allows the peaks from each of the three peak list selections to be displayed when one of the "Show" buttons is clicked. The [Separate Peak Table] function allows these peaks to be displayed in the main, separate `Peak Lists`_ table, which has many more peak manipulation options. The options below the table may be used to locate selected peaks within the spectrum window displays. The second "Peak Intensity Comparison" tab is where the heteronuclear NOE values are actually calculated. Assuming that two NOE experiment peak lists have been chosen and that some of their peaks match the assigned peak positions then the peak intensities are extracted and NOE values automatically calculated when the tab is opened. Although, a refresh of the table can be forced with [Find Matching Peaks] at the bottom If pairs of NOE saturated and reference peaks are found then the actual heteronuclear NOE value is displayed as the "Intensity Ratio" in the last, rightmost, column of the table. To store these values as a NOE measurement list; so that the data can be saved in the CCPN project without need for recalculation, the [Create Hetero NOE List] function can be used. The results are then available to view at any time via the `Measurement Lists`_ table. **Caveats & Tips** Erroneous peak intensity comparisons may be removed with the [Remove Pairs] function, but its is common to curate the "Assign" peak list first and avoid tidying afterwards. The "Closeness score" can be used to find peak positions where the compared NOE peaks are unexpectedly far from one another. .. _`Peak Lists`: EditPeakListsPopup.html .. _`Measurement Lists`: EditMeasurementListsPopup.html """ def __init__(self, parent, *args, **kw): self.guiParent = parent self.peakPairs = [] self.intensityType = 'height' self.selectedPair = None self.assignPeakList = None self.refPeakList = None self.satPeakList = None self.displayPeakList = None self.waiting = 0 BasePopup.__init__(self, parent, title="Data Analysis : Heteronuclear NOE", **kw) def body(self, guiFrame): self.geometry('700x700') guiFrame.expandGrid(0,0) options = ['Peak Lists & Settings','Peak Intensity Comparison'] tabbedFrame = TabbedFrame(guiFrame, options=options, callback=self.changeTab) tabbedFrame.grid(row=0, column=0, sticky='nsew') self.tabbedFrame = tabbedFrame frameA, frameB = tabbedFrame.frames row = 0 frameA.grid_columnconfigure(1, weight=1) frameA.grid_columnconfigure(3, weight=1) frameA.grid_columnconfigure(5, weight=1) frameA.grid_rowconfigure(5, weight=1) tipText = 'Number of reference peaks (no saturation)' self.peaksALabel = Label(frameA, text='Number of Ref Peaks: ', tipText=tipText) self.peaksALabel.grid(row=1,column=0,columnspan=2,sticky='w') tipText = 'Number of NOE saturation peaks' self.peaksBLabel = Label(frameA, text='Number of Sat Peaks: ', tipText=tipText) self.peaksBLabel.grid(row=1,column=2,columnspan=2,sticky='w') tipText = 'Number of peaks in assigned list' self.peaksCLabel = Label(frameA, text='Number of Assign Peaks: ', tipText=tipText) self.peaksCLabel.grid(row=1,column=4,columnspan=2,sticky='w') tipText = 'Selects which peak list is considered the NOE intensity reference (no saturation)' specALabel = Label(frameA, text='Ref Peak List: ') specALabel.grid(row=0,column=0,sticky='w') self.specAPulldown = PulldownList(frameA, callback=self.setRefPeakList, tipText=tipText) self.specAPulldown.grid(row=0,column=1,sticky='w') tipText = 'Selects which peak list is considered as NOE saturated.' specBLabel = Label(frameA, text='Sat Peak List: ') specBLabel.grid(row=0,column=2,sticky='w') self.specBPulldown = PulldownList(frameA, callback=self.setSatPeakList, tipText=tipText) self.specBPulldown.grid(row=0,column=3,sticky='w') tipText = 'Selects a peak list with assignments to use as a positional reference' specCLabel = Label(frameA, text='Assignment Peak List: ') specCLabel.grid(row=0,column=4,sticky='w') self.specCPulldown = PulldownList(frameA, callback=self.setAssignPeakList, tipText=tipText) self.specCPulldown.grid(row=0,column=5,sticky='w') frame0a = Frame(frameA) frame0a.grid(row=2,column=0,columnspan=6,sticky='nsew') frame0a.grid_columnconfigure(9, weight=1) tipText = '1H ppm tolerance for matching assigned peaks to reference & NOE saturation peaks' tolHLabel = Label(frame0a, text='Tolerances: 1H') tolHLabel.grid(row=0,column=0,sticky='w') self.tolHEntry = FloatEntry(frame0a,text='0.02', width=6, tipText=tipText) self.tolHEntry .grid(row=0,column=1,sticky='w') tipText = '15N ppm tolerance for matching assigned peaks to reference & NOE saturation peaks' tolNLabel = Label(frame0a, text=' 15N') tolNLabel .grid(row=0,column=2,sticky='w') self.tolNEntry = FloatEntry(frame0a,text='0.1', width=6, tipText=tipText) self.tolNEntry .grid(row=0,column=3,sticky='w') tipText = 'Whether to peak new peaks in reference & NOE saturated lists (at assignment locations)' label = Label(frame0a, text=' Pick new peaks?', grid=(0,4)) self.pickPeaksSelect = CheckButton(frame0a, tipText=tipText, grid=(0,5), selected=True) tipText = 'Whether to assign peaks in the peaks in the reference & NOE saturation lists, if not already assigned' label = Label(frame0a, text=' Assign peaks?') label.grid(row=0,column=6,sticky='w') self.assignSelect = CheckButton(frame0a, tipText=tipText) self.assignSelect.set(1) self.assignSelect.grid(row=0,column=7,sticky='w') tipText = 'Whether to consider peak height or volume in the heteronuclear NOE calculation' intensLabel = Label(frame0a, text=' Intensity Type:') intensLabel .grid(row=0,column=8,sticky='w') self.intensPulldown = PulldownList(frame0a, texts=['height','volume'], callback=self.setIntensityType, tipText=tipText) self.intensPulldown.grid(row=0,column=9,sticky='w') divider = LabelDivider(frameA, text='Peaks', grid=(3,0), gridSpan=(1,6)) tipTexts = ['Show the selected intensity reference peaks in the below table', 'Show the selected NOE saturation peaks in the below table', 'Show the selected assigned peak list in the below table', 'Show the displayed peaks in a separate peak table, where assignments etc. may be adjusted'] texts = ['Show Ref Peaks','Show Sat Peaks', 'Show Assign Peaks', 'Separate Peak Table'] commands = [self.viewRefPeakList, self.viewSatPeakList, self.viewAssignPeakList, self.viewSeparatePeakTable] self.viewPeaksButtons = ButtonList(frameA, expands=True, tipTexts=tipTexts, texts=texts, commands=commands) self.viewPeaksButtons.grid(row=4,column=0,columnspan=6,sticky='nsew') self.peakTable = PeakTableFrame(frameA, self.guiParent, grid=(5,0), gridSpan=(1,6)) self.peakTable.bottomButtons1.grid_forget() self.peakTable.bottomButtons2.grid_forget() #self.peakTable.topFrame.grid_forget() self.peakTable.topFrame.grid(row=2, column=0, sticky='ew') # Next tab frameB.expandGrid(0,0) tipTexts = ['Row number', 'Assignment annotation for NOE saturation peak', 'Assignment annotation for reference peak (no saturation)', '1H chemical shift of NOE saturation peak', '1H chemical shift of reference peak', '15N chemical shift of NOE saturation peak', '15N chemical shift of reference peak', 'The separation between compared peaks: square root of the sum of ppm differences squared', 'The intensity if the NOE saturation peak', 'The intensity of the reference peak (no saturation)', 'Ratio of peak intensities: saturated over reference', 'Residue(s) for reference peak'] colHeadings = ['#','Sat Peak','Ref Peak','1H shift A', '1H shift B','15N shift A','15N shift B', 'Closeness\nScore','Intensity A','Intensity B', 'Intensity\nRatio','Residue'] self.scrolledMatrix = ScrolledMatrix(frameB, multiSelect=True, headingList=colHeadings, callback=self.selectCell, tipTexts=tipTexts, grid=(0,0), deleteFunc=self.removePair) tipTexts = ['Force a manual update of the table; pair-up NOE saturation and reference peaks according to assigned peak positions', 'Remove the selected rows of peak pairs', 'Show peaks corresponding to the selected row in a table', 'Save the Heteronuclear NOE values in the CCPN project as a data list'] texts = ['Refresh Table','Remove Pairs', 'Show Peak Pair','Create Hetero NOE List'] commands = [self.matchPeaks,self.removePair, self.showPeakPair,self.makeNoeList] self.pairButtons = ButtonList(frameB, tipTexts=tipTexts, grid=(1,0), texts=texts, commands=commands) bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, helpUrl=self.help_url) bottomButtons.grid(row=0, column=0, sticky='e') self.updatePulldowns() self.updateAfter() self.administerNotifiers(self.registerNotify) def administerNotifiers(self, notifyFunc): for func in ('__init__', 'delete','setName'): for clazz in ('ccp.nmr.Nmr.DataSource', 'ccp.nmr.Nmr.Experiment',): notifyFunc(self.updatePulldowns, clazz, func) for func in ('__init__', 'delete'): notifyFunc(self.updatePulldowns,'ccp.nmr.Nmr.PeakList', func) for func in ('__init__', 'delete','setAnnotation','setFigOfMerit'): notifyFunc(self.updatePeaks, 'ccp.nmr.Nmr.Peak', func) for func in ('setAnnotation','setPosition','setNumAliasing'): notifyFunc(self.updatePeakChild, 'ccp.nmr.Nmr.PeakDim', func) for func in ('__init__', 'delete', 'setValue'): notifyFunc(self.updatePeakChild, 'ccp.nmr.Nmr.PeakIntensity', func) def changeTab(self, index): if index == 1: self.matchPeaks() def open(self): self.updatePulldowns() self.updateAfter() BasePopup.open(self) def destroy(self): self.administerNotifiers(self.unregisterNotify) BasePopup.destroy(self) def updatePulldowns(self, *obj): index0 = 0 index1 = 0 index2 = 0 names, peakLists = self.getPeakLists() if names: if self.refPeakList not in peakLists: self.refPeakList = peakLists[0] if self.satPeakList not in peakLists: self.satPeakList = peakLists[0] if self.assignPeakList not in peakLists: self.assignPeakList = peakLists[0] index0 = peakLists.index(self.refPeakList) index1 = peakLists.index(self.satPeakList) index2 = peakLists.index(self.assignPeakList) self.specAPulldown.setup(names, peakLists, index0) self.specBPulldown.setup(names, peakLists, index1) self.specCPulldown.setup(names, peakLists, index2) def updatePeakChild(self,peakChild): if self.waiting: return self.updatePeaks(peakChild.peak) def updatePeaks(self, peak): if self.waiting: return if peak.peakList in (self.refPeakList,self.satPeakList,self.assignPeakList): if peak.isDeleted and (peak.peakList in (self.refPeakList,self.satPeakList) ): for peaks in self.peakPairs: if peak in peaks: self.peakPairs.remove(peaks) if self.selectedPair is peaks: self.selectedPair = None self.updateAfter() return self.updateAfter() def setIntensityType(self, intensityType): self.intensityType = intensityType self.updateAfter() def viewRefPeakList(self): if self.refPeakList: self.updatePeakTable(self.refPeakList) def viewSatPeakList(self): if self.satPeakList: self.updatePeakTable(self.satPeakList) def viewAssignPeakList(self): if self.assignPeakList: self.updatePeakTable(self.assignPeakList) def viewSeparatePeakTable(self): if self.displayPeakList: self.guiParent.editPeakList(peakList=self.displayPeakList) def setRefPeakList(self, refPeakList): if self.displayPeakList is self.refPeakList: self.updatePeakTable(refPeakList) self.refPeakList = refPeakList self.updateViewButtons() self.updateAfter() def setSatPeakList(self, satPeakList): if self.displayPeakList is self.satPeakList: self.updatePeakTable(satPeakList) self.satPeakList = satPeakList self.updateViewButtons() self.updateAfter() def setAssignPeakList(self, assignPeakList): if self.displayPeakList is self.assignPeakList: self.updatePeakTable(assignPeakList) self.assignPeakList = assignPeakList self.updateViewButtons() self.updateAfter() def getPeakListName(self, peakList): if peakList: spectrum = peakList.dataSource experiment = spectrum.experiment name = '%s:%s:%d' % (experiment.name, spectrum.name, peakList.serial) else: name = '<None>' return name def getPeakLists(self): names = [] peakLists = [] for experiment in self.nmrProject.sortedExperiments(): for dataSource in experiment.sortedDataSources(): if dataSource.numDim == 2: dimsN = findSpectrumDimsByIsotope(dataSource,'15N') dimsH = findSpectrumDimsByIsotope(dataSource,'1H') if len(dimsN) == 1 and len(dimsH) == 1: for peakList in dataSource.sortedPeakLists(): name = self.getPeakListName(peakList) names.append( name ) peakLists.append(peakList) return names, peakLists def showPeakPair(self): if self.selectedPair: self.guiParent.viewPeaks(self.selectedPair) def selectCell(self, object, row, col): self.selectedPair = object if self.selectedPair: self.pairButtons.buttons[1].enable() self.pairButtons.buttons[2].enable() else: self.pairButtons.buttons[1].disable() self.pairButtons.buttons[2].disable() def removePair(self, *event): pairs = self.scrolledMatrix.currentObjects if pairs: for pair in pairs: self.peakPairs.remove(pair) self.selectedPair = None self.updateAfter() def matchPeaks(self): # assign relative to reference if self.assignPeakList and self.assignPeakList.peaks and self.refPeakList and self.satPeakList: tolH = float( self.tolHEntry.get() ) tolN = float( self.tolNEntry.get() ) pickNewPeaks = self.pickPeaksSelect.get() doAssign = self.assignSelect.get() dimH = findSpectrumDimsByIsotope(self.assignPeakList.dataSource,'1H' )[0] dimHA = findSpectrumDimsByIsotope(self.refPeakList.dataSource,'1H' )[0] dimHB = findSpectrumDimsByIsotope(self.satPeakList.dataSource,'1H' )[0] dimN = 1-dimH dimNA = 1-dimHA dimNB = 1-dimHB tolerancesA = [0,0] tolerancesA[dimHA] = tolH tolerancesA[dimNA] = tolN tolerancesB = [0,0] tolerancesB[dimHB] = tolH tolerancesB[dimNB] = tolN self.peakPairs = matchHnoePeaks(self.assignPeakList,self.refPeakList, self.satPeakList,tolerancesA,tolerancesB, pickNewPeaks,doAssign) self.updateAfter() def makeNoeList(self): if self.refPeakList is self.satPeakList: showWarning('Same Peak List', 'Ref Peak List and Sat Peak List cannot be the same', parent=self) return if self.peakPairs: s1 = self.refPeakList.dataSource s2 = self.satPeakList.dataSource noiseRef = getSpectrumNoise(s1) noiseSat = getSpectrumNoise(s2) es = '%s-%s' % (s1.experiment.name,s2.experiment.name) if len(es) > 50: es = 'Expt(%d)-Expt(%d)' % (s1.experiment.serial,s2.experiment.serial) noeList = self.nmrProject.newNoeList(unit='None',name='Hetero NOE list for %s' % es) noeList.setExperiments([s1.experiment,]) if s1.experiment is not s2.experiment: noeList.addExperiment( s2.experiment ) # TBD: sf, noeValueType, refValue, refDescription resonancePairsSeen = set() for (peakA,peakB) in self.peakPairs: # peakA is sat intensA = getPeakIntensity(peakA,self.intensityType) intensB = getPeakIntensity(peakB,self.intensityType) value = float(intensA)/intensB error = abs(value) * sqrt((noiseSat/intensA)**2 + (noiseRef/intensB)**2) resonances = tuple(self.getPeakResonances(peakA)) frozenResonances = frozenset(resonances) if len(resonances) < 2: pl = peakA.peakList sp = pl.dataSource msg = 'Skipping %s:%s:%d peak %d it has too few resonances assigned' data = (sp.experiment.name, sp.name, pl.serial, peakA.serial) showWarning('Warning',msg % data, parent=self) elif len(resonances) > 2: pl = peakA.peakList sp = pl.dataSource resonanceText = ' '.join([makeResonanceGuiName(r) for r in resonances]) msg = 'Skipping %s:%s:%d peak %d it has too many resonances assigned (%s)' data = (sp.experiment.name, sp.name, pl.serial, peakA.serial, resonanceText) showWarning('Warning', msg % data, parent=self) elif frozenResonances not in resonancePairsSeen: resonancePairsSeen.add(frozenResonances) noeList.newNoe(value=value,resonances=resonances,peaks=[peakA,peakB],error=error) else: resonanceText = ' '.join([makeResonanceGuiName(r) for r in resonances]) msg = 'Skipping duplicate entry for resonances %s' % resonanceText showWarning('Warning', msg, parent=self) self.parent.editMeasurements(measurementList=noeList) def getPeakResonances(self,peak): resonances = [] for peakDim in peak.sortedPeakDims(): for contrib in peakDim.sortedPeakDimContribs(): resonances.append(contrib.resonance) return resonances def updateAfter(self, *opt): if self.waiting: return else: self.waiting = True self.after_idle(self.update) def updateViewButtons(self): if self.refPeakList: self.viewPeaksButtons.buttons[0].enable() else: self.viewPeaksButtons.buttons[0].disable() if self.satPeakList: self.viewPeaksButtons.buttons[1].enable() else: self.viewPeaksButtons.buttons[1].disable() if self.assignPeakList: self.viewPeaksButtons.buttons[2].enable() else: self.viewPeaksButtons.buttons[2].disable() def updatePeakTable(self, peakList): if peakList is not self.displayPeakList: self.displayPeakList = peakList self.peakTable.update(peaks=peakList.sortedPeaks()) def update(self): if self.refPeakList: self.peaksALabel.set( 'Number of Ref Peaks: %d' % len(self.refPeakList.peaks) ) else: self.peaksALabel.set( 'Number of Ref Peaks: %d' % 0 ) if self.satPeakList: self.peaksBLabel.set( 'Number of Sat Peaks: %d' % len(self.satPeakList.peaks) ) else: self.peaksBLabel.set( 'Number of Sat Peaks: %d' % 0 ) if self.assignPeakList: self.peaksCLabel.set( 'Number of Assign Peaks: %d' % len(self.assignPeakList.peaks) ) else: self.peaksCLabel.set( 'Number of Assign Peaks: %d' % 0 ) if self.refPeakList and self.satPeakList and self.assignPeakList: if self.refPeakList is self.satPeakList: self.pairButtons.buttons[0].disable() else: self.pairButtons.buttons[0].enable() else: self.pairButtons.buttons[0].disable() if self.selectedPair: self.pairButtons.buttons[1].enable() self.pairButtons.buttons[2].enable() else: self.pairButtons.buttons[1].disable() self.pairButtons.buttons[2].disable() if self.peakPairs: self.pairButtons.buttons[3].enable() dsA = self.peakPairs[0][0].peakList.dataSource dsB = self.peakPairs[0][1].peakList.dataSource dimHA = findSpectrumDimsByIsotope(dsA,'1H')[0] dimHB = findSpectrumDimsByIsotope(dsB,'1H')[0] dimNA = findSpectrumDimsByIsotope(dsA,'15N')[0] dimNB = findSpectrumDimsByIsotope(dsB,'15N')[0] else: self.pairButtons.buttons[3].disable() objectList = [] textMatrix = [] i = 0 for (peakA,peakB) in self.peakPairs: i += 1 peakDimsA = peakA.sortedPeakDims() peakDimsB = peakB.sortedPeakDims() ppm0 = peakDimsA[dimHA].value ppm1 = peakDimsB[dimHB].value ppm2 = peakDimsA[dimNA].value ppm3 = peakDimsB[dimNB].value d0 = abs(ppm0-ppm1) d1 = abs(ppm2-ppm3) intensA = getPeakIntensity(peakA,self.intensityType) intensB = getPeakIntensity(peakB,self.intensityType) datum = [] datum.append( i ) datum.append( getPeakAnnotation(peakA, doPeakDims=False) ) datum.append( getPeakAnnotation(peakB, doPeakDims=False) ) datum.append( ppm0 ) datum.append( ppm1 ) datum.append( ppm2 ) datum.append( ppm3 ) datum.append( sqrt((d0*d0)+(d1*d1)) ) datum.append( intensA ) datum.append( intensB ) if intensB: datum.append( float(intensA)/intensB ) else: datum.append( None ) seqCodes = ','.join(['%s' % seqCode for seqCode in getPeakSeqCodes(peakB)]) datum.append(seqCodes) objectList.append( (peakA,peakB) ) textMatrix.append( datum ) if not objectList: textMatrix.append([]) self.scrolledMatrix.update(objectList=objectList, textMatrix=textMatrix) self.waiting = False
def __init__(self, guiParent, ccpnProject=None, **kw): self.guiParent = guiParent self.project = ccpnProject self.spectrum = None self.peakMode = 0 if ccpnProject: self.nmrProject = ccpnProject.currentNmrProject else: self.nmrProject = None Frame.__init__(self, guiParent, **kw) self.expandGrid(0,0) options = ['Peak Picking',] #,'About Auremol' 'NOE assignment','Homology Modelling',] self.tabbedFrame = TabbedFrame(self, options=options) self.tabbedFrame.grid(row=0,column=0,sticky='nsew') frameA = self.tabbedFrame.frames[0] #frameC.grid_columnconfigure(0, weight=1) #frameC.grid_rowconfigure(0, weight=1) #frameD.grid_columnconfigure(0, weight=1) #frameD.grid_rowconfigure(0, weight=1) # # Frame A # frameA.expandGrid(2,0) frameA.expandGrid(3,0) frameA.expandGrid(4,0) frameA.expandGrid(5,0) frame = Frame(frameA, grid=(0,0)) frame.expandGrid(0,4) label = Label(frame, text='Spectrum:', grid=(0,0)) self.spectrumPulldown = PulldownList(frame, self.changeSpectrum, grid=(0,1)) label = Label(frame, text=' Use Peak Sign:', grid=(0,2)) self.peakModePulldown = PulldownList(frame, self.changePeakMode, texts=PEAK_MODES, objects=[0,1,2], grid=(0,3)) frame = Frame(frameA, grid=(1,0)) frame.expandGrid(0,4) label = Label(frame, text='Integration Depth (Relative to max):', grid=(1,0)) self.segLevelEntry = FloatEntry(frame, text=0.1, grid=(1,1), width=8) label = Label(frame, text='Threshold (Threshold only):', grid=(1,3)) self.thresholdEntry = IntEntry(frame, text=100000, grid=(1,4), width=8) label = Label(frame, text='Keep Peaks (Adaptive only):', grid=(1,5)) self.keepPeakEntry = IntEntry(frame, text=4000, grid=(1,6), width=8) texts = ['Threshold\nPeak Pick','Adaptive\nPeak Pick'] commands = [self.pickThreshold, self.pickAdaptive] self.buttons = ButtonList(frameA, texts=texts, commands=commands, grid=(2,0), sticky='NSEW') frame = Frame(frameA, grid=(3,0)) frame.expandGrid(0,0) frame = Frame(frameA, grid=(4,0)) frame.expandGrid(0,0) frame = Frame(frameA, grid=(5,0)) frame.expandGrid(0,0) # # About """ frameB.expandGrid(4,0) label = Label(frameB, text='References', font='Helvetica 12 bold') label.grid(row=0, column=0, sticky='w') text = * Gronwald W, Brunner K, Kirchhofer R, Nasser A, Trenner J, Ganslmeier B, Riepl H, Ried A, Scheiber J, Elsner R, Neidig K-P, Kalbitzer HR AUREMOL, a New Program for the Automated Structure Elucidation of Biological Macromolecules Bruker Reports 2004; 154/155: 11-14 * Ried A, Gronwald W, Trenner JM, Brunner K, Neidig KP, Kalbitzer HR Improved simulation of NOESY spectra by RELAX-JT2 including effects of J-coupling, transverse relaxation and chemical shift anisotrophy J Biomol NMR. 2004 Oct;30(2):121-31 * Gronwald W, Moussa S, Elsner R, Jung A, Ganslmeier B, Trenner J, Kremer W, Neidig KP, Kalbitzer HR Automated assignment of NOESY NMR spectra using a knowledge based method (KNOWNOE) J Biomol NMR. 2002 Aug;23(4):271-87 * Gronwald W, Kirchhofer R, Gorler A, Kremer W, Ganslmeier B, Neidig KP, Kalbitzer HR RFAC, a program for automated NMR R-factor estimation J Biomol NMR. 2000 Jun;17(2):137-51 label = Label(frameB, text=text) label.grid(row=1, column=0, sticky='w') """ # # Frame C # # # Frame D # self.updateAll()
class EditFitGraphPopup(BasePopup): """ **Analyse Function Curve Fitting to Peak Series Data** This popup is used to display the fit of a curve, of the displayed equation type, to data that has been extracted for a group of spectrum peaks from an NMR series. Precisely which kind of data is being fitted depends on the parent tool that this popup window was launched from. For example, for the `Follow Intensity Changes`_ tool the displayed graph is of a time or frequency value on the "X" axis (e.g. T1) verses peak intensity. For the `Follow Shift Changes`_ system the plot is for the parameters of the experiment titration on the "X" axis (e.g concentration) verses chemical shift distance. The upper graph shows the peak data that was used; the blue points, and the points of the fitted theoretical curve; red points. The lower table lists the data points for all of the peaks in the group, to which the data relates. There will be one peak for each row of the table, and hence point on the "X" axis. For each data point in the table the corresponding peak from which the data was extracted may be located with the "Follow in window" option, using the stated spectrum window and making marker lines as desired. Alternatively, the peak may be viewed in a table with [Show Peak] In general operation this system is used to check how well the selected function curve fits the peak data. The data that is displayed comes from the analysis tool that launched this popup. Any outliers may be removed using [Remove Point] (only with good reason) or the peaks themselves may be corrected if something has gone awry. Given that the display is launched from the selection of a specific group of peaks from a popup like `Follow Shift Changes`_ or `Follow Intensity Changes`_ and there are usually several peak groups that need to be analysed, the [Previous Set] and [Next Set] buttons can be used to quickly jump to the next peak group and see the next curve in the analysis results. .. _`Follow Intensity Changes`: CalcRatesPopup.html .. _`Follow Shift Changes`: FollowShiftChangesPopup.html """ def __init__(self, parent, dataFitting, getXYfunction, updateFunction, xLabel, yLabel, showObjectFunction=None, nextSetFunction=None, prevSetFunction=None, graphTitle='', **kw): self.guiParent = parent self.getXYfunction = getXYfunction self.updateFunction = updateFunction self.nextSetFunction = nextSetFunction self.prevSetFunction = prevSetFunction self.dataFitting = dataFitting self.object = None self.xLabel = xLabel self.yLabel = yLabel self.x = [] self.y = [] self.yFit = [] self.params = () self.chiSq = 0 self.method = dataFitting.fitFunction self.waiting = False self.noiseLevel = dataFitting.noiseLevel self.graphTitle = graphTitle self.windowPane = None self.mark = None BasePopup.__init__(self, parent=parent, title='Fit Graph', **kw) parent.protocol("WM_DELETE_WINDOW", self.close) def body(self, guiFrame): guiFrame.grid_columnconfigure(0, weight=1) row = 0 self.scrolledGraph = ScrolledGraph(guiFrame, width=400, height=300, symbolSize=5, symbols=['square', 'circle'], dataColors=['#000080', '#800000'], lineWidths=[0, 1], grid=(row, 0)) #self.scrolledGraph.setZoom(0.7) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') label = Label(frame, text='Fitting Function:', grid=(0, 0)) tipText = 'Selects which form of function to fit to the experimental data' self.methodPulldown = PulldownList(frame, self.changeMethod, grid=(0, 1), tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') tipText = 'The effective equation of the final fitted graph, incorporating all parameters' self.equationLabel = Label(frame, text='Equation:', grid=(0, 0), tipText=tipText) tipText = 'The error in the fit of the selected parameterised function to the experimental data' self.errorLabel = Label(frame, text='Fit Error:', grid=(0, 1), tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') label = Label(frame, text='Include x origin?:', grid=(0, 0)) tipText = 'Whether to include the x=0 point in the drawing' self.xOriginSelect = CheckButton(frame, callback=self.draw, grid=(0, 1), selected=False, tipText=tipText) label = Label(frame, text='Include y origin?:', grid=(0, 2)) tipText = 'Whether to include the y=0 point in the drawing' self.yOriginSelect = CheckButton(frame, callback=self.draw, grid=(0, 3), selected=False, tipText=tipText) label = Label(frame, text='Include y error?:', grid=(0, 4)) tipText = 'Whether to include the y error bars in the drawing (if these exist)' self.yErrorSelect = CheckButton(frame, callback=self.draw, grid=(0, 5), selected=False, tipText=tipText) row += 1 frame = Frame(guiFrame, grid=(row, 0), sticky='ew') label = Label(frame, text='Navigation Window:', grid=(0, 0)) tipText = 'Selects which spectrum window will be used for navigating to peak positions' self.windowPanePulldown = PulldownList(frame, self.changeWindow, grid=(0, 1), tipText=tipText) label = Label(frame, text='Follow in window?:', grid=(0, 2)) tipText = 'Whether to navigate to the position of the reference peak (for the group), in the selected window' self.followSelect = CheckButton(frame, callback=self.windowPaneNavigate, grid=(0, 3), selected=False, tipText=tipText) label = Label(frame, text='Mark Ref Peak?:', grid=(0, 4)) tipText = 'Whether to put a multi-dimensional cross-mark through the reference peak position, so it can be identified in spectra' self.markSelect = CheckButton(frame, callback=None, tipText=tipText, grid=(0, 5), selected=False) row += 1 guiFrame.grid_rowconfigure(row, weight=1) tipTexts = [ 'The number of the data point, in order of increasing X-axis value', 'For each point, the value of the parameter which is varied in the NMR series, e.g. T1, temperature, concentration etc.', 'For each point, the experimental value being fitted, e.g. peak intensity of chemical shift distance', 'The value of the best-fit function at the X-axis location', 'The difference between the experimental (Y-axis) value and the fitted value', 'The error in the experimental (Y-axis) value' ] headingList = ['Point', 'x', 'y', 'Fitted y', u'\u0394', 'y error'] self.scrolledMatrix = ScrolledMatrix(guiFrame, headingList=headingList, callback=self.selectObject, tipTexts=tipTexts, grid=(row, 0)) row += 1 tipTexts = [ 'Remove the selected data point, optionally removing the underlying peak', 'Show a table of spectrum peaks that correspond to the selected data point' ] texts = ['Remove Point', 'Show Peak'] commands = [self.removePoint, self.showObject] if self.prevSetFunction: texts.append('Previous Set') tipTexts.append( 'Move to the previous set of fitted values; the next group of peaks, often corresponding to a different residue or resonance' ) commands.append(self.prevSet) if self.nextSetFunction: tipTexts.append( 'Move to the next set of fitted values; the next group of peaks, often corresponding to a different residue or resonance' ) texts.append('Next Set') commands.append(self.nextSet) bottomButtons = UtilityButtonList(guiFrame, texts=texts, commands=commands, helpUrl=self.help_url, tipTexts=tipTexts, grid=(row, 0), doClone=False) self.removeButton = bottomButtons.buttons[0] for func in ('__init__', 'delete', 'setName'): self.registerNotify(self.updateWindows, 'ccpnmr.Analysis.SpectrumWindow', func) self.update() def destroy(self): for func in ('__init__', 'delete', 'setName'): self.unregisterNotify(self.updateWindows, 'ccpnmr.Analysis.SpectrumWindow', func) BasePopup.destroy(self) def nextSet(self): if self.nextSetFunction: self.nextSetFunction() self.windowPaneNavigate() def prevSet(self): if self.prevSetFunction: self.prevSetFunction() self.windowPaneNavigate() def windowPaneNavigate(self, event=None): if self.followSelect.get() and self.dataFitting: peaks = self.dataFitting.objects if self.windowPane and peaks: peak = peaks[int(len(peaks) / 2)] windowFrame = self.windowPane.getWindowFrame() windowFrame.gotoPeak(peak) if self.markSelect.get(): if self.mark and not self.mark.isDeleted: self.mark.delete() self.mark = createPeakMark(self.dataFitting.refObject) def getWindows(self): peaks = self.scrolledMatrix.objectList windowPanes = [] if peaks: peak = peaks[0] project = peak.root spectrum = peak.peakList.dataSource tryWindows = getActiveWindows(project) for window in tryWindows: for windowPane in window.sortedSpectrumWindowPanes(): if isSpectrumInWindowPane(windowPane, spectrum): windowPanes.append(windowPane) return windowPanes def changeWindow(self, windowPane): if windowPane is not self.windowPane: self.windowPane = windowPane self.windowPaneNavigate() def updateWindows(self, window=None): windowPanes = self.getWindows() index = -1 names = [getWindowPaneName(wp) for wp in windowPanes] windowPane = self.windowPane if windowPanes: if windowPane not in windowPanes: windowPane = windowPanes[0] index = windowPanes.index(windowPane) if windowPane is not self.windowPane: self.windowPane = windowPane self.windowPaneNavigate() self.windowPanePulldown.setup(names, windowPanes, index) def showObject(self): if self.object and (self.object.className == 'Peak'): peaks = [self.object] self.guiParent.guiParent.viewPeaks(peaks) def close(self): BasePopup.close(self) def changeMethod(self, index): if self.dataFitting: self.method = index self.dataFitting.fitFunction = self.method self.updateAfter() def updateMethods(self, *opt): n = len(METHOD_NAMES) if self.method >= n: self.method = 1 self.methodPulldown.setup(METHOD_NAMES, range(n), self.method) def selectObject(self, object, row, col): if object: self.object = object self.updateButtons() def removePoint(self): if self.object and (len(self.dataFitting.objects) > 2): self.dataFitting.objects.remove(self.object) if showYesNo('Query', 'Delete the corresponding %s?' % (self.object.className), parent=self): self.object.delete() self.updateAfter() def draw(self, *junk): title = '%s Function fit %s' % (self.graphTitle, METHOD_NAMES[self.method]) dataSet1 = [] dataSet2 = [] useErr = self.yErrorSelect.isSelected() if not useErr: useErr = None for i in range(len(self.scrolledMatrix.textMatrix)): row = self.scrolledMatrix.textMatrix[i] x = row[1] y = row[2] y2 = row[3] err = useErr and row[5] dataSet1.append([x, y, err]) dataSet2.append([x, y2]) dataSet1.sort() dataSet2.sort() if dataSet1 and dataSet2: drawOriginX = self.xOriginSelect.isSelected() drawOriginY = self.yOriginSelect.isSelected() self.scrolledGraph.update(dataSets=[dataSet1, dataSet2], xLabel=self.xLabel, yLabel=self.yLabel, title=title, drawOriginX=drawOriginX, drawOriginY=drawOriginY) self.scrolledGraph.draw() def updateAfter(self, *object): if self.waiting: return else: self.waiting = True self.after_idle(self.update) def update(self, dataFitting=None, xLabel=None, yLabel=None, graphTitle=None, force=False): if (not force) and dataFitting and (self.dataFitting is dataFitting): if (self.method, self.xLabel, self.yLabel, self.noiseLevel) == \ (self.dataFitting.fitFunction, xLabel, yLabel, self.dataFitting.noiseLevel): self.waiting = False return if dataFitting: self.dataFitting = dataFitting self.xLabel = xLabel or self.xLabel self.yLabel = yLabel or self.yLabel self.graphTitle = graphTitle or self.graphTitle if not self.dataFitting: self.waiting = False return else: dataFitting = self.dataFitting dataFitting = self.getXYfunction(dataFitting) if dataFitting.fitFunction is not None: self.method = dataFitting.fitFunction self.noiseLevel = dataFitting.noiseLevel or self.noiseLevel self.updateMethods() isFitted = dataFitting.fit() textMatrix = [] objectList = [] if isFitted and self.method: methodInfo = getFitMethodInfo()[self.method - 1] textFormat, indices = methodInfo[2] textParams = [dataFitting.parameters[i] or 0 for i in indices] equationText = textFormat % tuple(textParams) errorText = '%4f' % dataFitting.fitError x = dataFitting.dataX y = dataFitting.dataY yFit = dataFitting.fittedY N = len(x) err = hasattr(dataFitting, 'dataErr') and dataFitting.dataErr if not err: err = None # wb104: 10 Mar 2014: not sure why the below was here, it isn't needed #if self.method == 10: # x = [sqrt(v) for v in x] data = [(x[i], y[i], yFit[i], y[i] - yFit[i], dataFitting.objects[i], err and err[i]) for i in range(N)] data.sort() for i in range(N): xi, yi, yFiti, deltai, object, erri = data[i] textMatrix.append([i + 1, xi, yi, yFiti, deltai, erri]) objectList.append(object) else: equationText = 'Equation: <No Fit>' errorText = '<None>' x = dataFitting.dataX y = dataFitting.dataY for i, x in enumerate(x): textMatrix.append([i + 1, x, y[i], None, None, None]) objectList.append(dataFitting.objects[i]) self.equationLabel.set('Equation: %s' % equationText) self.errorLabel.set('Fit Error: %s' % errorText) self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList) self.updateWindows() self.updateButtons() self.draw() if self.updateFunction: self.updateFunction(dataFitting) self.waiting = False def updateButtons(self): if self.object: self.removeButton.enable() else: self.removeButton.disable()
def body(self, guiFrame): guiFrame.grid_columnconfigure(2, weight=1) row = 0 label = Label(guiFrame, text='Template window: ', grid=(row, 0)) tipText = 'Selects which window to use as the basis for making a new spectrum window; sets the axis types accordingly' self.window_list = PulldownList(guiFrame, grid=(row, 1), callback=self.setAxisTypes, tipText=tipText) frame = LabelFrame(guiFrame, text='Strips', grid=(row, 2), gridSpan=(2, 1)) buttons = UtilityButtonList(guiFrame, doClone=False, helpUrl=self.help_url, grid=(row, 3)) row += 1 label = Label(guiFrame, text='New window name: ', grid=(row, 0)) tipText = 'A short name to identify the spectrum window, which will appear in the graphical interface' self.nameEntry = Entry(guiFrame, width=16, grid=(row, 1), tipText=tipText) row += 1 label = Label(frame, text='Columns: ', grid=(0, 0)) tipText = 'The number of vertical strips/dividers to initially make in the spectrum window' self.cols_menu = PulldownList(frame, objects=STRIP_NUMS, grid=(0, 1), texts=[str(x) for x in STRIP_NUMS], tipText=tipText) label = Label(frame, text='Rows: ', grid=(0, 2)) tipText = 'The number of horizontal strips/dividers to initially make in the spectrum window' self.rows_menu = PulldownList(frame, objects=STRIP_NUMS, grid=(0, 3), texts=[str(x) for x in STRIP_NUMS], tipText=tipText) row += 1 div = LabelDivider(guiFrame, text='Axes', grid=(row, 0), gridSpan=(1, 4)) row += 1 self.axis_lists = {} frame = Frame(guiFrame, grid=(row, 0), gridSpan=(1, 4)) col = 0 self.axisTypes = {} self.axisTypesIncludeNone = {} for label in AXIS_LABELS: self.axisTypes[label] = None w = Label(frame, text=' ' + label) w.grid(row=0, column=col, sticky='w') col += 1 if label in ('x', 'y'): includeNone = False tipText = 'Sets the kind of measurement (typically ppm for a given isotope) that will be used along the window %s axis' % label else: includeNone = True tipText = 'Where required, sets the kind of measurement (typically ppm for a given isotope) that will be used along the window %s axis' % label self.axisTypesIncludeNone[label] = includeNone getAxisTypes = lambda label=label: self.getAxisTypes(label) callback = lambda axisType, label=label: self.changedAxisType( label, axisType) self.axis_lists[label] = PulldownList(frame, callback=callback, tipText=tipText) self.axis_lists[label].grid(row=0, column=col, sticky='w') col += 1 frame.grid_columnconfigure(col, weight=1) row += 1 div = LabelDivider(guiFrame, text='Viewed Spectra', grid=(row, 0), gridSpan=(1, 4)) row += 1 guiFrame.grid_rowconfigure(row, weight=1) editWidgets = [None, None, None, None] editGetCallbacks = [None, self.toggleVisible, self.toggleToolbar, None] editSetCallbacks = [None, None, None, None] tipTexts = [ 'The "experiment:spectrum" name for the spectrum that may be viewed in the new window, given the axis selections', 'Sets whether the spectrum contours will be visible in the new window', 'Sets whether the spectrum appears at all in the window; if not in the toolbar it cannot be displayed', 'The number of peak lists the spectrum contains' ] headingList = ['Spectrum', 'Visible?', 'In Toolbar?', 'Peak Lists'] self.scrolledMatrix = ScrolledMatrix(guiFrame, headingList=headingList, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, multiSelect=True, grid=(row, 0), gridSpan=(1, 4), tipTexts=tipTexts) row += 1 tipTexts = [ 'Creates a new spectrum window with the specified parameters', 'Sets the contours of the selected spectra to be visible when the new window is made', 'Sets the contours of the selected spectra to not be displayed when the new window is made', 'Sets the selected spectra as absent from the window toolbar, and thus not displayable at all' ] texts = [ 'Create Window!', 'Selected\nVisible', 'Selected\nNot Visible', 'Selected\nNot In Toolbar' ] commands = [ self.ok, self.setSelectedDisplay, self.setSelectedHide, self.setSelectedAbsent ] buttonList = ButtonList(guiFrame, texts=texts, grid=(row, 0), commands=commands, gridSpan=(1, 4), tipTexts=tipTexts) buttonList.buttons[0].config(bg='#B0FFB0') self.updateAxisTypes() self.updateWindow() self.updateWindowName() self.administerNotifiers(self.registerNotify) self.updateAfter()
class EditExperimentSeriesPopup(BasePopup): """ **Setup Experiment Series for Chemical Shift and Intensity Changes** The purpose of this popup is to setup ordered groups of experiments that are related by the variation in some condition or parameter, but otherwise the kind of experiment being run is the same. For example the user could setup experiments for a temperature series, ligand binding titration or relaxation rate measurement. The layout is divided into two tables. The upper table shows all of the series that are known to the current project and the lower table shows all of the experiments or planes that comprise the selected series. These series relate to both groups of separate experiments (and hence spectra) and also single experiment where one dimension is not for NMR frequency but rather a "sampled" dimension and thus effectively combines many experiments (e.g. for different T1 values) as different planes. A stack of effectively 2D experiments combined in this manner is typically referred to as pseudo-3D. - The experiment is 3D but there are only two NMR dimensions. Series which are stacks of planes in a single experiment entity are automatically detected and entered into the table once they are loaded. Series that are constructed from multiple, separate experiments however must be setup by the user. To setup a new series of this kind [Add Series] makes a new, empty NMR series. Next the user should change the "Parameter varied" column to specify what type of thing is varied between the different experiments. The user then adds experiments into this series with the [Add Series Point] function at the bottom. Once the points have been added to the series the name of the experiment for each point may be changed. Initially, arbitrary experiments appear for the series points, so these almost always have to be adjusted. Once a stacked-plane experiment or series of experiments is setup, the user next sets (or checks) the value of the parameter associated with each point in the lower table. When loading stacked-plane experiments these values may come though automatically, if they are present in the spectrum header or parameter file. Given a completed NMR series specification the user may then extract the relevant data from the series using one of the analysis tools like `Follow Intensity Changes`_ or `Follow Shift Changes`_. **Caveats & Tips** Make sure the "Parameter Varied" for a given NMR series is appropriate to the type of analysis being performed. Many tools that extract T1 or Kd measurements for example look for specific types of series. The "Set/Unset Ref Plane" function is only used in certain kinds of series such as those that use trains of CPMG pulses. .. _`Follow Intensity Changes`: CalcRatesPopup.html .. _`Follow Shift Changes`: FollowShiftChangesPopup.html """ def __init__(self, parent, *args, **kw): self.guiParent = parent self.expSeries = None self.conditionPoint = None self.waiting = 0 BasePopup.__init__(self, parent, title="Experiment : NMR Series", **kw) def body(self, guiFrame): self.geometry("500x500") self.nameEntry = Entry(self, text='', returnCallback=self.setName, width=12) self.detailsEntry = Entry(self, text='', returnCallback=self.setDetails, width=16) self.valueEntry = FloatEntry(self, text='', returnCallback=self.setValue, width=10) self.errorEntry = FloatEntry(self, text='', returnCallback=self.setError, width=8) self.conditionNamesPulldown = PulldownList(self, callback=self.setConditionName, texts=self.getConditionNames()) self.unitPulldown = PulldownList(self, callback=self.setUnit, texts=self.getUnits()) self.experimentPulldown = PulldownList(self, callback=self.setExperiment) guiFrame.grid_columnconfigure(0, weight=1) row = 0 frame = Frame(guiFrame, grid=(row, 0)) frame.expandGrid(None,0) div = LabelDivider(frame, text='Current Series', grid=(0, 0)) utilButtons = UtilityButtonList(frame, helpUrl=self.help_url, grid=(0,1)) row += 1 frame0 = Frame(guiFrame, grid=(row, 0)) frame0.expandGrid(0,0) tipTexts = ['The serial number of the experiment series, but left blank if the series as actually a pseudo-nD experiment (with a sampled non-frequency axis)', 'The name of the experiment series, which may be a single pseudo-nD experiment', 'The number of separate experiments (and hence spectra) present in the series', 'The kind of quantity that varies for different experiments/planes within the NMR series, e.g. delay time, temperature, ligand concentration etc.', 'The number of separate points, each with a separate experiment/plane and parameter value, in the series'] headingList = ['#','Name','Experiments','Parameter\nVaried','Num\nPoints'] editWidgets = [None, self.nameEntry, None, self.conditionNamesPulldown, None] editGetCallbacks = [None, self.getName, None, self.getConditionName, None] editSetCallbacks = [None, self.setName, None, self.setConditionName, None] self.seriesMatrix = ScrolledMatrix(frame0, tipTexts=tipTexts, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, editWidgets=editWidgets, headingList=headingList, callback=self.selectExpSeries, deleteFunc=self.deleteExpSeries, grid=(0,0), gridSpan=(None, 3)) tipTexts = ['Make a new, blank NMR series specification in the CCPN project', 'Delete the selected NMR series from the project, although any component experiments remain. Note you cannot delete pseudo-nD series; delete the actual experiment instead', 'Colour the spectrum contours for each experiment in the selected series (not pseudo-nD) using a specified scheme'] texts = ['Add Series','Delete Series', 'Auto Colour Spectra'] commands = [self.addExpSeries,self.deleteExpSeries, self.autoColorSpectra] self.seriesButtons = ButtonList(frame0, texts=texts, commands=commands, grid=(1,0), tipTexts=tipTexts) label = Label(frame0, text='Scheme:', grid=(1,1)) tipText = 'Selects which colour scheme to apply to the contours of (separate) experiments within an NMR series' self.colorSchemePulldown = PulldownList(frame0, grid=(1,2), tipText=tipText) row += 1 div = LabelDivider(guiFrame, text='Experimental Parameters & Conditions', grid=(row, 0)) row += 1 guiFrame.grid_rowconfigure(row, weight=1) frame1 = Frame(guiFrame, grid=(row, 0)) frame1.expandGrid(0,0) tipTexts = ['The kind of experimental parameter that is being used to define the NMR series', 'The experiment that corresponds to the specified parameter value; can be edited from an arbitrary initial experiment', 'The numeric value of the parameter (condition) that relates to the experiment or point in the NMR series', 'The estimated error in value of the condition', 'The measurement unit in which the value of the condition is represented'] headingList = ['Parameter','Experiment','Value','Error','Unit'] editWidgets = [None,self.experimentPulldown,self.valueEntry,self.errorEntry, self.unitPulldown] editGetCallbacks = [None,self.getExperiment, self.getValue, self.getError, self.getUnit] editSetCallbacks = [None,self.setExperiment, self.setValue, self.setError, self.setUnit] self.conditionPointsMatrix = ScrolledMatrix(frame1, grid=(0,0), tipTexts=tipTexts, editSetCallbacks=editSetCallbacks, editGetCallbacks=editGetCallbacks, editWidgets=editWidgets, headingList=headingList, callback=self.selectConditionPoint, deleteFunc=self.deleteConditionPoint) self.conditionPointsMatrix.doEditMarkExtraRules = self.conditionTableShow tipTexts = ['Add a new point to the NMR series with an associated parameter value and experiment', 'Remove the selected point from the series, including any associated parameter value', 'For appropriate kinds of NMR series, set or unset a point as representing the plane to use as a reference'] texts = ['Add Series Point','Delete Series Point','Set/Unset Ref Plane'] commands = [self.addConditionPoint,self.deleteConditionPoint,self.setSampledReferencePlane] self.conditionPointsButtons = ButtonList(frame1, texts=texts, commands=commands, tipTexts=tipTexts, grid=(1,0)) self.updateAfter() self.updateColorSchemes() self.administerNotifiers(self.registerNotify) def administerNotifiers(self, notifyFunc): #for func in ('__init__', 'delete','setName'): for func in ('__init__', 'delete','setName','setConditionNames', 'addConditionName','removeConditionName'): notifyFunc(self.updateAfter,'ccp.nmr.Nmr.NmrExpSeries', func) for func in ('__init__', 'delete','setName'): notifyFunc(self.updateExperiments,'ccp.nmr.Nmr.Experiment', func) for func in ('__init__', 'delete'): notifyFunc(self.updateDataDim,'ccp.nmr.Nmr.SampledDataDim', func) for func in ('__init__', 'delete','setCondition','setUnit','setValue','setError'): notifyFunc(self.updateConditionsAfter,'ccp.nmr.Nmr.SampleCondition', func) for func in ('__init__', 'delete','setCondition'): notifyFunc(self.updateAfter,'ccp.nmr.Nmr.SampleCondition', func) for func in ('setConditionVaried', 'setPointErrors', 'addPointError', 'removePointError', 'setPointValues','addPointValue', 'removePointValue','setUnit'): notifyFunc(self.updateAfter,'ccp.nmr.Nmr.SampledDataDim', func) for func in ('__init__', 'delete'): notifyFunc(self.updateColorSchemes,'ccpnmr.AnalysisProfile.ColorScheme', func) def open(self): self.updateAfter() BasePopup.open(self) def updateColorSchemes(self, scheme=None): index = 0 prevScheme = self.colorSchemePulldown.getObject() schemes = getHueSortedColorSchemes(self.analysisProfile) schemes = [s for s in schemes if len(s.colors) > 1] colors = [list(s.colors) for s in schemes] if schemes: names = [s.name for s in schemes] if prevScheme in schemes: index = schemes.index(prevScheme) else: names = [] self.colorSchemePulldown.setup(names, schemes, index, colors) def autoColorSpectra(self): if self.expSeries and (self.expSeries.className != 'Experiment'): scheme = self.colorSchemePulldown.getObject() if scheme: colors = scheme.colors else: colors = ['#FF0000','#00FF00','#0000FF'] cdict = getNmrExpSeriesSampleConditions(self.expSeries) conditionName = list(self.expSeries.conditionNames)[0] expList = [] for sampleCondition in cdict.get(conditionName, []): expList.append( (sampleCondition.value, sampleCondition.parent.experiments) ) expList.sort() m = len(expList)-1.0 c = len(colors)-1 for i, (value, experiments) in enumerate(expList): p = c*i/m j = int(p) r1, g1, b1 = Color.hexToRgb(colors[j]) r2, g2, b2 = Color.hexToRgb(colors[min(c,j+1)]) f2 = p-j f1 = 1.0-f2 r = (r1*f1)+(r2*f2) g = (g1*f1)+(g2*f2) b = (b1*f1)+(b2*f2) hexColor = Color.hexRepr(r,g,b) for experiment in experiments: for spectrum in experiment.dataSources: if spectrum.dataType == 'processed': analysisSpec = getAnalysisSpectrum(spectrum) if analysisSpec.posColors: analysisSpec.posColors = [hexColor,] elif analysisSpec.negColors: analysisSpec.negColors = [hexColor,] def getUnusedExperiments(self): sampleExperiments = getSampledDimExperiments(self.nmrProject) experiments = [] for experiment in self.nmrProject.sortedExperiments(): if experiment in sampleExperiments: continue if self.expSeries and (self.expSeries.className != 'Experiment'): if experiment in self.expSeries.experiments: continue experiments.append(experiment) return experiments def conditionTableShow(self, object, row, col): if type(object) is type(()): dataDim, index = object refPlane = dataDim.analysisDataDim.refSamplePlane if refPlane == index: return False if col == 1: return False return True def setSampledReferencePlane(self): if self.expSeries and (self.expSeries.className == 'Experiment'): if self.conditionPoint: dataDim, point = self.conditionPoint analysisDataDim = dataDim.analysisDataDim refPoint = analysisDataDim.refSamplePlane if refPoint == point: analysisDataDim.refSamplePlane = None else: analysisDataDim.refSamplePlane = point self.updateAfter() def checkAddSampleCondition(self, experiment): conditionSet = getExperimentConditionSet(experiment) conditionName = self.expSeries.conditionNames[0] condDict = getNmrExpSeriesSampleConditions(self.expSeries) sampleConditions = condDict.get(conditionName, []) units = [sc.unit for sc in sampleConditions if sc.unit] if units: sortList = list(set(units)) sortList.sort(key = lambda u:units.count(u)) unit = sortList[-1] else: unit = CONDITION_UNITS_DICT[conditionName][0] condition = conditionSet.findFirstSampleCondition(condition=conditionName) if not condition: condition = conditionSet.newSampleCondition(condition=conditionName, unit=unit, value=0.0, error=0.0) def addConditionPoint(self): if self.expSeries and (self.expSeries.className != 'Experiment'): experiments = self.getUnusedExperiments() if not experiments: showWarning('Warning','No experiments available', parent=self) return experiment = experiments[0] if experiment not in self.expSeries.experiments: self.expSeries.addExperiment(experiment) self.checkAddSampleCondition(experiment) self.updateAfter() def deleteConditionPoint(self, *event): if self.conditionPoint and (self.expSeries.className != 'Experiment'): if showOkCancel('Confirm','Really delete series point?', parent=self): conditionSet = self.conditionPoint.sampleConditionSet experiments = [e for e in conditionSet.experiments if e in self.expSeries.experiments] for experiment in experiments: self.expSeries.removeExperiment(experiment) for experiment in experiments: for expSeries in experiment.nmrExpSeries: if self.conditionPoint.condition in self.expSeries.conditionNames: break else: continue break else: self.conditionPoint.delete() self.conditionPoint = None def selectConditionPoint(self, object, row, col): if object: self.conditionPoint = object self.updateButtons() def selectExpSeries(self, object, row, col): if object: self.expSeries = object self.checkExperimentConditionsConsistent() self.updateConditions() def checkExperimentConditionsConsistent(self): if self.expSeries.className != 'Experiment': for experiment in self.expSeries.experiments: self.checkAddSampleCondition(experiment) def getUnits(self): units = [] if self.expSeries: if self.expSeries.className == 'Experiment': conditionName = getExperimentSampledDim(self.expSeries).conditionVaried else: conditionName = self.expSeries.conditionNames[0] units = CONDITION_UNITS_DICT.get(conditionName) if not units: units = ['?',] return units def getUnit(self, sampleCondition): index = -1 units = self.getUnits() if units: if sampleCondition: if type(sampleCondition) is type(()): dataDim, index = sampleCondition unit = dataDim.unit else: unit = sampleCondition.unit if unit not in units: unit = units[0] index = units.index(unit) self.unitPulldown.setup(units,units,index) def setUnit(self, obj): name = self.unitPulldown.getObject() if self.conditionPoint: if type(self.conditionPoint) is type(()): dataDim, index = self.conditionPoint dataDim.setUnit(name) else: self.conditionPoint.setUnit(name) def getConditionNames(self): if self.expSeries and (self.expSeries.className == 'Experiment'): names = ['delay time','mixing time','num delays','pulsing frequency','gradient strength'] else: names = CONDITION_UNITS_DICT.keys() names.sort() return names def setConditionName(self, obj): name = self.conditionNamesPulldown.getObject() if self.expSeries: if self.expSeries.className == 'Experiment': dataDim = getExperimentSampledDim(self.expSeries) dataDim.conditionVaried = name else: self.expSeries.setConditionNames([name,]) def getConditionName(self, expSeries): index = 0 names = self.getConditionNames() if names: if expSeries: if expSeries.className == 'Experiment': name = getExperimentSampledDim(expSeries).conditionVaried else: name = expSeries.conditionNames[0] if name: index = names.index(name) else: index = 0 self.conditionNamesPulldown.setup(names,names,index) def getName(self, expSeries): if expSeries : self.nameEntry.set(expSeries.name) def setName(self, event): text = self.nameEntry.get() if text and text != ' ': self.expSeries.setName( text ) def getValue(self, conditionPoint): if conditionPoint: if type(self.conditionPoint) is type(()): dataDim, index = conditionPoint value = dataDim.pointValues[index] else: value = conditionPoint.value self.valueEntry.set(value) def setValue(self, event): value = self.valueEntry.get() if value is not None: if type(self.conditionPoint) is type(()): dataDim, index = self.conditionPoint values = list(dataDim.pointValues) values[index] = value dataDim.setPointValues(values) else: self.conditionPoint.setValue( value ) def getError(self, conditionPoint): if conditionPoint: if type(self.conditionPoint) is type(()): dataDim, index = conditionPoint if index < len(dataDim.pointErrors): error = dataDim.pointValues[index] else: error = 0.0 else: error = conditionPoint.error self.errorEntry.set(error) def setError(self, event): value = self.errorEntry.get() if value is not None: if type(self.conditionPoint) is type(()): dataDim, index = self.conditionPoint pointErrors = dataDim.pointErrors if pointErrors: values = list(pointErrors) else: values = [0.0] * dataDim.numPoints values[index] = value dataDim.setPointErrors(values) else: self.conditionPoint.setError( value ) def getDetails(self, expSeries): if expSeries : self.detailsEntry.set(expSeries.details) def setDetails(self, event): text = self.detailsEntry.get() if text and text != ' ': self.expSeries.setDetails( text ) def addExpSeries(self): expSeries = self.nmrProject.newNmrExpSeries(conditionNames=['delay time',]) def deleteExpSeries(self, *event): if self.expSeries and (self.expSeries.className != 'Experiment'): if showOkCancel('Confirm','Really delete series?', parent=self): self.expSeries.delete() self.expSeries = None self.conditionPoint = None def getExperiments(self): if self.expSeries and (self.expSeries.className == 'Experiment'): return [self.expSeries,] else: return self.nmrProject.sortedExperiments() def getExperiment(self, sampleCondition): index = 0 names = [] if self.conditionPoint and (type(self.conditionPoint) != type(())): index = 0 experiment = self.conditionPoint.parent.findFirstExperiment() experiments = self.getUnusedExperiments() name = experiment.name names = [name] + [e.name for e in experiments] experiments = [experiment,] + experiments self.experimentPulldown.setup(names,experiments,index) def setExperiment(self, obj): experiment = self.experimentPulldown.getObject() if self.conditionPoint and (type(self.conditionPoint) != type(())): conditionSet = getExperimentConditionSet(experiment) if conditionSet is not self.conditionPoint.parent: if experiment not in self.expSeries.experiments: self.expSeries.addExperiment(experiment) unit = self.conditionPoint.unit if not unit: unit = CONDITION_UNITS_DICT[self.expSeries.conditionNames[0]] condition = self.conditionPoint.condition experiments = set(self.expSeries.experiments) for experiment0 in self.conditionPoint.parent.experiments: if experiment0 in experiments: experiments.remove(experiment0) self.expSeries.experiments = experiments value = self.conditionPoint.value error = self.conditionPoint.error self.conditionPoint.delete() self.conditionPoint = conditionSet.findFirstSampleCondition(condition=condition) if self.conditionPoint: self.conditionPoint.unit = unit self.updateAfter() else: self.conditionPoint = conditionSet.newSampleCondition(condition=condition,unit=unit, value=value,error=error) def updateDataDim(self, sampledDataDim): experiment = sampledDataDim.dataSource.experiment self.updateExperiments(experiment) def updateExperiments(self, experiment): experiments = self.getExperiments() names = [e.name for e in experiments] self.experimentPulldown.setup(names, experiments,0) if getExperimentSampledDim(experiment): self.updateAfter() elif self.expSeries: if self.expSeries.className == 'Experiment': if experiment is self.expSeries: self.updateConditionsAfter() elif experiment in self.expSeries.experiments: self.updateConditionsAfter() def updateConditionsAfter(self, sampleCondition=None): if self.waitingConditions: return if sampleCondition: experiments = sampleCondition.sampleConditionSet.experiments for experiment in experiments: if self.expSeries.className == 'Experiment': if experiment is self.expSeries: self.waitingConditions = True self.after_idle(self.updateConditions) break elif experiment in self.expSeries.experiments: self.waitingConditions = True self.after_idle(self.updateConditions) break else: self.waitingConditions = True self.after_idle(self.updateConditions) def updateConditions(self): self.updateButtons() objectList = [] textMatrix = [] colorMatrix = [] nCols = len(self.conditionPointsMatrix.headingList) defaultColors = [None] * nCols if self.expSeries: if self.expSeries.className == 'Experiment': dataDim = getExperimentSampledDim(self.expSeries) analysisDataDim = getAnalysisDataDim(dataDim) conditionVaried = dataDim.conditionVaried expName = self.expSeries.name unit = dataDim.unit pointValues = dataDim.pointValues pointErrors = dataDim.pointErrors refPlane = analysisDataDim.refSamplePlane for i in range(dataDim.numPoints): if i < len(pointErrors): error = pointErrors[i] else: error = None pointText = ':%3d' % (i+1) if i == refPlane: datum = ['* Ref Plane *', expName+pointText, None, None, None] colorMatrix.append(['#f08080'] * nCols) else: datum = [conditionVaried , expName+pointText, pointValues[i], error, unit] colorMatrix.append(defaultColors) textMatrix.append(datum) objectList.append((dataDim, i)) else: condDict = getNmrExpSeriesSampleConditions(self.expSeries) conditionNames = self.expSeries.conditionNames for conditionName in conditionNames: for sampleCondition in condDict.get(conditionName, []): datum = [sampleCondition.condition, ' '.join([e.name for e in sampleCondition.parent.experiments]), sampleCondition.value, sampleCondition.error, sampleCondition.unit] textMatrix.append(datum) objectList.append(sampleCondition) colorMatrix.append(defaultColors) self.conditionPointsMatrix.update(objectList=objectList, colorMatrix=colorMatrix, textMatrix=textMatrix) self.waitingConditions = 0 def updateAfter(self, object=None): if self.waiting: return else: self.waiting = True self.after_idle(self.update) def updateButtons(self): if self.expSeries is None: self.seriesButtons.buttons[1].disable() self.seriesButtons.buttons[2].disable() self.conditionPointsButtons.buttons[0].disable() self.conditionPointsButtons.buttons[1].disable() self.conditionPointsButtons.buttons[2].disable() elif self.expSeries.className == 'Experiment': self.seriesButtons.buttons[1].disable() self.seriesButtons.buttons[2].disable() self.conditionPointsButtons.buttons[0].disable() self.conditionPointsButtons.buttons[1].disable() self.conditionPointsButtons.buttons[2].enable() else: self.seriesButtons.buttons[1].enable() self.seriesButtons.buttons[2].enable() self.conditionPointsButtons.buttons[0].enable() self.conditionPointsButtons.buttons[2].disable() if self.conditionPoint is None: self.conditionPointsButtons.buttons[1].disable() else: self.conditionPointsButtons.buttons[1].enable() def update(self): self.updateButtons() objectList = [] textMatrix = [] for experiment in getSampledDimExperiments(self.nmrProject): getExperimentConditionSet(experiment) sampledDim = getExperimentSampledDim(experiment) datum = [None, experiment.name, 1, sampledDim.conditionVaried, sampledDim.numPoints] textMatrix.append(datum) objectList.append(experiment) for expSeries in self.nmrProject.sortedNmrExpSeries(): experiments = expSeries.experiments conditionSets = len([e.sampleConditionSet for e in experiments if e.sampleConditionSet]) datum = [expSeries.serial, expSeries.name or ' ', len(experiments), ','.join(expSeries.conditionNames), conditionSets] textMatrix.append(datum) objectList.append(expSeries) self.seriesMatrix.update(objectList=objectList, textMatrix=textMatrix) self.updateConditions() self.waiting = False def destroy(self): self.administerNotifiers(self.unregisterNotify) BasePopup.destroy(self)
class NewWindowPopup(BasePopup): """ **Create New Windows to Display Spectra** This tool is used to make new windows for the graphical display of spectra, which will usually be as contours. It is notable that some spectrum windows will be made automatically when spectra are loaded if there is no existing appropriate window to display a spectrum. However, making new spectrum windows allows the user to specialise different windows for different tasks and gives complete freedom as to which types of axis go in which direction. For example the user may wish to make a new window so that a spectrum can be viewed from an orthogonal, rotated aspect. A new spectrum window is made by first considering whether it is similar to any existing windows. If so, then the user selects the appropriate template window to base the new one upon. The user then chooses a name for the window via the "New window name" field, although the name may be changed after the window is created. Usually the user does not need to consider the "Strips" section, but if required the new window can be created with starting strips and orthogonal sub-divisions (although these are not permanent). After setting the required axes and spectrum visibility, as described below, the user clicks on [Create Window!] to actually make the new spectrum display window. **Axes** The number and type of axes for the new window are chosen using the pulldown menus in the "Axes" section. The idea is that the user chooses which NMR isotopes should appear on the X, Y, & Z axes. Naturally, X and Y axes must always be set to something, to represent the plane of the screen, but the Z axes are optional. If not required, a Z axis may be set to "None" to indicate that it will not be used. Up to four Z axes may be specified, labelled as "z1", "z2" etc., and these represent extra dimensions orthogonal to the plane of the screen, which are often conceptualised as depth axes. It should be noted that the Y axis type may be set to "value", which refers to a spectrum intensity axis, rather than an NMR isotope axis. Setting the Y axis to "value" and only having the X axis set to an isotope is used to create windows that can show 1D spectra. Such value axes can also be used for 2D and higher dimensionality spectra, to show the data as an intensity graph (a "slice") rather than as contours. **Spectra** The lower "Viewed Spectra" section lists all of the spectra within the project that may be shown by a window with the selected axes. All spectra with isotopes in their data dimensions that match the isotope types of the window axes can potentially be displayed. This system also allows for displayed spectra to have fewer dimensions than the axes has windows, as long as at least the X and Y axes are present. For example a 2D H-N spectrum can be shown in a 3D H-N-H window, but not a 3D H-H-N. For spectra that have more than one data dimension of the same isotope, then which data dimension goes with which window axis is not always known to Analysis. Where there is ambiguity, this system will simply map the spectrum data dimensions in order to the next matching window axis. If this mapping turns out to be wrong, then it may be changed at any time via the main _Windows settings; toggling the "Dim. Mapping" of the "Spectrum & Peak List Mappings" tab. For the spectra listed in the lower table, which may be placed in the new window, the user has control over whether the spectra actually will appear. Firstly the user can change the "Visible?" column, either via a double-click or by using the appropriate lower buttons. By default spectra are set as not being visible in new windows, and the user toggles the ones that should be seen to "Yes". This basic spectrum visibility can readily be changed by the toggle buttons that appear in the "toolbar" at the top of the spectrum display, so the "Visible?" setting here is only about what initially appears. The "In Toolbar?" setting of a spectrum is a way of allowing the user to state that a spectrum should never appear in the window, and not even allow it to be toggled on later via the toolbar at the top of the windows. This is a way of reducing clutter, and allows certain windows to be used for particular subsets of spectra. For example the user may wish to put the spectra for a temperature series in one window, but not in other windows used for resonance assignment where they would get in the way. The "In Toolbar" setting can be changed after a window has been made, but only via the main Windows_ settings popup. .. _Windows: EditWindowPopup.html """ def __init__(self, parent, *args, **kw): self.visibleSpectra = parent.visibleSpectra self.toolbarSpectra = parent.toolbarSpectra self.waiting = False self.window = None BasePopup.__init__(self, parent=parent, title='Window : New Window', **kw) def body(self, guiFrame): guiFrame.grid_columnconfigure(2, weight=1) row = 0 label = Label(guiFrame, text='Template window: ', grid=(row, 0)) tipText = 'Selects which window to use as the basis for making a new spectrum window; sets the axis types accordingly' self.window_list = PulldownList(guiFrame, grid=(row, 1), callback=self.setAxisTypes, tipText=tipText) frame = LabelFrame(guiFrame, text='Strips', grid=(row, 2), gridSpan=(2, 1)) buttons = UtilityButtonList(guiFrame, doClone=False, helpUrl=self.help_url, grid=(row, 3)) row += 1 label = Label(guiFrame, text='New window name: ', grid=(row, 0)) tipText = 'A short name to identify the spectrum window, which will appear in the graphical interface' self.nameEntry = Entry(guiFrame, width=16, grid=(row, 1), tipText=tipText) row += 1 label = Label(frame, text='Columns: ', grid=(0, 0)) tipText = 'The number of vertical strips/dividers to initially make in the spectrum window' self.cols_menu = PulldownList(frame, objects=STRIP_NUMS, grid=(0, 1), texts=[str(x) for x in STRIP_NUMS], tipText=tipText) label = Label(frame, text='Rows: ', grid=(0, 2)) tipText = 'The number of horizontal strips/dividers to initially make in the spectrum window' self.rows_menu = PulldownList(frame, objects=STRIP_NUMS, grid=(0, 3), texts=[str(x) for x in STRIP_NUMS], tipText=tipText) row += 1 div = LabelDivider(guiFrame, text='Axes', grid=(row, 0), gridSpan=(1, 4)) row += 1 self.axis_lists = {} frame = Frame(guiFrame, grid=(row, 0), gridSpan=(1, 4)) col = 0 self.axisTypes = {} self.axisTypesIncludeNone = {} for label in AXIS_LABELS: self.axisTypes[label] = None w = Label(frame, text=' ' + label) w.grid(row=0, column=col, sticky='w') col += 1 if label in ('x', 'y'): includeNone = False tipText = 'Sets the kind of measurement (typically ppm for a given isotope) that will be used along the window %s axis' % label else: includeNone = True tipText = 'Where required, sets the kind of measurement (typically ppm for a given isotope) that will be used along the window %s axis' % label self.axisTypesIncludeNone[label] = includeNone getAxisTypes = lambda label=label: self.getAxisTypes(label) callback = lambda axisType, label=label: self.changedAxisType( label, axisType) self.axis_lists[label] = PulldownList(frame, callback=callback, tipText=tipText) self.axis_lists[label].grid(row=0, column=col, sticky='w') col += 1 frame.grid_columnconfigure(col, weight=1) row += 1 div = LabelDivider(guiFrame, text='Viewed Spectra', grid=(row, 0), gridSpan=(1, 4)) row += 1 guiFrame.grid_rowconfigure(row, weight=1) editWidgets = [None, None, None, None] editGetCallbacks = [None, self.toggleVisible, self.toggleToolbar, None] editSetCallbacks = [None, None, None, None] tipTexts = [ 'The "experiment:spectrum" name for the spectrum that may be viewed in the new window, given the axis selections', 'Sets whether the spectrum contours will be visible in the new window', 'Sets whether the spectrum appears at all in the window; if not in the toolbar it cannot be displayed', 'The number of peak lists the spectrum contains' ] headingList = ['Spectrum', 'Visible?', 'In Toolbar?', 'Peak Lists'] self.scrolledMatrix = ScrolledMatrix(guiFrame, headingList=headingList, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks, multiSelect=True, grid=(row, 0), gridSpan=(1, 4), tipTexts=tipTexts) row += 1 tipTexts = [ 'Creates a new spectrum window with the specified parameters', 'Sets the contours of the selected spectra to be visible when the new window is made', 'Sets the contours of the selected spectra to not be displayed when the new window is made', 'Sets the selected spectra as absent from the window toolbar, and thus not displayable at all' ] texts = [ 'Create Window!', 'Selected\nVisible', 'Selected\nNot Visible', 'Selected\nNot In Toolbar' ] commands = [ self.ok, self.setSelectedDisplay, self.setSelectedHide, self.setSelectedAbsent ] buttonList = ButtonList(guiFrame, texts=texts, grid=(row, 0), commands=commands, gridSpan=(1, 4), tipTexts=tipTexts) buttonList.buttons[0].config(bg='#B0FFB0') self.updateAxisTypes() self.updateWindow() self.updateWindowName() self.administerNotifiers(self.registerNotify) self.updateAfter() def administerNotifiers(self, notifyFunc): self.registerNotify(self.updateWindowName, 'ccpnmr.Analysis.SpectrumWindow', '__init__') for clazz in ('ccp.nmr.Nmr.Experiment', 'ccp.nmr.Nmr.DataSource'): for func in ('__init__', 'delete', 'setName'): notifyFunc(self.updateAfter, clazz, func) for func in ('__init__', 'delete'): notifyFunc(self.updateAfter, 'ccp.nmr.Nmr.PeakList', func) for func in ('__init__', 'delete', 'setName', 'addSpectrumWindowGroup', 'removeSpectrumWindowGroup', 'setSpectrumWindowGroups'): notifyFunc(self.updateWindow, 'ccpnmr.Analysis.SpectrumWindow', func) for func in ('addSpectrumWindow', 'removeSpectrumWindow', 'setSpectrumWindows'): notifyFunc(self.updateWindow, 'ccpnmr.Analysis.SpectrumWindowGroup', func) for func in ('__init__', 'delete', 'setName'): notifyFunc(self.updateAxisTypes, 'ccpnmr.Analysis.AxisType', func) # Set visible contours, on commit, according to selection # Get hold of spectrumWindowView ASAP def destroy(self): self.administerNotifiers(self.unregisterNotify) BasePopup.destroy(self) def getSpectra(self): spectrumIsotopes = {} spectra = [] for experiment in self.nmrProject.sortedExperiments(): name = experiment.name for spectrum in experiment.sortedDataSources(): spectrumIsotopes[spectrum] = [] spectra.append(['%s:%s' % (name, spectrum.name), spectrum]) for dataDim in spectrum.dataDims: dimTypes = [] if dataDim.className != 'SampledDataDim': for dataDimRef in dataDim.dataDimRefs: expDimRef = dataDimRef.expDimRef isotopes = set() for isotopeCode in expDimRef.isotopeCodes: isotopes.add(isotopeCode) dimTypes.append( (expDimRef.measurementType.lower(), isotopes)) else: dimTypes.append('sampled') spectrumIsotopes[spectrum].append(dimTypes) axisIsotopes = {} for label in AXIS_LABELS: if label not in ('x', 'y'): if self.axis_lists[label].getSelectedIndex() == 0: continue axisType = self.axis_lists[label].getObject() axisIsotopes[label] = (axisType.measurementType.lower(), set(axisType.isotopeCodes)) spectraSel = [] axes = axisIsotopes.keys() axes.sort() for name, spectrum in spectra: dimIsotopes = spectrumIsotopes[spectrum] for label in axes: mType, selected = axisIsotopes[label] if label == 'y' and mType == 'none': continue # value axis for i, dimTypes in enumerate(dimIsotopes): for dimType in dimTypes: if dimType == 'sampled': if label != 'z1': continue axisType = self.axis_lists[label].getObject() if axisType.name != 'sampled': continue dimIsotopes.pop(i) break else: measurementType, isotopes = dimType if (mType == measurementType) and (selected <= isotopes): dimIsotopes.pop(i) break else: continue break else: if label in ('x', 'y'): break else: if not dimIsotopes: spectraSel.append([name, spectrum]) return spectraSel def setSelectedAbsent(self): for spectrum in self.scrolledMatrix.currentObjects: self.visibleSpectra[spectrum] = False self.toolbarSpectra[spectrum] = False self.updateAfter() def setSelectedDisplay(self): for spectrum in self.scrolledMatrix.currentObjects: self.visibleSpectra[spectrum] = True self.toolbarSpectra[spectrum] = True self.updateAfter() def setSelectedHide(self): for spectrum in self.scrolledMatrix.currentObjects: self.visibleSpectra[spectrum] = False self.toolbarSpectra[spectrum] = True self.updateAfter() def toggleToolbar(self, spectrum): boolean = not self.toolbarSpectra.get(spectrum, True) self.toolbarSpectra[spectrum] = boolean if boolean is False: self.visibleSpectra[spectrum] = False self.updateAfter() def toggleVisible(self, spectrum): boolean = not self.visibleSpectra.get(spectrum, False) self.visibleSpectra[spectrum] = boolean if boolean: if not self.toolbarSpectra.get(spectrum, True): self.toolbarSpectra[spectrum] = True self.updateAfter() def updateAfter(self, object=None): if self.waiting: return else: self.waiting = True self.after_idle(self.update) def update(self): for spectrum in self.visibleSpectra.keys(): if spectrum.isDeleted: del self.visibleSpectra[spectrum] textMatrix = [] objectList = [] colorMatrix = [] for name, spectrum in self.getSpectra(): colours = [None, None, None, None] if self.visibleSpectra.get(spectrum): colours[0] = '#60F060' isVisible = 'Yes' self.visibleSpectra[ spectrum] = True # do not need this but play safe in case above if changed else: isVisible = 'No' self.visibleSpectra[spectrum] = False if self.toolbarSpectra.get(spectrum, True): inToolbar = 'Yes' self.toolbarSpectra[spectrum] = True else: colours[0] = '#600000' inToolbar = 'No' self.toolbarSpectra[spectrum] = False datum = [ name, isVisible, inToolbar, ','.join(['%d' % pl.serial for pl in spectrum.peakLists]) ] textMatrix.append(datum) objectList.append(spectrum) colorMatrix.append(colours) self.scrolledMatrix.update(objectList=objectList, textMatrix=textMatrix, colorMatrix=colorMatrix) self.waiting = False def updateAxisTypes(self, *extra): for label in AXIS_LABELS: names = [] objects = [] includeNone = self.axisTypesIncludeNone[label] if includeNone: names.append('None') objects.append(None) axisType = self.axisTypes[label] axisTypes = self.getAxisTypes(label) objects.extend(axisTypes) if axisTypes: if axisType not in objects: axisType = objects[0] index = objects.index(axisType) names.extend([x.name for x in axisTypes]) else: index = 0 self.axis_lists[label].setup(names, objects, index) self.changedAxisType(label, axisType) def changedAxisType(self, label, axisType): if axisType is not self.axisTypes[label]: self.axisTypes[label] = axisType self.updateAfter() def updateWindow(self, *extra): window = self.window windows = self.parent.getWindows() if windows: if window not in windows: window = windows[0] index = windows.index(window) names = [x.name for x in windows] else: index = 0 names = [] self.window_list.setup(names, windows, index) self.setAxisTypes(window) def updateWindowName(self, *extra): self.nameEntry.set(WindowBasic.defaultWindowName(self.project)) def getAxisTypes(self, label): axisTypes = self.parent.getAxisTypes() if label == 'z1': axisTypes = [ axisType for axisType in axisTypes if axisType.name == 'sampled' or not axisType.isSampled ] else: axisTypes = [ axisType for axisType in axisTypes if not axisType.isSampled ] if label != 'y': axisTypes = [ at for at in axisTypes if at.name != WindowBasic.VALUE_AXIS_NAME ] return axisTypes def setAxisTypes(self, window): project = self.project if not project: return if window is self.window: return self.window = window if window: windowPanes = window.sortedSpectrumWindowPanes() if windowPanes: # might be empty because notifier called before windowPanes set up windowPane = windowPanes[0] for label in AXIS_LABELS: axisPanel = windowPane.findFirstAxisPanel(label=label) if axisPanel and axisPanel.panelType \ and axisPanel.panelType.axisType: self.axis_lists[label].setSelected( axisPanel.panelType.axisType) elif label not in ('x', 'y'): self.axis_lists[label].setIndex(0) self.updateAfter() def apply(self): project = self.project if not project: return False name = self.nameEntry.get().strip() if not name: showError('No name', 'Need to enter name', parent=self) return False names = [ window.name for window in self.analysisProject.spectrumWindows ] if (name in names): showError('Repeated name', 'Name already used', parent=self) return False axisTypes = [] for label in AXIS_LABELS: if label not in ('x', 'y'): if self.axis_lists[label].getSelectedIndex() == 0: continue axisType = self.axis_lists[label].getObject() axisTypes.append(axisType) ncols = self.cols_menu.getObject() nrows = self.rows_menu.getObject() window = WindowBasic.createSpectrumWindow(project, name, [ axisTypes, ], ncols=ncols, nrows=nrows) return True
class SecStructurePredictPopup(BasePopup): """ **Predict Protein Secondary Structure** This popup window is designed to allow the prediction of secondary structure for a protein chain given chemical shifts, using the (external) program D2D. The Options to select are the Chain and the Shift List, for which the prediction is then made. The Secondary Structure Predictions table lists the residues in the chain. For each residue the residue number, residue type and current secondary structure set for that residue is given. The remaining columns are for the predictions made by D2D, and of course are only filled in once D2D is run. The predicted secondary structure is listed first, followed by the probability of that residue being Helix, Beta, Coil or PPII (the predicted secondary structure will be specified by the maximum of these). To run the prediction click on the "Run D2D Prediction!" button. This does not store this information in the project. To do that you have to click on the "Commit Predicted Secondary Structure" button. **Caveats & Tips** The predicted secondary structure cell is coloured red if the prediction is unreliable. Unreliable predictions are not stored with the "Commit" button but all reliable ones are. If you need to edit the secondary structure for a residue then use the Secondary Structure Chart: .. _Secondary Structure Chart: SecStructureGraphPopup.html **References** The D2D programme: http://www-vendruscolo.ch.cam.ac.uk/d2D/index.php *C. Camilloni, A. De Simone, W. Vranken and M. Vendruscolo. Determination of Secondary Structure Populations in Disordered States of Proteins using NMR Chemical Shifts. Biochemistry 2012, 51: 2224-2231 """ def __init__(self, parent, *args, **kw): self.chain = None self.shiftList = None self.predictionDict = {} BasePopup.__init__(self, parent=parent, title='Structure : Predict Secondary Structure') def body(self, guiFrame): self.geometry('700x500') guiFrame.expandGrid(1, 0) row = 0 # TOP LEFT FRAME frame = LabelFrame(guiFrame, text='Options') frame.grid(row=row, column=0, sticky='nsew') frame.columnconfigure(5, weight=1) label = Label(frame, text='Chain') label.grid(row=0, column=0, sticky='w') self.chainPulldown = PulldownList( frame, callback=self.changeChain, tipText='Choose the molecular system chain to make predictions for' ) self.chainPulldown.grid(row=0, column=1, sticky='w') label = Label(frame, text='Shift List') label.grid(row=0, column=2, sticky='w') self.shiftListPulldown = PulldownList( frame, callback=self.changeShiftList, tipText='Select the shift list to take input chemical shifts from') self.shiftListPulldown.grid(row=0, column=3, sticky='w') row += 1 # BOTTOM LEFT FRAME frame = LabelFrame(guiFrame, text='Secondary Structure Predictions') frame.grid(row=row, column=0, sticky='nsew') frame.grid_columnconfigure(0, weight=1) frame.grid_rowconfigure(0, weight=1) tipTexts = ('Residue number in chain', 'Residue type code', 'Current stored secondary structure code', 'Predicted secondary structure code') + SEC_STRUC_TIPS headingList = ('Res\nNum', 'Res\nType', 'Current\nSS', 'Predicted\nSS') + SEC_STRUC_KEYS n = len(headingList) editWidgets = n * [None] editGetCallbacks = n * [None] editSetCallbacks = n * [None] self.predictionMatrix = ScrolledMatrix( frame, headingList=headingList, tipTexts=tipTexts, editWidgets=editWidgets, editGetCallbacks=editGetCallbacks, editSetCallbacks=editSetCallbacks) self.predictionMatrix.grid(row=0, column=0, sticky='nsew') row += 1 tipTexts = [ 'Run the D2D method to predict secondary structure', 'Store the secondary structure predictions in the CCPN project' ] texts = [ 'Run D2D Prediction!', 'Commit Predicted\nSecondary Structure' ] commands = [self.runD2D, self.storeSecondaryStructure] self.buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, help_url=self.help_url, expands=True, tipTexts=tipTexts) self.buttonList.grid(row=row, column=0, columnspan=2, sticky='ew') self.update() self.notify(self.registerNotify) def destroy(self): self.notify(self.unregisterNotify) BasePopup.destroy(self) def notify(self, notifyfunc): for func in ('__init__', 'delete'): notifyfunc(self.updateChainPulldown, 'ccp.molecule.MolSystem.Chain', func) for func in ('__init__', 'delete', 'setName'): notifyfunc(self.updateShiftListPulldown, 'ccp.nmr.Nmr.ShiftList', func) for func in ('setSecStrucCode', ): notifyfunc(self.updatePredictionMatrixAfter, 'ccp.nmr.Nmr.ResonanceGroup', func) def update(self): self.updateShiftListPulldown() self.updateChainPulldown() self.updatePredictionMatrixAfter() def runD2D(self): chain = self.chain shiftList = self.shiftList if (not chain) or (not shiftList): showError('Cannot Run D2D', 'Please specify a chain and a shift list.', parent=self) return self.predictionDict[chain] = runD2D(chain, shiftList) self.updatePredictionMatrix() def storeSecondaryStructure(self): if not self.chain: return getSpinSystem = self.nmrProject.findFirstResonanceGroup newSpinSystem = self.nmrProject.newResonanceGroup predDict = self.predictionDict.get(self.chain, {}) n = 0 for residue in predDict: (ssCode, isReliable, probabilityDict) = predDict[residue] if isReliable: spinSystem = getSpinSystem(residue=residue) if not spinSystem: spinSystem = newSpinSystem(residue=residue, ccpCode=residue.ccpCode) spinSystem.secStrucCode = ssCode n += 1 showInfo('Info', 'Stored secondary structure types for %d residues.' % n, parent=self) def updatePredictionMatrixAfter(self, index=None, text=None): self.after_idle(self.updatePredictionMatrix) def updatePredictionMatrix(self): objectList = [] textMatrix = [] colorMatrix = [] n = len(SEC_STRUC_KEYS) chain = self.chain if chain: predDict = self.predictionDict.get(chain, {}) getSpinSystem = self.nmrProject.findFirstResonanceGroup for residue in chain.sortedResidues(): spinSystem = getSpinSystem(residue=residue) currentSsCode = spinSystem and spinSystem.secStrucCode data = [residue.seqCode, residue.ccpCode, currentSsCode] colors = 3 * [None] if residue in predDict: (ssCode, isReliable, probabilityDict) = predDict[residue] data.append(ssCode) if isReliable: colors.append(None) else: colors.append('#FF3333') for key in SEC_STRUC_KEYS: data.append(probabilityDict[key]) colors.extend(n * [None]) else: data.extend((n + 1) * [None]) colors.extend((n + 1) * [None]) textMatrix.append(data) objectList.append(residue) colorMatrix.append(colors) self.predictionMatrix.update(textMatrix=textMatrix, objectList=objectList, colorMatrix=colorMatrix) def changeChain(self, chain): if chain is not self.chain: self.chain = chain self.updatePredictionMatrixAfter() def changeShiftList(self, shiftList): if shiftList is not self.shiftList: self.shiftList = shiftList self.updatePredictionMatrixAfter() def updateChainPulldown(self, obj=None): index = 0 names = [] chains = [] chain = self.chain for molSystem in self.project.molSystems: msCode = molSystem.code for chainA in molSystem.chains: residues = chainA.residues if not residues: continue for residue in residues: # Must have at least one protein residue if residue.molType == 'protein': names.append('%s:%s' % (msCode, chainA.code)) chains.append(chainA) break if chains: if chain not in chains: chain = chains[0] index = chains.index(chain) else: chain = None if chain is not self.chain: self.chain = chain self.updatePredictionMatrixAfter() self.chainPulldown.setup(names, chains, index) def updateShiftListPulldown(self, obj=None): index = 0 names = [] shiftLists = getShiftLists(self.nmrProject) if shiftLists: if self.shiftList not in shiftLists: self.shiftList = shiftLists[0] index = shiftLists.index(self.shiftList) names = ['%s:%d' % (sl.name, sl.serial) for sl in shiftLists] else: self.shiftList = None self.shiftListPulldown.setup(names, shiftLists, index)
def body(self): '''describes the body of this tab. It bascically consists of some field to fill out for the user at the top and a ScrolledGraph that shows the progess of the annealing procedure a the bottom. ''' frame = self.frame # frame.expandGrid(13,0) frame.expandGrid(15, 1) row = 0 text = 'Calculate Assignment Suggestions' command = self.runCalculations self.startButton = Button(frame, command=command, text=text) self.startButton.grid(row=row, column=0, sticky='nsew', columnspan=2) row += 1 Label(frame, text='Amount of runs: ', grid=(row, 0)) tipText = 'The amount of times the whole optimization procedure is performed, each result is safed' self.repeatEntry = IntEntry(frame, grid=(row, 1), width=7, text=10, returnCallback=self.updateRepeatEntry, tipText=tipText, sticky='nsew') self.repeatEntry.bind('<Leave>', self.updateRepeatEntry, '+') row += 1 Label(frame, text='Temperature regime: ', grid=(row, 0)) tipText = 'This list of numbers govern the temperature steps during the annealing, every number represents 1/(kb*t), where kb is the Boltzmann constant and t the temperature of one step.' self.tempEntry = Entry(frame, text=map(str, self.acceptanceConstantList), width=64, grid=(row, 1), isArray=True, returnCallback=self.updateAcceptanceConstantList, tipText=tipText, sticky='nsew') row += 1 Label(frame, text='Amount of attempts per temperature:', grid=(row, 0)) tipText = 'The amount of attempts to switch the position of two spinsystems in the sequence are performed for each temperature point' self.NAStepEntry = IntEntry(frame, grid=(row, 1), width=7, text=10000, returnCallback=self.updateStepEntry, tipText=tipText, sticky='nsew') self.NAStepEntry.bind('<Leave>', self.updateStepEntry, '+') row += 1 Label(frame, text='Fraction of peaks to leave out:', grid=(row, 0)) tipText = 'In each run a fraction of the peaks can be left out of the optimization, thereby increasing the variability in the outcome and reducing false negatives. In each run this will be different randomly chosen sub-set of all peaks. 0.1 (10%) can be a good value.' self.leaveOutPeaksEntry = FloatEntry(frame, grid=(row, 1), width=7, text=0.0, returnCallback=self.updateLeavePeaksOutEntry, tipText=tipText, sticky='nsew') self.leaveOutPeaksEntry.bind( '<Leave>', self.updateLeavePeaksOutEntry, '+') row += 1 Label(frame, text='Minmal amino acid typing score:', grid=(row, 0)) tipText = 'If automatic amino acid typing is selected, a cut-off value has to set. Every amino acid type that scores higher than the cut-off is taken as a possible type. This is the same score as can be found under resonance --> spin systems --> predict type. Value should be between 0 and 100' self.minTypeScoreEntry = FloatEntry(frame, grid=(row, 1), width=7, text=1.0, returnCallback=self.updateMinTypeScoreEntry, tipText=tipText, sticky='nsew') self.minTypeScoreEntry.bind( '<Leave>', self.updateMinTypeScoreEntry, '+') row += 1 Label(frame, text='Minimal colabelling fraction:', grid=(row, 0)) tipText = 'The minimal amount of colabelling the different nuclei should have in order to still give rise to a peak.' self.minLabelEntry = FloatEntry(frame, grid=(row, 1), width=7, text=0.1, returnCallback=self.updateMinLabelEntry, tipText=tipText, sticky='nsew') self.minLabelEntry.bind('<Leave>', self.updateMinLabelEntry, '+') row += 1 Label(frame, text='Use sequential assignments:', grid=(row, 0)) tipText = 'When this option is select the present sequential assignments will be kept in place' self.useAssignmentsCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Use tentative assignments:', grid=(row, 0)) tipText = 'If a spin system has tentative assignments this can be used to narrow down the amount of possible sequential assignments.' self.useTentativeCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Use amino acid types:', grid=(row, 0)) tipText = 'Use amino acid types of the spin systems. If this option is not checked the spin systems are re-typed, only resonance names and frequencies are used' self.useTypeCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Include untyped spin systems:', grid=(row, 0)) tipText = 'Also include spin system that have no type information. Amino acid typing will be done on the fly.' self.useAlsoUntypedSpinSystemsCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Use dimensional assignments:', grid=(row, 0)) tipText = 'If one or more dimensions of a peak is already assigned, assume that this assignment is the only option. If not the check the program will consider all possibilities for the assignment of the dimension.' self.useDimensionalAssignmentsCheck = CheckButton( frame, selected=True, tipText=tipText, grid=(row, 1)) row += 1 Label(frame, text='Chain:', grid=(row, 0)) self.molPulldown = PulldownList( frame, callback=self.changeMolecule, grid=(row, 1)) self.updateChains() row += 1 Label(frame, text='Residue ranges: ', grid=(row, 0)) tipText = 'Which residues should be included. Example: "10-35, 62-100, 130".' self.residueRangeEntry = Entry(frame, text=None, width=64, grid=(row, 1), isArray=True, returnCallback=self.updateResidueRanges, tipText=tipText, sticky='nsew') self.updateResidueRanges(fromChain=True) row += 1 self.energyPlot = ScrolledGraph(frame, symbolSize=2, width=600, height=200, title='Annealing', xLabel='temperature step', yLabel='energy') self.energyPlot.grid(row=row, column=0, columnspan=2, sticky='nsew')