Example #1
0
class LabeledEntry(Frame):
    def __init__(self,
                 parent,
                 label,
                 entry='',
                 separator=': ',
                 label_width=20,
                 entry_width=60,
                 label_anchor=Tkinter.E,
                 show='',
                 returnCallback=None,
                 tipText=None,
                 *args,
                 **kw):

        apply(Frame.__init__, (self, parent) + args, kw)

        self.grid_columnconfigure(1, weight=1)

        self.separator = separator

        text = label + separator
        self.label = Label(self,
                           text=text,
                           width=label_width,
                           anchor=label_anchor)
        self.label.grid(row=0, column=0, sticky=Tkinter.EW)

        self.entry = Entry(self,
                           show=show,
                           width=entry_width,
                           returnCallback=returnCallback,
                           tipText=tipText)
        self.entry.insert(0, entry)
        self.entry.grid(row=0, column=1, sticky=Tkinter.EW)

    def getLabel(self):

        text = self.label.get()
        n = text.find(self.separator)
        if (n >= 0):
            text = text[:n]

        return text

    def setLabel(self, text=''):

        text = text + self.separator
        self.label.set(text)

    def getEntry(self):

        return self.entry.get()

    def setEntry(self, text=''):

        self.entry.set(text)
Example #2
0
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
Example #3
0
class CreatePanelTypePopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.axisType = None

        BasePopup.__init__(self,
                           parent=parent,
                           title='Create panel type',
                           modal=True,
                           **kw)

    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 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.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.types_list.setup(names, axisTypes, index)

    def apply(self):

        name = self.name_entry.get()
        if not name:
            showError('No name', 'Need to enter name', parent=self)
            return False

        names = [
            panelType.name for panelType in self.analysisProject.panelTypes
        ]
        if name in names:
            showError('Repeated name', 'Name already used', parent=self)
            return False

        axisType = self.types_list.getObject()

        if not axisType:
            showError('No axis type', 'Need to create axis type', parent=self)
            return False

        self.analysisProject.newPanelType(name=name, axisType=axisType)

        return True
Example #4
0
class CingGui(BasePopup):

    def __init__(self, parent, options, *args, **kw):


        # Fill in below variable once run generates some results
        self.haveResults = None
        # store the options
        self.options = options

        BasePopup.__init__(self, parent=parent, title='CING Setup', **kw)

#    self.setGeometry(850, 750, 50, 50)

        self.project = None

#    self.tk_strictMotif( True)

        self.updateGui()
    # end def __init__

    def body(self, guiFrame):

        row = 0
        col =0
#    frame = Frame( guiFrame )
#    frame.grid(row=row, column=col, sticky='news')
        self.menuBar = Menu( guiFrame)
        self.menuBar.grid( row=row, column=col, sticky='ew')

        #----------------------------------------------------------------------------------
        # Project frame
        #----------------------------------------------------------------------------------

#    guiFrame.grid_columnconfigure(row, weight=1)
#    frame = LabelFrame(guiFrame, text='Project', font=medFont)
        row = +1
        col =0
        frame = LabelFrame(guiFrame, text='Project', **labelFrameAttributes )
        print '>', frame.keys()
        frame.grid(row=row, column=col, sticky='nsew' )
        frame.grid_columnconfigure(2, weight=1)
#    frame.grid_rowconfigure(0, weight=1)

        srow = 0
        self.projectOptions = ['old','new from PDB','new from CCPN','new from CYANA']
        self.projOptionsSelect = RadioButtons(frame, selected_index=0, entries=self.projectOptions, direction='vertical',
                                              select_callback=self.updateGui
                                             )
        self.projOptionsSelect.grid(row=srow,column=0,rowspan=len(self.projectOptions),columnspan=2, sticky='w')

        if self.options.name: 
            text = self.options.name
        else: 
            text=''
        # end if
        self.projEntry = Entry(frame, bd=1, text=text, returnCallback=self.updateGui)
        self.projEntry.grid(row=srow,column=2,columnspan=2,sticky='ew')
#    self.projEntry.bind('<Key>', self.updateGui)
        self.projEntry.bind('<Leave>', self.updateGui)

        projButton = Button(frame, bd=1,command=self.chooseOldProjectFile, text='browse')
        projButton.grid(row=srow,column=3,sticky='ew')

        srow += 1
        self.pdbEntry = Entry(frame, bd=1, text='')
        self.pdbEntry.grid(row=srow,column=2,sticky='ew')
        self.pdbEntry.bind('<Leave>', self.updateGui)

        pdbButton = Button(frame, bd=1,command=self.choosePdbFile, text='browse')
        pdbButton.grid(row=srow,column=3,sticky='ew')

        srow += 1
        self.ccpnEntry = Entry(frame, bd=1, text='')
        self.ccpnEntry.grid(row=srow,column=2,sticky='ew')
        self.ccpnEntry.bind('<Leave>', self.updateGui)

        ccpnButton = Button(frame, bd=1,command=self.chooseCcpnFile, text='browse')
        ccpnButton.grid(row=srow,column=3,sticky='ew')

        srow += 1
        self.cyanaEntry = Entry(frame, bd=1, text='')
        self.cyanaEntry.grid(row=srow,column=2,sticky='ew')
        self.cyanaEntry.bind('<Leave>', self.updateGui)

        cyanaButton = Button(frame, bd=1,command=self.chooseCyanaFile, text='browse')
        cyanaButton.grid(row=srow,column=3,sticky='ew')

        #Empty row
        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow,column=0,sticky='nw')

        srow += 1
        label = Label(frame, text='Project name:')
        label.grid(row=srow,column=0,sticky='nw')
        self.nameEntry = Entry(frame, bd=1, text='')
        self.nameEntry.grid(row=srow,column=2,sticky='w')

        #Empty row
        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow,column=0,sticky='nw')

        srow += 1
        self.openProjectButton = Button(frame, command=self.openProject, text='Open Project', **actionButtonAttributes )
        self.openProjectButton.grid(row=srow,column=0, columnspan=4, sticky='ew')


        #----------------------------------------------------------------------------------
        # status
        #----------------------------------------------------------------------------------
#    guiFrame.grid_columnconfigure(1, weight=0)
        srow = 0
        frame = LabelFrame(guiFrame, text='Status', **labelFrameAttributes)
        frame.grid( row=srow, column=1, sticky='wnes')
        self.projectStatus = Text(frame, height=11, width=70, borderwidth=0, relief='flat')
        self.projectStatus.grid(row=0, column=0, sticky='wen')

        #Empty row
        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow,column=0,sticky='nw')

        srow += 1
        self.closeProjectButton = Button(frame, command=self.closeProject, text='Close Project', **actionButtonAttributes)
        self.closeProjectButton.grid(row=srow,column=0, columnspan=4, sticky='ew')

        #----------------------------------------------------------------------------------
        # Validate frame
        #----------------------------------------------------------------------------------

        row +=1
        col=0
        frame = LabelFrame(guiFrame, text='Validate', **labelFrameAttributes)
#    frame = LabelFrame(guiFrame, text='Validate', font=medFont)
        frame.grid(row=row, column=col, sticky='nsew')
#    frame.grid_columnconfigure(2, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        srow = 0
#    label = Label(frame, text='validation')
#    label.grid(row=srow,column=0,sticky='nw')
#
#    self.selectDoValidation = CheckButton(frame)
#    self.selectDoValidation.grid(row=srow, column=1,sticky='nw' )
#    self.selectDoValidation.set(True)
#
#    srow += 1
#    label = Label(frame, text='')
#    label.grid(row=srow,column=0,sticky='nw')
#
#    srow += 1
        label = Label(frame, text='checks')
        label.grid(row=srow,column=0,sticky='nw')

        self.selectCheckAssign = CheckButton(frame)
        self.selectCheckAssign.grid(row=srow, column=1,sticky='nw' )
        self.selectCheckAssign.set(True)
        label = Label(frame, text='assignments and shifts')
        label.grid(row=srow,column=2,sticky='nw')


#    srow += 1
#    self.selectCheckQueen = CheckButton(frame)
#    self.selectCheckQueen.grid(row=srow, column=4,sticky='nw' )
#    self.selectCheckQueen.set(False)
#    label = Label(frame, text='QUEEN')
#    label.grid(row=srow,column=5,sticky='nw')
#
#    queenButton = Button(frame, bd=1,command=None, text='setup')
#    queenButton.grid(row=srow,column=6,sticky='ew')


        srow += 1
        self.selectCheckResraint = CheckButton(frame)
        self.selectCheckResraint.grid(row=srow, column=1,sticky='nw' )
        self.selectCheckResraint.set(True)
        label = Label(frame, text='restraints')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        self.selectCheckStructure = CheckButton(frame)
        self.selectCheckStructure.grid(row=srow, column=1,sticky='nw' )
        self.selectCheckStructure.set(True)
        label = Label(frame, text='structural')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        self.selectMakeHtml = CheckButton(frame)
        self.selectMakeHtml.grid(row=srow, column=1,sticky='nw' )
        self.selectMakeHtml.set(True)
        label = Label(frame, text='generate HTML')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        self.selectCheckScript = CheckButton(frame)
        self.selectCheckScript.grid(row=srow, column=1,sticky='nw' )
        self.selectCheckScript.set(False)
        label = Label(frame, text='user script')
        label.grid(row=srow,column=0,sticky='nw')

        self.validScriptEntry = Entry(frame, bd=1, text='')
        self.validScriptEntry.grid(row=srow,column=2,columnspan=3, sticky='ew')

        scriptButton = Button(frame, bd=1,command=self.chooseValidScript, text='browse')
        scriptButton.grid(row=srow,column=5,sticky='ew')

        srow += 1
        label = Label(frame, text='ranges')
        label.grid(row=srow,column=0,sticky='nw')
        self.rangesEntry = Entry( frame, text='' )
        self.rangesEntry.grid( row=srow, column=2, columnspan=3, sticky='ew')

#    self.validScriptEntry = Entry(frame, bd=1, text='')
#    self.validScriptEntry.grid(row=srow,column=3,sticky='ew')
#
#    scriptButton = Button(frame, bd=1,command=self.chooseValidScript, text='browse')
#    scriptButton.grid(row=srow,column=4,sticky='ew')


        srow += 1
        texts    = ['Run Validation','View Results','Setup QUEEN']
        commands = [self.runCing, None, None]
        buttonBar = ButtonList(frame, texts=texts, commands=commands,expands=True)
        buttonBar.grid(row=srow, column=0, columnspan=6, sticky='ew')
        for button in buttonBar.buttons:
            button.config(**actionButtonAttributes)
        # end for
        self.runButton = buttonBar.buttons[0]
        self.viewResultButton = buttonBar.buttons[1]
        self.queenButton = buttonBar.buttons[2]

        #----------------------------------------------------------------------------------
        # Miscellaneous frame
        #----------------------------------------------------------------------------------

        row +=0
        col=1
#    frame = LabelFrame(guiFrame, text='Miscellaneous', font=medFont)
        frame = LabelFrame(guiFrame, text='Miscellaneous', **labelFrameAttributes)
        frame.grid(row=row, column=col, sticky='news')
        frame.grid_columnconfigure(2, weight=1)
        frame.grid_columnconfigure(4, weight=1,minsize=30)
        frame.grid_rowconfigure(0, weight=1)

        # Exports

        srow = 0
        label = Label(frame, text='export to')
        label.grid(row=srow,column=0,sticky='nw')

        self.selectExportXeasy = CheckButton(frame)
        self.selectExportXeasy.grid(row=srow, column=1,sticky='nw' )
        self.selectExportXeasy.set(True)
        label = Label(frame, text='Xeasy, Sparky, TALOS, ...')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        self.selectExportCcpn = CheckButton(frame)
        self.selectExportCcpn.grid(row=srow, column=1,sticky='nw' )
        self.selectExportCcpn.set(True)
        label = Label(frame, text='CCPN')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        self.selectExportQueen = CheckButton(frame)
        self.selectExportQueen.grid(row=srow, column=1,sticky='nw' )
        self.selectExportQueen.set(True)
        label = Label(frame, text='QUEEN')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        self.selectExportRefine = CheckButton(frame)
        self.selectExportRefine.grid(row=srow, column=1,sticky='nw' )
        self.selectExportRefine.set(True)
        label = Label(frame, text='refine')
        label.grid(row=srow,column=2,sticky='nw')

        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow,column=0,sticky='nw')

        # User script

        srow += 1
        label = Label(frame, text='user script')
        label.grid(row=srow,column=0,sticky='nw')

        self.selectMiscScript = CheckButton(frame)
        self.selectMiscScript.grid(row=srow, column=1,sticky='nw' )
        self.selectMiscScript.set(False)

        self.miscScriptEntry = Entry(frame, bd=1, text='')
        self.miscScriptEntry.grid(row=srow,column=3,sticky='ew')

        script2Button = Button(frame, bd=1,command=self.chooseMiscScript, text='browse')
        script2Button.grid(row=srow,column=4,sticky='ew')

        srow += 1
        texts    = ['Export','Run Script']
        commands = [None, None]
        buttonBar = ButtonList(frame, texts=texts, commands=commands,expands=True)
        buttonBar.grid(row=srow, column=0, columnspan=5, sticky='ew')
        for button in buttonBar.buttons:
            button.config(**actionButtonAttributes)
        # end for
        self.exportButton = buttonBar.buttons[0]
        self.scriptButton = buttonBar.buttons[1]

        #----------------------------------------------------------------------------------
        # Textarea
        #----------------------------------------------------------------------------------
        row +=1
        guiFrame.grid_rowconfigure(row, weight=1)
        self.outputTextBox = ScrolledText(guiFrame)
        self.outputTextBox.grid(row=row, column=0, columnspan=2, sticky='nsew')

        self.redirectConsole()

        #----------------------------------------------------------------------------------
        # Buttons
        #----------------------------------------------------------------------------------
        row +=1
        col=0
        texts    = ['Quit', 'Help']
        commands = [self.close, None]
        self.buttonBar = ButtonList(guiFrame, texts=texts, commands=commands,expands=True)
        self.buttonBar.grid(row=row, column=col, columnspan=2, sticky='ew')

#    self.openProjectButton = self.buttonBar.buttons[0]
#    self.closeProjectButton = self.buttonBar.buttons[1]
#    self.runButton = self.buttonBar.buttons[0]
#    self.viewResultButton = self.buttonBar.buttons[1]

        for button in self.buttonBar.buttons:
            button.config(**actionButtonAttributes)
        # end for
    # end def body


    def getGuiOptions(self):

        projectName = self.projEntry.get()

        index = self.projOptionsSelect.getIndex()

        if index > 0:
            makeNewProject = True
            projectImport  = None

            if index > 1:
                i = index-2
                format = ['PDB','CCPN','CYANA'][i]
                file   = [self.pdbEntry, self.ccpnEntry, self.cyanaEntry][i].get()

                if not file:
                    showWarning('Failure','No %s file selected' % format)
                    return
                # end if

                projectImport  = (format, file)
            # end if

        else:
            # Chould also check that any old project file exists

            makeNewProject = False
            projectImport  = None
        # end if

        doValidation = self.selectDoValidation.get()
        checks = []

        if doValidation:
            if self.selectCheckAssign.get():
                checks.append('assignments')
            # end if

            if self.selectCheckResraint.get():
                checks.append('restraints')
            # end if

            if self.selectCheckStructure.get():
                checks.append('structural')
            # end if

            if self.selectMakeHtml.get():
                checks.append('HTML')
            # end if

            if self.selectCheckScript.get():
                script = self.validScriptEntry.get()

                if script:
                    checks.append( ('script',script) )
                # end if
            # end if

            if self.selectCheckQueen.get():
                checks.append('queen')
            # end if
        # end if

        exports = []

        if self.selectExportXeasy.get():
            exports.append('Xeasy')
        # end if

        if self.selectExportCcpn.get():
            exports.append('CCPN')
        # end if

        if self.selectExportQueen.get():
            exports.append('QUEEN')
        # end if

        if self.selectExportRefine.get():
            exports.append('refine')
        # end if

        miscScript = None

        if self.selectMiscScript.get():
            script = self.miscScriptEntry.get()

            if script:
                miscScript = script
            # end if
        # end if

        return projectName, makeNewProject, projectImport, doValidation, checks, exports, miscScript
    # end def getGuiOptions


    def runCing(self):

        options = self.getGuiOptions()

        if options:

            projectName, makeNewProject, projectImport, doValidation, checks, exports, miscScript = options

            print 'Project name:', projectName
            print 'Make new project?', makeNewProject
            print 'Import source:', projectImport
            print 'Do vailidation?', doValidation
            print 'Validation checks:', ','.join(checks)
            print 'Export to:', ','.join(exports)
            print 'User script:', miscScript
        # end if
    # end def runCing

        # else there was already an error message

    def chooseOldProjectFile(self):

        fileTypes = [  FileType('CING', ['project.xml']),
                       FileType('All',  ['*'])
                    ]
        popup = FileSelectPopup(self, file_types = fileTypes,
                                title = 'Select CING project file', dismiss_text = 'Cancel',
                                selected_file_must_exist = True)

        fileName = popup.getFile()
#    dirName  = popup.getDirectory()

        if len(fileName) > 0:
                # Put text into entry,name widgets
            dummy,name = cing.Project.rootPath(fileName)
            self.projEntry.configure(state='normal')
            self.projEntry.set(fileName)

            self.nameEntry.configure(state='normal')
            self.nameEntry.set(name)
            self.nameEntry.configure(state='disabled')
            # choose the correct radiobutton
            self.projOptionsSelect.setIndex(0)
            self.updateGui()
        # end if
        #nd if

        popup.destroy()
    # end def chooseOldProjectFile

    def choosePdbFile(self):

        fileTypes = [ FileType('PDB', ['*.pdb']),  FileType('All', ['*'])]
        popup = FileSelectPopup(self, file_types = fileTypes,
                                title = 'PDB file', dismiss_text = 'Cancel',
                                selected_file_must_exist = True)

        fileName = popup.getFile()
        if len(fileName)>0:
            # Put text into entry widget
            self.pdbEntry.configure(state='normal')
            self.pdbEntry.set(fileName)
            # Put text into name widget
            _dir,name,dummy = nTpath( fileName )
            self.nameEntry.configure(state='normal')
            self.nameEntry.set(name)
            # choose the correct radiobutton
            self.projOptionsSelect.setIndex(1)
            self.updateGui()
        #end if

        popup.destroy()
    # end def choosePdbFile


    def chooseCcpnFile(self):

        fileTypes = [  FileType('XML', ['*.xml']), FileType('All', ['*'])]
        popup = FileSelectPopup(self, file_types = fileTypes,
                                title = 'CCPN project XML file', dismiss_text = 'Cancel',
                                selected_file_must_exist = True)

        fileName = popup.getFile()
        if len(fileName)>0:
            self.pdbEntry.configure(state='normal')
            self.pdbEntry.set(fileName)
            self.projOptionsSelect.setIndex(1)

            _dir,name,dummy = nTpath( fileName )
            self.nameEntry.set(name)
        #end if
        self.ccpnEntry.set(fileName)
        self.projOptionsSelect.setIndex(2)

        popup.destroy()
    # end def chooseCcpnFile


    def chooseCyanaFile(self):

        # Prepend default Cyana file extension below
        fileTypes = [  FileType('All', ['*']), ]
        popup = FileSelectPopup(self, file_types = fileTypes,
                                title = 'CYANA fproject file', dismiss_text = 'Cancel',
                                selected_file_must_exist = True)

        fileName = popup.getFile()
        self.cyanaEntry.set(fileName)
        self.projOptionsSelect.setIndex(3)

        popup.destroy()
    # end def chooseCyanaFile

    def chooseValidScript(self):

        # Prepend default Cyana file extension below
        fileTypes = [  FileType('All', ['*']), ]
        popup = FileSelectPopup(self, file_types = fileTypes,
                                title = 'Script file', dismiss_text = 'Cancel',
                                selected_file_must_exist = True)

        fileName = popup.getFile()
        self.validScriptEntry.set(fileName)
        popup.destroy()
    # end def chooseValidScript

    def chooseMiscScript(self):

        # Prepend default Cyana file extension below
        fileTypes = [  FileType('All', ['*']), ]
        popup = FileSelectPopup(self, file_types = fileTypes,
                                title = 'Script file', dismiss_text = 'Cancel',
                                selected_file_must_exist = True)

        fileName = popup.getFile()
        self.miscScriptEntry.set(fileName)
        popup.destroy()
    # end def chooseMiscScript

    def openProject(self ):
        projOption = self.projOptionsSelect.get()
        if projOption == self.projectOptions[0]: 
            self.openOldProject()
        elif projOption == self.projectOptions[1]: 
            self.initPdb()
        # end if

        if self.project: 
            self.project.gui = self
        # end if
        self.updateGui()
    #end def

    def openOldProject(self ):
        fName = self.projEntry.get()
        if not os.path.exists( fName ):
            nTerror('Error: file "%s" does not exist\n', fName)
        #end if

        if self.project: 
            self.closeProject()
        # end if
        self.project = cing.Project.open( name=fName, status='old', verbose=False )
    #end def

    def initPdb(self ):
        fName = self.pdbEntry.get()
        if not os.path.exists( fName ):
            nTerror('Error: file "%s" does not exist\n', fName)
        #end if
        self.project = cing.Project.open( self.nameEntry.get(), status='new' )
        self.project.initPDB( pdbFile=fName, convention = 'PDB' )
    #end def

    def closeProject(self):
        if self.project: 
            self.project.close()
        # end if
        self.project = None
        self.updateGui()
    #end def

    def updateGui(self, event=None):

        projOption = self.projOptionsSelect.get()
        buttons = self.buttonBar.buttons

        # Disable entries
        for e in [self.projEntry, self.pdbEntry, self.ccpnEntry, self.cyanaEntry, self.nameEntry]:
            e.configure(state='disabled')
        #end for

        if projOption == self.projectOptions[0]:
            # Enable entries
            self.projEntry.configure(state='normal')

            if (len(self.projEntry.get()) > 0):
                self.openProjectButton.enable()
                self.runButton.enable()
            else:
                self.openProjectButton.disable()
                self.runButton.disable()
            #end if

        elif projOption == self.projectOptions[1]:
            # Enable entries
            self.pdbEntry.configure(state='normal')
            self.nameEntry.configure(state='normal')

            if (len(self.pdbEntry.get()) > 0 and len(self.nameEntry.get())  > 0):
                buttons[0].enable()
                buttons[1].enable()
            else:
                buttons[0].disable()
                buttons[1].disable()
            #end if
        #end if

        elif projOption == self.projectOptions[2]:
            # Enable entries
            self.ccpnEntry.configure(state='normal')
            self.nameEntry.configure(state='normal')

            if (len(self.ccpnEntry.get()) > 0 and len(self.nameEntry.get())  > 0):
                buttons[0].enable()
                buttons[1].enable()
            else:
                buttons[0].disable()
                buttons[1].disable()
            #end if
        #end if

        elif projOption == self.projectOptions[3]:
            # Enable entries
            self.cyanaEntry.configure(state='normal')
            self.nameEntry.configure(state='normal')

            if (len(self.cyanaEntry.get()) > 0 and len(self.nameEntry.get())  > 0):
                buttons[0].enable()
                buttons[1].enable()
            else:
                buttons[0].disable()
                buttons[1].disable()
            #end if
        #end if

        self.projectStatus.clear()
        if not self.project:
            self.projectStatus.setText('No open project')
            self.closeProjectButton.setText('Close Project')
            self.closeProjectButton.disable()
        else:
            self.projectStatus.setText(self.project.format())
            self.closeProjectButton.enable()
            self.closeProjectButton.setText(sprintf('Close Project "%s"', self.project.name))
        #end if
    #end def

    def redirectConsole(self):

        #pipe = TextPipe(self.inputTextBox.text_area)
        #sys.stdin = pipe

        pipe = TextPipe(self.outputTextBox.text_area)
        sys.stdout = pipe
        nTmessage.stream = pipe
    # end def redirectConsole
#    sys.stderr = pipe

    def resetConsole(self):
        #sys.stdin   = stdin
        nTmessage.stream = stdout
        sys.stdout  = stdout
        sys.stderr  = stderr
    # end def resetConsole

    def open(self):

        self.redirectConsole()
        BasePopup.open(self)
    # end def open

    def close(self):

        geometry = self.getGeometry()
        self.resetConsole()
        BasePopup.close(self)

        print 'close:',geometry
        sys.exit(0) # remove later
    # end def close

    def destroy(self):

        geometry = self.getGeometry()
        self.resetConsole()
        BasePopup.destroy(self)

        print 'destroy:',geometry
        sys.exit(0) # remove later
Example #5
0
class EditPeakPopup(BasePopup):
    """
  **Edit Position, Intensity & Details for a Peak**
  
  This popup window provides an means of editing peak information as an
  alternative to editing values in the main peak tables. This popup is also used
  to specify parameters for when a new peak is explicitly added to a peak list
  using a tabular display.

  The user can specify the position of the peak's dimensions in ppm, Hz or data
  point units. Also, the user can adjust the height and volume peak intensity
  values and a textual "Details" field, ,which can carry the user's comments
  about the peak.

  When editing an existing peak, no changes are made to the peak until the
  [Update] button is pressed. Likewise for a new peak the [Add Peak] button
  commits the changes. If the popup window is closed before the changes are 
  committed then the entire editing or peak addition operation is cancelled.

  """
    def __init__(self, parent, peak=None, peakList=None, *args, **kw):

        self.titleColor = '#000080'
        self.numDims = 0
        self.peak = peak

        kw['borderwidth'] = 6
        BasePopup.__init__(self, parent=parent, title='Edit Peak', **kw)

        self.registerNotify(self.deletedPeak, 'ccp.nmr.Nmr.Peak', 'delete')

        for func in ('setAnnotation', 'setDetails', 'setFigOfMerit'):
            self.registerNotify(self.updatePeak, 'ccp.nmr.Nmr.Peak', func)
        for func in ('setAnnotation', 'setPosition', 'setNumAliasing'):
            self.registerNotify(self.updatePeak, 'ccp.nmr.Nmr.PeakDim', func)
        for func in ('__init__', 'delete', 'setValue'):
            self.registerNotify(self.updatePeak, 'ccp.nmr.Nmr.PeakIntensity',
                                func)

        self.dimensionLabels = []
        self.dimensionEntries = []
        self.update(self.peak, peakList)

    def body(self, guiParent):

        self.geometry("+150+150")

        guiParent.grid_columnconfigure(0, weight=1)
        self.master_frame = guiParent

        units = ('ppm', 'point', 'Hz')

        self.unit = 'ppm'

        self.specLabel = Label(guiParent,
                               fg=self.titleColor,
                               grid=(0, 0),
                               sticky='ew')

        self.peakLabel = Label(guiParent, grid=(0, 1), sticky='ew')

        self.unit_frame = frame = Frame(guiParent,
                                        grid=(1, 1),
                                        gridSpan=(1, 2))

        self.unitLabel = Label(frame, text='Current units: ', grid=(0, 0))
        tipText = 'Selects which unit of measurement to display peak dimension positions with'
        self.unitSelect = PulldownList(frame,
                                       callback=self.changeUnit,
                                       texts=units,
                                       grid=(0, 1),
                                       tipText=tipText)

        self.heightLabel = Label(guiParent,
                                 text='Height',
                                 borderwidth=2,
                                 relief='groove')
        tipText = 'Sets the peak height; the value of the spectrum point intensity (albeit often interpolated)'
        self.heightEntry = FloatEntry(guiParent,
                                      borderwidth=1,
                                      tipText=tipText)
        self.volumeLabel = Label(guiParent,
                                 text='Volume',
                                 borderwidth=2,
                                 relief='groove')
        tipText = 'Sets the peak volume integral; normally a summation of data point values'
        self.volumeEntry = FloatEntry(guiParent,
                                      borderwidth=1,
                                      tipText=tipText)
        self.detailLabel = Label(guiParent,
                                 text='Details',
                                 borderwidth=2,
                                 relief='groove')
        tipText = 'A user-configurable textual comment for the peak, which appears an tables and occasionally on spectrum displays'
        self.detailEntry = Entry(guiParent, borderwidth=1, tipText=tipText)

        tipTexts = [
            'Commits the specified values to update the peak and closes the popup',
        ]
        texts = ['Update']
        commands = [self.commit]
        self.buttons = UtilityButtonList(guiParent,
                                         texts=texts,
                                         commands=commands,
                                         doClone=False,
                                         helpUrl=self.help_url,
                                         tipTexts=tipTexts)

    def open(self):

        self.updatePeak()
        BasePopup.open(self)

    def updatePeak(self, object=None):

        peak = None
        if object:
            if object.className == 'Peak':
                peak = object
            elif object.className == 'PeakDim':
                peak = object.peak
            elif object.className == 'PeakIntensity':
                peak = object.peak

        if (peak is None) or (peak is self.peak):
            self.update(peak=self.peak)

    def update(self, peak=None, peakList=None):

        # first destroy old labels and entries (saves grid hassles)

        for label in self.dimensionLabels:
            label.destroy()
        for entry in self.dimensionEntries:
            entry.destroy()

        # now setup required data

        if peak:
            title = 'Edit Peak'
            self.buttons.buttons[0].config(text='Update')
        else:
            title = 'Add Peak'
            self.buttons.buttons[0].config(text='Add Peak')

        self.setTitle(title)

        self.peak = peak
        self.peakList = peakList
        if not peakList:
            if peak:
                self.peakList = peak.peakList
            else:
                return

        peakList = self.peakList
        spectrum = peakList.dataSource.name
        self.numDims = peakList.dataSource.numDim
        self.posn = self.numDims * [0]
        self.dataDims = peakList.dataSource.sortedDataDims()

        if self.peak:

            serial = self.peak.serial
            dims = self.peak.sortedPeakDims()
            details = self.peak.details
            if not details:
                details = ''
            if self.peak.annotation:
                annotn = '%0.16s' % self.peak.annotation
            else:
                annotn = ''

            heightIntensity = self.peak.findFirstPeakIntensity(
                intensityType='height')
            volumeIntensity = self.peak.findFirstPeakIntensity(
                intensityType='volume')

            if heightIntensity:
                height = heightIntensity.value
            else:
                height = 0.0

            if volumeIntensity:
                volume = volumeIntensity.value
            else:
                volume = 0.0

            for i in range(self.numDims):
                peakDim = dims[i]
                dataDimRef = peakDim.dataDimRef
                if dataDimRef:
                    self.posn[i] = peakDim.position + (
                        peakDim.numAliasing * dataDimRef.dataDim.numPointsOrig)
                else:
                    self.posn[i] = peakDim.position

        else:

            dict = peakList.__dict__.get('serialDict')
            if dict is None:
                serial = 1
            else:
                serial = dict.get('peaks', 0) + 1

            height = 0.0
            volume = 0.0
            details = ''
            annotn = ''

        self.specLabel.set(
            text='Experiment: %s Spectrum: %s PeakList: %d' %
            (peakList.dataSource.experiment.name, spectrum, peakList.serial))
        self.peakLabel.set(text='Peak: %d' % serial)

        self.dimensionLabels = self.numDims * ['']
        self.dimensionEntries = self.numDims * ['']
        for i in range(self.numDims):
            pos = self.posn[i]
            if self.unit != 'point':
                dataDim = self.dataDims[i]
                if dataDim.className == 'FreqDataDim':
                    pos = unit_converter[('point', self.unit)](
                        pos, getPrimaryDataDimRef(dataDim))
            self.dimensionLabels[i] = Label(self.master_frame,
                                            text='F%d' % (i + 1),
                                            borderwidth=2,
                                            relief='groove')
            tipText = 'The peak position in dimension %d, in the specified units' % (
                i + 1)
            self.dimensionEntries[i] = FloatEntry(self.master_frame,
                                                  borderwidth=1,
                                                  text='%8.4f' % pos,
                                                  tipText=tipText)

        self.heightEntry.set(text='%f' % height)
        self.volumeEntry.set(text='%f' % volume)
        self.detailEntry.set(text=details)

        row = 0
        self.specLabel.grid(row=row, column=0, columnspan=2, sticky='nsew')

        row = row + 1
        self.peakLabel.grid(row=row, column=0, sticky='nsew')
        self.unit_frame.grid(row=row, column=1, columnspan=2, sticky='nsew')

        for i in range(self.numDims):
            row = row + 1
            self.dimensionLabels[i].grid(row=row, column=0, sticky='nsew')
            self.dimensionEntries[i].grid(row=row,
                                          column=1,
                                          columnspan=3,
                                          sticky='e')

        row = row + 1
        self.heightLabel.grid(row=row, column=0, sticky='nsew')
        self.heightEntry.grid(row=row, column=1, columnspan=3, sticky='e')

        row = row + 1
        self.volumeLabel.grid(row=row, column=0, sticky='nsew')
        self.volumeEntry.grid(row=row, column=1, columnspan=3, sticky='e')

        row = row + 1
        self.detailLabel.grid(row=row, column=0, sticky='nsew')
        self.detailEntry.grid(row=row, column=1, columnspan=3, sticky='e')

        row = row + 1
        self.buttons.grid(row=row, column=0, columnspan=4, sticky='nsew')

    def changeUnit(self, unit):

        posDisp = self.numDims * [None]
        for i in range(self.numDims):
            posDisp[i] = float(self.dimensionEntries[i].get())
            if self.unit != 'point':
                dataDim = self.dataDims[i]
                if dataDim.className == 'FreqDataDim':
                    posDisp[i] = unit_converter[(self.unit, 'point')](
                        posDisp[i], getPrimaryDataDimRef(dataDim))

        self.unit = unit
        if self.unit != 'point':
            for i in range(self.numDims):
                dataDim = self.dataDims[i]
                if dataDim.className == 'FreqDataDim':
                    posDisp[i] = unit_converter[('point', self.unit)](
                        posDisp[i], getPrimaryDataDimRef(dataDim))

        for i in range(self.numDims):
            value = posDisp[i]
            if value is None:
                self.dimensionEntries[i].set('None')
            else:
                self.dimensionEntries[i].set('%8.4f' % posDisp[i])

    def commit(self):

        posDisp = self.numDims * [0]

        for i in range(self.numDims):
            posDisp[i] = float(self.dimensionEntries[i].get())
            if self.unit != 'point':
                dataDim = self.dataDims[i]
                if dataDim.className == 'FreqDataDim':
                    self.posn[i] = unit_converter[(self.unit, 'point')](
                        posDisp[i], getPrimaryDataDimRef(dataDim))

            else:
                self.posn[i] = posDisp[i]

        if self.peak:
            movePeak(self.peak, self.posn)
        else:
            self.peak = pickPeak(self.peakList, self.posn)

        height = self.heightEntry.get()
        volume = self.volumeEntry.get()
        setManualPeakIntensity(self.peak, height, intensityType='height')
        setManualPeakIntensity(self.peak, volume, intensityType='volume')

        details = self.detailEntry.get() or None

        self.peak.setDetails(details)

        self.close()

    def deletedPeak(self, peak):

        if self.peak is peak:
            self.close()

    def destroy(self):

        self.unregisterNotify(self.deletedPeak, 'ccp.nmr.Nmr.Peak', 'delete')

        for func in ('setAnnotation', 'setDetails', 'setFigOfMerit'):
            self.unregisterNotify(self.updatePeak, 'ccp.nmr.Nmr.Peak', func)
        for func in ('setAnnotation', 'setPosition', 'setNumAliasing'):
            self.unregisterNotify(self.updatePeak, 'ccp.nmr.Nmr.PeakDim', func)
        for func in ('__init__', 'delete', 'setValue'):
            self.unregisterNotify(self.updatePeak, 'ccp.nmr.Nmr.PeakIntensity',
                                  func)

        BasePopup.destroy(self)
Example #6
0
class OpenMacroPopup(BasePopup):
  """
  **Locate Python Macro Scripts On Disk**
  
  This popup is used to locate a Python file and function definition on disk
  so that it can be loaded into Analysis as a "Macro". The top table
  is a file browser that the user can navigate to the location of the Python
  file (typically sending in ".py"). When a Python file is selected in the
  upper table the system will look through the contents of the file to find
  any macro functions that are defined within. Note that a macro function 
  is defined by the normal Python "def" keyword but must take "argSever"
  as its first input argument. 
  
  Any macro functions in the selected file will be displayed in the
  lower table. Clicking on the name of a function in this table
  selects it for opening. The user may edit the name of the macro for 
  display purposes within Analysis. Finally clicking [Load Macro]
  will add it to the CCPN project, stored in a user-specific way
  inside the current Analysis profile. Once loaded into the
  project the new macro will appear in the main macro table
  (the "Macros" tab of `User Options`_)
  
  .. _`User Options`: EditProfilesPopup.html
    
  """


  def __init__(self, parent, **kw):

    # TBD: properly
    transient = True
    BasePopup.__init__(self, parent=parent, title='Open macro', transient=transient, **kw)

  def body(self, guiParent):

    guiParent.grid_columnconfigure(1,weight=1)
    row = 0

    file_types = [  FileType('Python', ['*.py']), FileType('All', ['*']) ]
    self.file_select = FileSelect(guiParent, file_types=file_types,
                                  single_callback=self.chooseFile,
                                  double_callback=self.chooseFile)
    self.file_select.grid(row=row, column=0, columnspan=2, sticky='nsew')
    
    row = row + 1
    headingList=('Function',)
    self.scrolledMatrix = ScrolledMatrix(guiParent, initialRows=4,
                            headingList=headingList, callback=self.selectFunction)
    self.scrolledMatrix.grid(row=row, column=0, columnspan=2, sticky='nsew')
    guiParent.grid_rowconfigure(row,weight=1)

    row = row + 1
    self.moduleLabel1 = Label(guiParent, text='Module: ')
    self.moduleLabel1.grid(row=row, column=0, sticky='nw')
    self.moduleLabel2 = Label(guiParent, text=' ')
    self.moduleLabel2.grid(row=row, column=1, sticky='nw')

    row = row + 1
    self.functionLabel1 = Label(guiParent, text='Function: ')
    self.functionLabel1.grid(row=row, column=0, sticky='nw')
    self.functionLabel2 = Label(guiParent, text=' ')
    self.functionLabel2.grid(row=row, column=1, sticky='nw')

    row = row + 1
    self.nameLabel = Label(guiParent, text='Name: ')
    self.nameLabel.grid(row=row, column=0, sticky='nw')
    self.nameEntry = Entry(guiParent, text=' ', width=40)
    self.nameEntry.grid(row=row, column=1, sticky='nw')

    row = row + 1
    texts = [ 'Load Macro' ]
    commands = [ self.loadMacro ]
    buttons = UtilityButtonList(guiParent, texts=texts,
                                commands=commands, helpUrl=self.help_url)
    buttons.grid(row=row, column=0, columnspan=2, sticky='ew')
    
    self.loadButton = buttons.buttons[0]
    self.loadButton.disable()
    
    self.path     = None
    self.module   = None
    self.function = None

  def selectFunction(self, function, row, col):
  
    if function:
      self.loadButton.enable()
      self.function = function
      self.functionLabel2.set(function)
      self.nameEntry.set(function)
    
  def updateFunctions(self, file):
  
    self.loadButton.disable()
    functions = []
    fileHandle = open(file, 'r')
    line = fileHandle.readline()
    textMatrix = []
    while line :
      match = re.match('\s*def\s+(\w+)\s*\(.*argServer',line)
      if match:
        function = match.group(1)
        functions.append(function)
        textMatrix.append( [function,] )
      line = fileHandle.readline()

    self.scrolledMatrix.update(objectList=functions,textMatrix=textMatrix)

  def chooseFile(self, file):
    
    fullPath =self.file_select.getFile()
    if not os.path.isdir(fullPath) and file:
      (self.path, module) = splitPath(fullPath)
      module = re.sub('\..+?$','',module)
      self.module = module
      self.moduleLabel2.set(module)
      self.updateFunctions(file)

  def loadMacro(self):
    
    if self.module and self.function and self.path:
      name = self.nameEntry.get()
      if not name:
        name = self.function
        
      analysisProfile = self.analysisProfile
      
      m1 = analysisProfile.newMacro(name=name,path=self.path,
                                    function=self.function,
                                    module=self.module,ordering=1)
 
    self.close()
Example #7
0
class TableExportPopup(BasePopup):
    def __init__(self,
                 parent,
                 headings,
                 entries,
                 title='',
                 file='',
                 *args,
                 **kw):

        headings = [heading.replace('\n', ' ') for heading in headings]

        if (headings[0].lower() == 'number'):
            self.addNumber = False
        else:
            self.addNumber = True
            headings.insert(0, 'Number')

        if (not title):
            title = 'Export data'

        self.exportSelection = parent.tableExportSelection
        self.headings = headings
        self.entries = entries
        self.file = file

        kw['title'] = title
        kw['transient'] = True
        kw['modal'] = True
        BasePopup.__init__(self, parent=parent, *args, **kw)

    def body(self, master):

        master.grid_columnconfigure(2, weight=1)

        row = 0
        label = Label(master, text='Data to export:')
        label.grid(row=row, column=0, columnspan=3, sticky=Tkinter.W)

        self.check_buttons = {}
        i = 0
        for heading in self.headings:
            row = row + 1
            isSelected = self.exportSelection.get(row, True)
            self.check_buttons[i] = c = CheckButton(
                master, selected=isSelected, callback=self.toggleCheckButton)
            c.grid(row=row, column=1)
            label = Label(master, text=heading)
            label.grid(row=row, column=2, sticky=Tkinter.W)
            i += 1

        row = row + 1
        button = Button(master, text='File:', command=self.findFile)
        button.grid(row=row, column=0, sticky=Tkinter.W)
        self.file_entry = Entry(master, text=self.file, width=30)
        self.file_entry.grid(row=row,
                             column=1,
                             columnspan=2,
                             sticky=Tkinter.EW)

        row = row + 1
        label = Label(master, text='Format:')
        label.grid(row=row, column=0, sticky=Tkinter.W)
        self.format_menu = PulldownMenu(master, entries=exportFormats)
        self.format_menu.grid(row=row,
                              column=1,
                              columnspan=2,
                              sticky=Tkinter.W)

        row = row + 1
        master.grid_rowconfigure(row, weight=1)
        texts = ['Save']
        commands = [self.ok]
        buttons = createDismissHelpButtonList(master,
                                              texts=texts,
                                              commands=commands,
                                              dismiss_text='Cancel')
        buttons.grid(row=row, column=0, columnspan=3, sticky=Tkinter.EW)

    def toggleCheckButton(self, isSelected):

        for i in self.check_buttons.keys():
            self.exportSelection[i] = self.check_buttons[i].get()

    def apply(self):

        file = self.file_entry.get()
        format = self.format_menu.getSelected()
        join = exportJoin[format]

        n = 0
        headings = []
        for heading in self.headings:
            if self.check_buttons[n].get():
                headings.append(n)
            n += 1

        if (not headings):
            showError('Nothing selected',
                      'No data selected to export.',
                      parent=self)
            return False

        try:
            fp = open(file, 'w')
        except IOError, e:
            showError('File error', str(e))
            return False

        for n in headings:
            if (n != headings[0]):
                fp.write(join)
            fp.write(self.headings[n].encode('utf-8'))
        fp.write('\n')

        m = 0
        for data in self.entries:
            if data:
                for n in headings:
                    if (n != headings[0]):
                        fp.write(join)
                    if (self.addNumber):
                        if (n == 0):
                            x = m + 1
                        else:
                            x = data[n - 1]
                    else:
                        x = data[n]
                    if (type(x) == type(float(1))):
                        if (x == 0):
                            t = '0'
                        elif ((abs(x) > 10000) or (abs(x) < 0.001)):
                            t = '%6.5e' % x
                        else:
                            t = '%6.5f' % x
                    else:
                        t = str(x)
                    fp.write(t)
                fp.write('\n')
                m = m + 1

        fp.close()

        return True
Example #8
0
class NmrPipePseudoPopup(BasePopup):

    pseudoEntries = ('Is Pseudo Expt', 'Is Not Pseudo Expt')

    def __init__(self, parent, params, dim, fileName='', *args, **kw):

        self.dim = dim
        self.params = params
        self.fileName = fileName

        m = template_re.match(fileName)
        if m:
            n = len(m.groups(2))
            ss = '%%0%dd' % n
            template = re.sub(template_re, r'\1%s\3' % ss, fileName)
        else:
            template = fileName
        self.template = template

        BasePopup.__init__(self,
                           parent=parent,
                           title='NMRPipe Pseudo Data',
                           modal=True,
                           **kw)

    def body(self, master):

        fileName = self.fileName
        directory = os.path.dirname(fileName)
        if not directory:
            directory = os.getcwd()
        fileName = os.path.basename(fileName)

        m = template_re.match(fileName)
        if m:
            n = len(m.groups(2))
            ss = '%%0%dd' % n
            template = re.sub(template_re, r'\1%s\3' % ss, fileName)
        else:
            template = fileName

        master.rowconfigure(0, weight=1)
        master.rowconfigure(1, weight=1)
        master.columnconfigure(1, weight=1)

        tipTexts = [
            'The experiment is pseudo-N dimensional, with a sampled axis',
            'The experiment is the regular kind with only NMR frequency axes'
        ]
        self.pseudoButton = RadioButtons(
            master,
            entries=self.pseudoEntries,
            select_callback=self.changedPseudoMode,
            grid=(0, 0),
            sticky='nw',
            tipTexts=tipTexts)

        frame = self.pseudoFrame = Frame(master)
        self.pseudoFrame.grid(row=1, column=0, sticky='nsew')

        row = 0
        npts = self.params.npts[self.dim]
        tipText = 'Number of data points (planes) along sampled axis'
        label = Label(frame, text='Number of points: ')
        label.grid(row=row, column=0, sticky='e')
        self.nptsEntry = IntEntry(frame,
                                  text=npts,
                                  tipText=tipText,
                                  width=8,
                                  grid=(row, 1))

        tipText = 'Load the values for the sampled axis from a text file containing a list of numeric values'
        Button(frame,
               text='Load values from text file',
               command=self.loadValues,
               tipText=tipText,
               grid=(row, 2),
               sticky='ew')

        row = row + 1
        tipText = 'The values (e.g. T1, T2) corresponding to each data point (plane) along sampled axis'
        label = Label(frame, text='Point values: ')
        label.grid(row=row, column=0, sticky='e')
        self.valueEntry = FloatEntry(frame, isArray=True, tipText=tipText)
        self.valueEntry.grid(row=row, column=1, columnspan=2, sticky='ew')

        row = row + 1
        tipText = 'Fetch the Point values from the files given by the NMRPipe template'
        button = Button(
            frame,
            text='Fetch values from file(s) specified by template below',
            command=self.fetchValues,
            tipText=tipText)
        button.grid(row=row, column=1, columnspan=2, sticky='w')

        row = row + 1
        tipText = 'The directory where the data files reside'
        button = Button(frame,
                        text='Data directory: ',
                        command=self.chooseDirectory)
        button.grid(row=row, column=0, sticky='e')
        self.directoryEntry = Entry(frame,
                                    text=directory,
                                    width=40,
                                    tipText=tipText)
        self.directoryEntry.grid(row=row, column=1, columnspan=2, sticky='ew')

        row = row + 1
        tipText = 'The NMRPipe template for the data files, if you want to use these to fetch the point values from'
        button = Button(frame,
                        text='NMRPipe template: ',
                        command=self.chooseFile)
        button.grid(row=row, column=0, sticky='e')
        self.templateEntry = Entry(frame, text=template, tipText=tipText)
        self.templateEntry.grid(row=row, column=1, columnspan=2, sticky='ew')

        for n in range(row):
            frame.rowconfigure(n, weight=1)
        frame.columnconfigure(1, weight=1)

        buttons = UtilityButtonList(master,
                                    closeText='Ok',
                                    doClone=False,
                                    closeCmd=self.updateParams,
                                    helpUrl=self.help_url)
        buttons.grid(row=2, column=0, sticky='ew')

    def loadValues(self):

        directory = self.parent.fileSelect.getDirectory()
        fileSelectPopup = FileSelectPopup(self,
                                          title='Select Sampled Data File',
                                          dismiss_text='Cancel',
                                          selected_file_must_exist=True,
                                          multiSelect=False,
                                          directory=directory)

        fileName = fileSelectPopup.file_select.getFile()

        if not fileName:
            return

        fileObj = open(fileName, 'rU')

        data = ''
        line = fileObj.readline()
        while line:
            data += line
            line = fileObj.readline()

        fileObj.close()

        data = re.sub(',\s+', ',', data)
        data = re.sub('\s+', ',', data)
        data = re.sub(',,', ',', data)
        data = re.sub('[^0-9,.\-+eE]', '', data)

        self.valueEntry.set(data)

    def chooseDirectory(self):

        directory = os.path.dirname(self.fileName)
        if not directory:
            directory = os.getcwd()
        popup = FileSelectPopup(self, directory=directory, show_file=False)
        directory = popup.getDirectory()
        popup.destroy()

        if directory:
            self.directoryEntry.set(directory)

    def chooseFile(self):

        directory = self.directoryEntry.get()
        if not directory:
            directory = os.getcwd()
        popup = FileSelectPopup(self, directory=directory)
        file = popup.getFile()
        popup.destroy()

        if file:
            template = os.path.basename(file)
            self.templateEntry.set(template)

    def updateParams(self):

        params = self.params
        if self.pseudoButton.get() == self.pseudoEntries[0]:
            npts = self.nptsEntry.get()
            params.npts[self.dim] = npts
            values = self.valueEntry.get()
            try:
                params.setSampledDim(self.dim, values)
            except ApiError, e:
                showError('Set Sampled Dim', e.error_msg, parent=self)
                return
            params.fixNullDims(ignoreDim=self.dim)
        else:
Example #9
0
class IsotopeSchemeEditor(BasePopup):
    """
  **Create and Edit Per-residue Reference Isotope Schemes**
  
  This system allows the user to create schemes that describe particular
  patterns of atomic isotope labelling in terms of combinations of isotopically
  labelled forms of residues. Once constructed, these schemes may then be
  applied to a molecule of known residue sequence to gauge the levels of
  spin-active isotope incorporation in an NMR experiment. This information is
  useful in several places withing Analysis, including giving more intelligent
  assignment options and in the generation of distance restraints by matching
  peak positions to chemical shifts. Although the schemes may be used directly
  they are typically used as reference information for configuring the `Isotope
  Labelling`_ system; where isotope labelling patterns are tied to particular
  molecules and experiments.

  Because all of the different isotope labelled versions (isotopomers) of each
  residue type are described independently, a scheme can be used to estimate the
  specific amounts of incorporation present at multiple atom sites at the same
  time. For example, although a residue type may have significant levels of 13C
  at the CA and CB positions on average, there may be no form of the residue
  where CA and CB are labelled at the same time, and thus CA-CB correlations
  would not be observed in NMR.

  This popup window is divided into three main tabs, the first describes the
  overall schemes that are available; that would be applied to a molecule in a
  given situation. The second tab details the residue isotopomer components
  within the selected scheme, i.e. which labelled residue forms are present. The
  last tab displays isotopomer labelling in a graphical, three-dimensional way.
  If any isotope labelling schemes have been created or edited the user may 
  immediately save these to disk via the [Save Schemes] button to the right of
  the tabs, although these will naturally be saved when the main CCPN project
  is.

  **Reference Schemes**

  This table lists all of the reference isotope schemes that are available to
  the project. A number of standard schemes are included by default, as part of
  the main CCPN installation. However, the user is free to create new schemes,
  either from a completely blank description or by copying and modifying one of
  the existing schemes. By selecting on a isttope scheme row in the table the
  scheme is selected to be active for the whole popup and the user can see the
  contents of the scheme via the other two tabs.

  It should be noted that the user cannot edit the standard schemes provided by
  CCPN, given that these are stored with the software. Any new or copied schemes
  that the user creates will be stored inside the current CCPN project. If a new
  scheme should be made available to multiple projects, its XML file can be
  copied into the main CCPN installation, if the user has appropriate write
  access.

  **Isotopomers**
  
  The middle tab allows the user to view, and where appropriate edit, the
  isotope labelling descriptions for the residues within the current scheme
  (selected in the pulldown menu at the top). An isotope scheme is constructed
  by specifying one or more isotopomers for each residue type. Each isotopomer
  represents a different way of incorporating spin-active atom labels into a
  given kind of residue. Often there will only be one labelled form of a
  residue, and hence one isotopomer. However, with some kinds of isotope
  enrichment, for example using glycerol 13C labelled at the C2 position,
  connected labelled and unlabelled atom sites can be incorporated in
  alternative ways, resulting in distinct forms of labelling patterns that are
  not the result of a pure random mix. Knowing which labels are present at the
  same time, in the same isotopomer form, can be very important for determining
  which NMR correlations are possible.

  In general use when looking through the default, immutable reference schemes
  that come with CCPN the user can scroll through the isotopomer versions of
  each residue in the upper table. By clicking on one of these rows the lower
  table is filled with details of the amount of each kind of isotope (on
  average) at each atom site. For the lower "Atom Labels" table only one kind of
  chemical element is shown at a time, but the user may switch to  a different
  one via the "Chemical Element" pulldown.

  **Editing Isotopomers**

  When dealing with copied or new isotope schemes the user is allowed to 
  edit all aspects of the scheme. With a completely new scheme there will be no
  isotopomer records to start with and it is common practice to fill in a
  standard set of isotopomers, one for each residue type, made with a base level
  of isotope incorporation. To set this base level the user can use [Set Default
  Abundances] to manually specify values, although the default is to use natural
  abundance levels, which is appropriate in most circumstances. With the base
  levels set the [Add Default Abundance Set] will automatically fill-in a
  starting set of isotopomers for the scheme. Extra isotopomers can be added for
  a specific type of residue via the [Add New:] function and adjacent pulldown
  menu or by copying existing ones; whichever is easier. Each isotopomer has an
  editable weight to enable the user to indicate the relative abundance within a
  given residue type.

  Once a new isotopomer specification is created clicking on its row allows the 
  user to specify the isotope labelling pattern in the lower "Atom Labels"
  table. Here the user selects which kind of chemical element to consider and
  then  double-clicks to edit the "Weighting" columns in the table. The
  weightings represent the relative abundance of a given nuclear isotope at a
  given atom site. The weightings could be set as ratios, fractions, or
  percentages; it is only the relative proportion that is important. For example
  if a carbon atom site was known to have 5% Carbon-12 and 95% Carbon-13
  isotopes then the respective weights could be entered as 1 & 19 or  0.05 &
  0.95; whatever is most convenient. For efficient setup of schemes the
  [Propagate Abundances] function can be used to spread the same levels of
  incorporation over several atom sites (from the last selected row).

  **Isotopomer Structure**
  
  The last tab is an alternative way of presenting the isotope patterns present
  within the residues of the current scheme (selected in either of the first two
  tabs). Here the user selects a residue type in the upper left pulldown menu
  and then a numbered isotopomer, or an average of all isotopomers, in the right
  hand pulldown menu. The structural display will show a moveable picture of the
  residue (in a standard conformation) where unlabelled atom sites are
  represented with grey spheres, labelled sites with yellow spheres and
  intermediate incorporation with shades in between.

  It should be noted that this kind of 3D display is only possible if there is
  an idealised structure available for a residue type. This data will be 
  present for all of the regular biopolymer residues, but may be missing for
  more unusual compounds; although a lack of coordinates does not impact upon
  the isotopomer setup.

  To move and rotate the three-dimensional residue display the following
  keyboard controls may be used:
  
  * Rotate: Arrow keys
  
  * Zoom: Page Up & Page Down keys

  * Translate: Arrow keys + Control key

  Or alternatively the following mouse controls:
  
  * Rotate: Middle button click & drag
  
  * Zoom: Mouse wheel or middle button click + Shift key & drag up/down

  * Translate: Middle button click & drag + Control key

  Also an options menu appears when the right mouse button is clicked.

  .. _`Isotope Labelling`: EditMolLabellingPopup.html
 
  """
    def __init__(self, parent, project=None, *args, **kw):

        if not project:
            self.project = Implementation.MemopsRoot(
                name='defaultUtilityProject')
        else:
            self.project = project

        self.waiting = False
        self.waitingAtom = False
        self.molType = 'protein'
        self.scheme = None
        self.isotopomer = None
        self.isotopomerV = False  # Not None
        self.ccpCodeV = None
        self.element = 'C'
        self.atomLabelTuple = None
        self.isotopes = [x[0] for x in getSortedIsotopes(self.project, 'C')]
        self.defaultAbun = {}

        BasePopup.__init__(self,
                           parent=parent,
                           title='Molecule : Reference Isotope Schemes',
                           **kw)

    def body(self, guiFrame):

        self.geometry('700x600')

        guiFrame.expandGrid(0, 0)

        tipTexts = [
            'A table of all of the reference isotope scheme definitions available to the project',
            'A list of the residue isotopomers that comprise the selected isotope labelling scheme',
            'A three-dimensional representation of residues and their isotopomer labelling'
        ]

        options = ['Reference Schemes', 'Isotopomers', 'Isotopomer Structure']

        tabbedFrame = TabbedFrame(guiFrame,
                                  options=options,
                                  grid=(0, 0),
                                  tipTexts=tipTexts)

        self.tabbedFrame = tabbedFrame
        frameA, frameB, frameC = tabbedFrame.frames

        #
        # Schemes
        #

        frameA.expandGrid(0, 0)

        tipTexts = [
            'A short textual code that identifies the reference isotope scheme in graphical displays',
            'The full name for the isotope scheme',
            'A detailed description of the isotope scheme including user comments',
            'The name of the CCPN data repository in which the isotope scheme is saved; "refData" is in the CCPn installation'
        ]
        headingList = ['Code', 'Name', 'Description', 'Save Location']
        self.schemeNameEntry = Entry(self,
                                     text='',
                                     returnCallback=self.setSchemeName,
                                     width=20)
        self.schemeDetailsEntry = Entry(self,
                                        text='',
                                        returnCallback=self.setSchemeDetails,
                                        width=20)
        editWidgets = [
            None, self.schemeNameEntry, self.schemeDetailsEntry, None
        ]
        editGetCallbacks = [
            None, self.getSchemeName, self.getSchemeDetails, None
        ]
        editSetCallbacks = [
            None, self.setSchemeName, self.setSchemeDetails, None
        ]

        self.schemeMatrix = ScrolledMatrix(frameA,
                                           headingList=headingList,
                                           callback=self.selectScheme,
                                           editWidgets=editWidgets,
                                           editSetCallbacks=editSetCallbacks,
                                           editGetCallbacks=editGetCallbacks,
                                           multiSelect=False,
                                           grid=(0, 0),
                                           tipTexts=tipTexts)
        self.schemeMatrix.doEditMarkExtraRules = self.schemeEditRules

        tipTexts = [
            'Make a new reference isotope scheme definition based on a copy of the scheme currently selected',
            'Delete the selected isotope scheme',
            'Make a new, blank isotope scheme'
        ]
        texts = ['Copy', 'Delete', 'New']
        commands = [self.copyScheme, self.removeScheme, self.makeNewScheme]
        self.schemeButtons = ButtonList(frameA,
                                        texts=texts,
                                        commands=commands,
                                        grid=(1, 0),
                                        tipTexts=tipTexts)

        #
        # Isotopomers
        #

        frameB.expandGrid(3, 0)

        row = 0
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(0, 2)

        tipText = 'Selects which of the available isotope schemes to view/edit'
        label = Label(frame, text='Reference Scheme:', grid=(0, 0))
        self.schemePulldown = PulldownList(frame,
                                           callback=self.setLabellingScheme,
                                           grid=(0, 1),
                                           tipText=tipText)
        row += 1
        div = LabelDivider(frameB, text='Isotopomers', grid=(row, 0))

        row += 1
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(1, 2)

        self.isotopomerFrame = frame
        self.abundanceWidget = MultiWidget(self,
                                           FloatEntry,
                                           relief='raised',
                                           borderwidth=2,
                                           callback=self.setDefaultAbundances,
                                           useImages=False)

        tipText = 'Opens a panel that allows you to set the basis/default abundances for C, H & N isotopes; used as the starting point for new isotopomer definitions'
        self.abundanceButton = Button(frame,
                                      text='Set Default\nAbundances',
                                      borderwidth=1,
                                      command=self.enterDefaultAbundances,
                                      grid=(0, 0),
                                      tipText=tipText)

        tipText = 'Sets the basis/default abundances for C, H & N isotopes to their natural abundance proportions'
        button = Button(frame,
                        text='Set Natural\nAbundance Default',
                        borderwidth=1,
                        command=self.resetDefaultAbundance,
                        grid=(0, 1),
                        sticky='ew',
                        tipText=tipText)

        label = Label(frame, text='Molecule Type:', grid=(0, 2), sticky='e')
        entries = standardResidueCcpCodes.keys()
        entries.sort()
        entries.reverse()
        tipText = 'Selects which type of bio-polymer to define residue isotopomer labelling for'
        self.molTypePulldown = PulldownList(frame,
                                            callback=self.setMolType,
                                            texts=entries,
                                            grid=(0, 3),
                                            tipText=tipText)

        row += 1
        tipTexts = [
            'The CCPN code that identifies the kind of residue the isotopomer relates to',
            'The number of the particular isotopomer (isotope pattern) within its residue type',
            'The fraction of the total residues, of its kind, that the isotopomer make up'
        ]
        headingList = ['Ccp Code', 'Variant', 'Weight']
        self.isotopomerWeightEntry = FloatEntry(
            self, text='', returnCallback=self.setIsotopomerWeight, width=6)
        editWidgets = [None, None, self.isotopomerWeightEntry]
        editGetCallbacks = [None, None, self.getIsotopomerWeight]
        editSetCallbacks = [None, None, self.setIsotopomerWeight]

        self.isotopomerMatrix = ScrolledMatrix(
            frameB,
            tipTexts=tipTexts,
            headingList=headingList,
            callback=self.selectIsotopomer,
            editWidgets=editWidgets,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            multiSelect=True,
            grid=(row, 0))
        self.isotopomerMatrix.doEditMarkExtraRules = self.isotopomerEditRules

        row += 1
        frame = Frame(frameB, grid=(row, 0), sticky='ew')
        frame.expandGrid(0, 0)

        tipTexts = [
            'Delete the selected residue isotopomers from the current isotope scheme',
            'Make a new residue isotopomer definition by copying the details of the last selected isotopomer',
            'Add a complete set of isotopomers to the isotope scheme, one for each residue type, based on the states default isotope abundances',
            'For all residue isotopomers in the scheme, set the labelling of one kind of atom (the user is prompted) to its default isotopic incorporation ',
            'Add a new residue isotopomer definition that uses the default isotopic incorporation'
        ]

        texts = [
            'Delete\nSelected', 'Copy\nSelected', 'Add Default\nAbundance Set',
            'Set Atom Type\nTo Default', 'Add\nNew:'
        ]

        commands = [
            self.removeIsotopomers, self.duplicateResidues,
            self.addDefaultIsotopomers, self.setAtomTypeDefault,
            self.addNewIsotopomer
        ]

        self.isotopomerButtons = ButtonList(frame,
                                            texts=texts,
                                            commands=commands,
                                            grid=(0, 0),
                                            tipTexts=tipTexts)
        tipText = 'Selects which kind of residue isotopomer may be added to the current isotope scheme'
        self.ccpCodePulldown = PulldownList(frame,
                                            callback=None,
                                            grid=(0, 1),
                                            sticky='e',
                                            tipText=tipText)

        row += 1
        div = LabelDivider(frameB, text='Atom Labels', grid=(row, 0))

        row += 1
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(1, 3)

        label = Label(frame, text='Chemical Element:', grid=(0, 0))
        tipText = 'Selects which kind of atoms to select from the selected residue isotopomer; to display isotopic incorporation in the below table'
        self.elementPulldown = PulldownList(frame,
                                            callback=self.changeChemElement,
                                            grid=(0, 1),
                                            tipText=tipText)
        self.updateChemElements()

        label = Label(frame, text='Water Exchangeable Atoms:', grid=(0, 2))
        tipText = 'Sets whether to show atoms considered as being "water exchangeable"; their isotopic labelling will rapidly equilibrate with aqueous solvent'
        self.exchangeCheck = CheckButton(frame,
                                         callback=self.updateAtomLabelsAfter,
                                         grid=(0, 3),
                                         selected=False,
                                         tipText=tipText)
        row += 1
        # Tip texts set on update
        headingList = [
            'Atom\nName', 'Weighting\n13C'
            'Weighting\n12C', '%12C', '%13C'
        ]
        self.atomLabelTupleWeightEntry = FloatEntry(
            self, text='', width=6, returnCallback=self.setAtomLabelWeight)

        self.atomsMatrix = ScrolledMatrix(frameB,
                                          headingList=headingList,
                                          callback=self.selectAtomLabel,
                                          multiSelect=True,
                                          grid=(row, 0))
        self.atomsMatrix.doEditMarkExtraRules = self.atomsEditRules

        row += 1
        tipTexts = [
            'For the selected atom sites, in the current isotopomer, set their isotopic incorporation to the default values',
            'Spread the isotopic incorporation values from the last selected atom site to all selected atoms sites'
        ]
        texts = ['Reset Selected to Default Abundance', 'Propagate Abundances']
        commands = [self.setAtomLabelsDefault, self.propagateAbundances]
        self.atomButtons = ButtonList(frameB,
                                      texts=texts,
                                      commands=commands,
                                      grid=(row, 0),
                                      tipTexts=tipTexts)

        #
        # View Frame
        #

        frameC.expandGrid(1, 0)

        row = 0
        frame = Frame(frameC, grid=(row, 0), sticky='ew')
        frame.grid_columnconfigure(3, weight=1)

        label = Label(frame, text='Residue Type:', grid=(0, 0))
        tipText = 'Selects which kind of residue, within the current isotope scheme, to show isotopomer structures for'
        self.viewCcpCodePulldown = PulldownList(
            frame,
            callback=self.selectViewCcpcode,
            grid=(0, 1),
            tipText=tipText)

        label = Label(frame, text='Isotopomer:', grid=(0, 2))
        tipText = 'Selects which kind of isotopomer (labelling pattern) to display, from the selected residue type.'
        self.viewIsotopomerPulldown = PulldownList(
            frame,
            callback=self.selectViewIsotopomer,
            grid=(0, 3),
            tipText=tipText)

        row += 1
        self.viewIsotopomerFrame = ViewIsotopomerFrame(frameC,
                                                       None,
                                                       grid=(row, 0))

        #
        # Main
        #

        tipTexts = [
            'Save all changes to the reference isotope scheme to disk; the saves ALL changes to the CCPN installation for all projects to use',
        ]
        texts = ['Save Schemes']
        commands = [self.saveSchemes]
        self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame,
                                               texts=texts,
                                               commands=commands,
                                               helpUrl=self.help_url,
                                               grid=(0, 0),
                                               sticky='e',
                                               tipTexts=tipTexts)

        self.updateChemElements()
        self.updateCcpCodes()
        self.updateSchemes()
        self.administerNotifiers(self.registerNotify)

    def atomsEditRules(self, atomLabel, row, col):

        if self.scheme:
            return isSchemeEditable(self.scheme)

        else:
            return False

    def isotopomerEditRules(self, isotopomer, row, col):

        if self.scheme:
            return isSchemeEditable(self.scheme)

        else:
            return False

    def schemeEditRules(self, scheme, row, col):

        return isSchemeEditable(scheme)

    def administerNotifiers(self, notifyFunc):

        for func in ('__init__', 'delete', 'setLongName', 'setDetails'):
            for clazz in ('ccp.molecule.ChemCompLabel.LabelingScheme', ):
                notifyFunc(self.updateSchemes, clazz, func)

        for func in ('__init__', 'delete', 'setWeight'):
            notifyFunc(self.updateIsotopomersAfter,
                       'ccp.molecule.ChemCompLabel.Isotopomer', func)
            notifyFunc(self.updateAtomLabelsAfter,
                       'ccp.molecule.ChemCompLabel.AtomLabel', func)

    def getCcpCodeIsotopomers(self, ccpCode):

        chemCompLabel = self.scheme.findFirstChemCompLabel(
            molType=self.molType, ccpCode=ccpCode)

        if chemCompLabel:
            isotopomers = list(chemCompLabel.isotopomers)

        else:
            isotopomers = []

        return isotopomers

    def selectViewCcpcode(self, ccpCode):

        if ccpCode != self.ccpCodeV:
            self.ccpCodeV = ccpCode
            self.isotopomerV = False
            self.updateViewIsotopomerPulldown()

    def selectViewIsotopomer(self, isotopomer):

        self.isotopomerV = isotopomer

        if isotopomer is None:
            isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV)
        else:
            isotopomers = [
                isotopomer,
            ]

        self.viewIsotopomerFrame.setIsotopomers(isotopomers)

    def updateViewCcpCodePulldown(self):

        if self.scheme:
            codes = self.getCcpCodes(self.molType)

            if self.ccpCodeV not in codes:
                self.ccpCodeV = codes[0]
                self.isotopomerV = False  # Not None
                self.updateViewIsotopomerPulldown()

            index = codes.index(self.ccpCodeV)

        else:
            codes = []
            index = 0

        self.viewCcpCodePulldown.setup(codes, codes, index)

    def updateViewIsotopomerPulldown(self):

        index = 0
        isotopomers = []
        names = []

        if self.scheme:
            isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV)
            names = ['%d' % i.serial for i in isotopomers]

            isotopomers.insert(0, None)
            names.insert(0, '<All>')

            if self.isotopomerV not in isotopomers:
                self.isotopomerV = None
                isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV)
                self.viewIsotopomerFrame.setIsotopomers(isotopomers)

        self.viewIsotopomerPulldown.setup(names, isotopomers, index)

    def updateButtons(self):

        buttonsA = self.schemeButtons.buttons
        buttonsB = self.isotopomerButtons.buttons
        buttonsC = self.atomButtons.buttons

        if self.scheme:
            buttonsA[0].enable()
            isEditable = isSchemeEditable(self.scheme)

            if isEditable:
                buttonsA[1].enable()
            else:
                buttonsA[1].disable()

            buttonsB[2].enable()
            buttonsB[3].enable()
            self.bottomButtons.buttons[0].enable()

            if isEditable:
                if self.isotopomer:
                    for button in buttonsB:
                        button.enable()
                    for button in buttonsC:
                        button.enable()

                else:
                    buttonsB[0].disable()
                    buttonsB[1].disable()
                    buttonsB[3].disable()
                    buttonsC[0].disable()
                    buttonsC[1].disable()

                    buttonsB[2].enable()
                    buttonsB[4].enable()

            else:
                for button in buttonsB:
                    button.disable()
                for button in buttonsC:
                    button.disable()

        else:
            buttonsA[0].disable()
            buttonsA[1].disable()
            for button in buttonsB:
                button.disable()
            for button in buttonsC:
                button.disable()
            self.bottomButtons.buttons[0].disable()

    def resetDefaultAbundance(self):

        self.defaultAbun = {}

    def setDefaultAbundances(self, values):

        self.abundanceWidget.place_forget()

        if values is not None:
            i = 0
            for element in elementSymbols:  # TBD getAllIsotopes
                for code, isotope in getSortedIsotopes(self.project, element):
                    self.defaultAbun[isotope] = values[i]
                    i += 1

    def enterDefaultAbundances(self):

        x = self.isotopomerFrame.winfo_x()
        y = self.isotopomerFrame.winfo_y()
        x0 = self.abundanceButton.winfo_x()
        y0 = self.abundanceButton.winfo_y()

        values = []
        options = []

        for element in elementSymbols:  # TBD getAllIsotopes
            for code, isotope in getSortedIsotopes(self.project, element):
                options.append(code + ':')
                values.append(
                    self.defaultAbun.get(isotope, 100.0 * isotope.abundance))

        N = len(values)
        self.abundanceWidget.maxRows = N
        self.abundanceWidget.minRows = N
        self.abundanceWidget.set(values=values, options=options)
        self.abundanceWidget.place(x=x + x0, y=y + y0)

    def selectAtomLabel(self, obj, row, col):

        self.atomLabelTuple = (obj, col)

    def setMolType(self, molType):

        if molType != self.molType:
            self.molType = molType
            self.isotopomer = None
            self.updateCcpCodes()
            self.updateIsotopomers()

    def getCcpCodes(self, molType):

        codes = []
        for code in standardResidueCcpCodes[molType]:
            codes.append(code)

        codes.sort()

        return codes

    def updateCcpCodes(self):

        codes = self.getCcpCodes(self.molType)

        if self.isotopomer:
            index = codes.index(self.isotopomer.ccpCode)
        else:
            index = 0

        self.ccpCodePulldown.setup(codes, codes, index)

    def setIsotopomerWeight(self, event):

        value = self.isotopomerWeightEntry.get()

        if value is not None:
            self.isotopomer.setWeight(abs(value))

    def getIsotopomerWeight(self, isotopomer):

        if isotopomer:
            self.isotopomerWeightEntry.set(isotopomer.weight)

    def setSchemeName(self, event):

        text = self.schemeNameEntry.get()

        if text:
            text = text.strip() or None
        else:
            text = None

        self.scheme.setLongName(text)

    def getSchemeName(self, scheme):

        if scheme:
            self.schemeNameEntry.set(scheme.longName)

    def getSchemeDetails(self, scheme):

        if scheme:
            self.schemeDetailsEntry.set(scheme.details)

    def setSchemeDetails(self, event):

        text = self.schemeDetailsEntry.get()

        if text:
            text = text.strip() or None
        else:
            text = None

        self.scheme.setDetails(text)

    def updateSchemes(self, obj=None):

        textMatrix = []
        objectList = []

        for labelingScheme in self.project.sortedLabelingSchemes():

            repository = labelingScheme.findFirstActiveRepository()

            if repository:
                saveLocation = repository.name
            else:
                saveLocation = None

            line = [
                labelingScheme.name, labelingScheme.longName,
                labelingScheme.details, saveLocation
            ]

            textMatrix.append(line)
            objectList.append(labelingScheme)

        self.schemeMatrix.update(textMatrix=textMatrix, objectList=objectList)

        self.updateSchemePulldown()
        self.updateIsotopomers()

    def updateSchemePulldown(self):

        scheme = self.scheme
        schemes = self.project.sortedLabelingSchemes()
        names = [ls.longName or ls.name for ls in schemes]

        if names:
            if scheme not in schemes:
                scheme = schemes[0]

            index = schemes.index(scheme)

        else:
            index = 0
            scheme = None

        self.setLabellingScheme(scheme)
        self.schemePulldown.setup(names, schemes, index)

    def copyScheme(self):

        if self.scheme:
            name = askString('Input text', 'New Scheme Code:', '', parent=self)
            scheme = self.project.findFirstLabelingScheme(name=name)
            if scheme:
                showWarning('Failure', 'Scheme name already in use')
                return

            if name:
                newScheme = copySubTree(self.scheme,
                                        self.project,
                                        topObjectParameters={'name': name})

            else:
                showWarning('Failure', 'No name specified')

        else:
            showWarning('Failure', 'No scheme selected to copy')

    def removeScheme(self):

        if self.scheme and isSchemeEditable(self.scheme):
            self.scheme.delete()
            self.scheme = None

    def makeNewScheme(self):

        name = askString('Input text', 'New Scheme Code:', '', parent=self)

        if name:
            scheme = self.project.findFirstLabelingScheme(name=name)
            if scheme:
                showWarning('Failure', 'Scheme name already in use')
            else:
                scheme = self.project.newLabelingScheme(name=name)
                self.scheme = scheme

        else:
            showWarning('Failure', 'No name specified')

    def setLabellingScheme(self, scheme):

        if scheme is not self.scheme:
            self.scheme = scheme
            self.isotopomerV = False
            self.isotopomer = None
            self.updateIsotopomers()

    def selectScheme(self, object, row, col):

        self.setLabellingScheme(object)
        self.updateSchemePulldown()

    def open(self):

        BasePopup.open(self)

        self.updateSchemes()

    def saveSchemes(self):

        schemes = [x for x in self.project.labelingSchemes if x.isModified]

        if schemes:
            for scheme in schemes:
                scheme.save()
            showInfo('Notice', 'Successfully saved %d schemes' % len(schemes))
            self.updateSchemes()

        else:
            showWarning('Notice', 'No modified schemes to save')

    def addNewIsotopomer(self):

        if self.scheme:
            ccpCode = self.ccpCodePulldown.getObject()
            chemCompLabel = self.getChemCompLabel(self.molType, ccpCode)

            self.makeIsotopomer(chemCompLabel)

    def makeIsotopomer(self, chemCompLabel, weight=1.0):

        isotopomer = chemCompLabel.newIsotopomer(weight=weight)

        chemComp = chemCompLabel.chemComp

        for chemAtom in chemComp.chemAtoms:
            if chemAtom.elementSymbol:
                chemElement = chemAtom.chemElement
                for isotope in chemElement.isotopes:
                    code = '%d%s' % (isotope.massNumber,
                                     chemAtom.elementSymbol)
                    weight = self.defaultAbun.get(isotope,
                                                  100.0 * isotope.abundance)
                    isotopomer.newAtomLabel(name=chemAtom.name,
                                            subType=chemAtom.subType,
                                            isotopeCode=code,
                                            weight=weight)

        return isotopomer

    def getChemCompLabel(self, molType, ccpCode):

        chemCompLabel = None
        if self.scheme:
            chemCompLabel = self.scheme.findFirstChemCompLabel(molType=molType,
                                                               ccpCode=ccpCode)
            if not chemCompLabel:
                chemCompLabel = self.scheme.newChemCompLabel(molType=molType,
                                                             ccpCode=ccpCode)
        return chemCompLabel

    def selectIsotopomer(self, obj, row, col):

        self.isotopomer = obj
        self.updateChemElements()
        self.updateAtomLabels()

    def updateIsotopomersAfter(self, obj=None):

        if self.waiting:
            return
        else:
            self.waiting = True
            self.after_idle(self.updateIsotopomers)

    def updateIsotopomers(self):

        self.updateViewCcpCodePulldown()
        self.updateViewIsotopomerPulldown()

        textMatrix = []
        objectList = []

        if self.scheme:
            chemCompLabels = [(label.ccpCode, label)
                              for label in self.scheme.chemCompLabels]
            chemCompLabels.sort()

            for key, chemCompLabel in chemCompLabels:
                if chemCompLabel.molType == self.molType:
                    for isotopomer in chemCompLabel.sortedIsotopomers():

                        line = [
                            chemCompLabel.ccpCode, isotopomer.serial,
                            isotopomer.weight
                        ]

                        textMatrix.append(line)
                        objectList.append(isotopomer)

        self.isotopomerMatrix.update(textMatrix=textMatrix,
                                     objectList=objectList)
        self.updateAtomLabelsAfter()
        self.waiting = False

    def setAtomTypeDefault(self):

        if self.scheme:
            atomName = askString(
                'Query',
                'Specify atom name to set\ndefault abundance for',
                'H',
                parent=self)

            if not atomName:
                return

            atomLabels = []
            for chemCompLabel in self.scheme.chemCompLabels:
                if chemCompLabel.molType == self.molType:
                    for isotopomer in chemCompLabel.isotopomers:
                        # Multiple because of isotopes and subTypes
                        atomLabels += isotopomer.findAllAtomLabels(
                            name=atomName)

            if atomLabels:
                for atomLabel in atomLabels:
                    isotope = atomLabel.isotope
                    weight = self.defaultAbun.get(isotope,
                                                  100.0 * isotope.abundance)
                    atomLabel.weight = weight

            else:
                data = (atomName, self.scheme.name)
                msg = 'Atom name %s does not match any atoms in %s scheme isotopomers' % data
                showWarning('Failure', msg)

    def addDefaultIsotopomers(self):

        if self.scheme:
            codes = self.getCcpCodes(self.molType)

            for ccpCode in codes:
                chemCompLabel = self.getChemCompLabel(self.molType, ccpCode)

                if not chemCompLabel.isotopomers:
                    self.makeIsotopomer(chemCompLabel)

    def removeIsotopomers(self):

        isotopomers = self.isotopomerMatrix.currentObjects

        if isotopomers:
            for isotopomer in isotopomers:
                isotopomer.delete()

            self.isotopomer = None

    def duplicateResidues(self):

        isotopomers = self.isotopomerMatrix.currentObjects

        for isotopomer in isotopomers:
            chemCompLabel = isotopomer.chemCompLabel
            new = copySubTree(isotopomer, chemCompLabel)

    def updateChemElements(self):

        if self.isotopomer:
            chemCompLabel = self.isotopomer.chemCompLabel
            elementDict = {}

            for chemAtom in chemCompLabel.chemComp.chemAtoms:
                symbol = chemAtom.elementSymbol
                if symbol:
                    elementDict[symbol] = True

            names = elementDict.keys()
            names.sort()

        else:
            names = ['C', 'N', 'H']

        if self.element not in names:
            index = 0
        else:
            index = names.index(self.element)

        self.elementPulldown.setup(names, names, index)

    def updateAtomLabelsAfter(self, obj=None):

        if self.waitingAtom:
            return

        else:
            self.waitingAtom = True
            self.after_idle(self.updateAtomLabels)

    def updateAtomLabels(self):

        element = self.elementPulldown.getText()

        textMatrix = []
        objectList = []
        headingList = [
            'Atom Name',
        ]
        tipTexts = [
            'The name of the atom within its residue, for which to set isotopic abundances, within the selected isotopomer',
        ]

        isotopeCodes = [x[0] for x in getSortedIsotopes(self.project, element)]
        headingList.extend(['Weighting\n%s' % x for x in isotopeCodes])
        tip = 'The amount of %s isotope incorporation; can be a ratio, percentage or fraction (the value used is relative to the sum of all weights)'
        tipTexts.extend([tip % x for x in isotopeCodes])

        tip = 'The percentage %s isotope incorporation, calculated using stated weights'
        headingList.extend(['%%%s' % x for x in isotopeCodes])
        tipTexts.extend([tip % x for x in isotopeCodes])

        editWidgets = [
            None,
        ]
        editGetCallbacks = [
            None,
        ]
        editSetCallbacks = [
            None,
        ]
        editWidgets.extend(
            [self.atomLabelTupleWeightEntry for x in isotopeCodes])
        editGetCallbacks.extend(
            [self.getAtomLabelWeight for x in isotopeCodes])
        editSetCallbacks.extend(
            [self.setAtomLabelWeight for x in isotopeCodes])
        editWidgets.extend([None for x in isotopeCodes])
        editGetCallbacks.extend([None for x in isotopeCodes])
        editSetCallbacks.extend([None for x in isotopeCodes])

        doExchangeable = self.exchangeCheck.get()

        if self.isotopomer:

            atomDict = {}
            for atomLabel in self.isotopomer.sortedAtomLabels():
                if atomLabel.chemAtom.elementSymbol == element:
                    if (not doExchangeable) and (
                            atomLabel.chemAtom.waterExchangeable):
                        continue

                    name = atomLabel.name
                    subType = atomLabel.subType
                    atomDict[(name, subType)] = True

            atomNames = atomDict.keys()
            atomNames = greekSortAtomNames(atomNames)

            for atomName, subType in atomNames:

                if subType == 1:
                    name = atomName
                else:
                    name = '%s:%d' % (atomName, subType)

                line = [
                    name,
                ]
                atomLabels = []

                sumWeights = 0.0
                for isotope in isotopeCodes:
                    atomLabel = self.isotopomer.findFirstAtomLabel(
                        name=atomName, subType=subType, isotopeCode=isotope)
                    atomLabels.append(atomLabel)

                    if atomLabel:
                        weight = atomLabel.weight
                        sumWeights += weight
                        line.append(weight)

                    else:
                        line.append(0.0)

                if sumWeights:
                    for atomLabel in atomLabels:
                        line.append(100.0 * atomLabel.weight / sumWeights)

                else:
                    for atomLabel in atomLabels:
                        line.append(None)

                textMatrix.append(line)
                objectList.append(atomLabels)

        self.atomsMatrix.update(textMatrix=textMatrix,
                                objectList=objectList,
                                headingList=headingList,
                                tipTexts=tipTexts,
                                editWidgets=editWidgets,
                                editGetCallbacks=editGetCallbacks,
                                editSetCallbacks=editSetCallbacks)

        self.waitingAtom = False
        self.updateButtons()

    def setAtomLabelWeight(self, event):

        value = self.atomLabelTupleWeightEntry.get()

        if value is not None:
            atomLabels, col = self.atomLabelTuple

            chemAtom = None
            for label in atomLabels:
                if label:
                    chemAtom = label.chemAtom
                    break

            atomLabel = atomLabels[col - 1]

            if chemAtom and (atomLabel is None):
                isotopeCode, isotope = getSortedIsotopes(
                    self.project, chemAtom.elementSymbol)[col - 1]
                atomLabel = self.isotopomer.newAtomLabel(
                    name=chemAtom.name,
                    subType=chemAtom.subType,
                    isotopeCode=isotopeCode,
                    weight=value)
            atomLabel.setWeight(value)

    def setAtomLabelsDefault(self):

        atomLabelTuples = self.atomsMatrix.currentObjects

        for atomLabels in atomLabelTuples:
            for atomLabel in atomLabels:
                isotope = atomLabel.isotope
                weight = self.defaultAbun.get(isotope,
                                              100.0 * isotope.abundance)

                atomLabel.weight = weight

    def propagateAbundances(self):

        atomLabels, col = self.atomLabelTuple
        atomLabelTuples = self.atomsMatrix.currentObjects

        weightDict = {}
        for atomLabel in atomLabels:
            weightDict[atomLabel.isotope] = atomLabel.weight

        for atomLabels0 in atomLabelTuples:
            if atomLabels0 != atomLabels:
                for atomLabel in atomLabels0:
                    atomLabel.weight = weightDict[atomLabel.isotope]

    def getAtomLabelWeight(self, null):

        atomLabels, col = self.atomLabelTuple

        if atomLabels and (col > 0):
            atomLabel = atomLabels[col - 1]

            if atomLabel is None:
                weight = 0.0
            else:
                weight = atomLabel.weight

            self.atomLabelTupleWeightEntry.set(weight)

    def changeChemElement(self, name):

        self.element = name
        self.isotopes = [x[0] for x in getSortedIsotopes(self.project, name)]
        self.updateAtomLabels()

    def destroy(self):

        self.administerNotifiers(self.unregisterNotify)

        BasePopup.destroy(self)
Example #10
0
class EditMeasurementListsPopup(BasePopup):
    """
  **The NMR Derived Measurements and Their Lists**
  
  The purpose of this popup window is to display lists of measurements within
  the current CCPN project. A "Measurement" in this regard is a value that is
  derived from NMR data and connects to one or more resonances (which may be
  assigned to atoms). The most commonly encountered kind of measurement is the
  chemical shift, which is usually derived from recording the positions of peaks
  in spectra. In this instance the chemical shift measurement of a resonance is
  made when it is assigned to the dimension of a peak. Because CCPN allows
  multiple shift lists (technically a type of measurement list) a resonance may
  have a several chemical shift measurements; useful studying different
  conditions. 

  There are several different kinds of measurement and hence measurement list that
  may be included within a CCPN project, for example J-coupling, hydrogen
  exchange rate, chemical shift anisotropy, T1 relaxation and chemical shift.
  All types will be displayed by this popup if they are available within the
  current project, although Analysis does not necessarily have tools to record
  all of these different kinds of measurement.

  The layout of this popup consists of two tabs, one for the organising lists
  that contain the measurements and another to display the individual
  measurements within a single list. With the exception of blank
  lists for chemical shifts, measurement lists are not made using this popup,
  instead they are made at the point where an analysis is performed, e.g. T1
  lists are made with data from the `Follow Intensity Changes`_
  tool. 

  The second tab, containing the "Measurements" table displays the details of
  the individual measured values within a selected list. What the values mean
  and which units they are in, if any, naturally depends on the kind of list
  being viewed. If measurements are made within CCPN software (as opposed to
  being imported) then the individual measurements usually record the spectrum
  peaks that were used in the calculation of the measured value, e.g. the peaks
  for which positions record chemical shift or intensities record T1.

  **Caveats & Tips**

  If there is no chemical shift list within a project a new one will be made
  automatically to record the shifts of any assignments.

  The shift list with which an experiment is associate may be changed via the "Shift
  List" column of the main `Experiments`_ table.

  Measurements other than chemical shift, like T1 and T2 relaxation times will only
  appear within this system if a measurement list entity is formally made. Simply
  measuring values from spectra, for example using the `Follow Intensity Changes`_
  tool

  .. _`Follow Intensity Changes`: CalcRatesPopup.html
  .. _`Experiments`: EditExperimentPopup.html
  
  """
    def __init__(self, parent, *args, **kw):

        self.guiParent = parent
        self.experiment = None
        self.measurementList = None
        self.measurementListB = None
        self.measurement = None
        self.waitingList = False
        self.waitingMeasurement = False

        BasePopup.__init__(self,
                           parent,
                           title="Resonance : Measurement Lists",
                           **kw)

    def body(self, guiFrame):

        self.geometry('600x600')

        guiFrame.expandGrid(0, 0)

        tipTexts = [
            'A table of all the NMR measurement lists in the project, including shift lists, T1 lists, J-coupling lists etc.',
            'A table listing all of the individual measurements within an NMR measurement list'
        ]
        options = ['Measurement Lists', 'Measurements Table']
        tabbedFrame = TabbedFrame(guiFrame,
                                  options=options,
                                  grid=(0, 0),
                                  tipTexts=tipTexts)
        self.tabbedFrame = tabbedFrame
        frameA, frameB = tabbedFrame.frames

        # Measurement Lists

        frameA.expandGrid(1, 0)
        self.detailsEntry = Entry(self,
                                  text='',
                                  returnCallback=self.setDetails,
                                  width=12)
        self.nameEntry = Entry(self,
                               text='',
                               returnCallback=self.setName,
                               width=12)

        row = 0
        frame0 = Frame(frameA, grid=(row, 0), gridSpan=(1, 2))
        frame0.grid_columnconfigure(2, weight=1)

        label = Label(frame0, text='Experiment:', grid=(0, 0), sticky='e')

        tipText = 'Selects an experiment, if required, to restrict the measurement list table display; showing only lists which were derived using the experiment'
        self.experimentPulldown = PulldownList(frame0,
                                               callback=self.setExperiment,
                                               grid=(0, 1),
                                               tipText=tipText)

        row += 1
        tipTexts = [
            'The serial number of measurement list',
            'The type of measurement list, e.g. shift list, T1 list, J coupling list',
            'A short identifying name for the list, for graphical displays',
            'The number of measurements contained within the list',
            'The unit of measurement used for the values in the list',
            'The names of the experiments which were used to derive the measurements',
            'A user-specified textual comment for the measurement list'
        ]
        justifyList = [
            'center', 'center', 'center', 'center', 'center', 'left'
        ]
        #colHeadings      = ['List Type','Name','Size','Unit','Experiments','Other Info','Details']
        colHeadings = [
            '#', 'List Type', 'Name', 'Size', 'Unit', 'Experiments', 'Details'
        ]
        editWidgets = [
            None, None, self.nameEntry, None, None, None, None,
            self.detailsEntry
        ]
        editGetCallbacks = [
            None, None, self.getName, None, None, None, None, self.getDetails
        ]
        editSetCallbacks = [
            None, None, self.setName, None, None, None, None, self.setDetails
        ]

        self.listsMatrix = ScrolledMatrix(
            frameA,
            grid=(row, 0),
            gridSpan=(1, 2),
            justifyList=justifyList,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            editWidgets=editWidgets,
            headingList=colHeadings,
            callback=self.selectListCell,
            deleteFunc=self.deleteMeasurementList,
            tipTexts=tipTexts)

        row += 1
        tipTexts = [
            'Show a table of the individual measurements within the selected measurement list',
            'Make a new, blank chemical shift list within the project',
            'Make a synthetic chemical shift list using random coil values, adjusting protein backbone values for sequence where approprate',
            'Delete the selected measurement list'
        ]
        texts = [
            'Show Measurements', 'New Shift List',
            'Make Random Coil Shift List', 'Delete'
        ]
        commands = [
            self.showMeasurements, self.addShiftList,
            self.makeRandomCoilShiftList, self.deleteMeasurementList
        ]
        self.listButtons = ButtonList(frameA,
                                      texts=texts,
                                      commands=commands,
                                      grid=(row, 0),
                                      gridSpan=(1, 2),
                                      tipTexts=tipTexts)

        # Measurements

        self.measurementDetailsEntry = Entry(
            self, text='', returnCallback=self.setMeasurementDetails, width=12)
        self.measurementMeritEntry = FloatEntry(
            self, returnCallback=self.setMeasurementMerit, width=6)

        row = 0
        frame0 = Frame(frameB, grid=(row, 0))
        frame0.grid_columnconfigure(2, weight=1)

        label = Label(frame0,
                      text='Measurement List:',
                      grid=(0, 0),
                      sticky='e')

        tipText = 'Selects the measurement list to display measurements for'
        self.listPulldown = PulldownList(frame0,
                                         callback=self.setMeasurementList,
                                         grid=(0, 1),
                                         tipText=tipText)

        row += 1
        frameB.expandGrid(row, 0)
        tipTexts = [
            'The serial number of the measurement within its containing list',
            'The number or assignment of the NMR resonance(s) to which the measurement applies',
            'The numeric value of the NMR measurement on the specified resonance(s), and the unit of measurement',
            'The standard deviation error in the measured value',
            'The molecular chain, if any, to which the measurement relates by virtue of atom assigned resonances',
            'The isotope type(s) of the measures resonance(s)',
            'A figure-of-merit value for the measurement indicating its quality or reliability',
            'The number of peaks in the CCPN project used to take the measurement',
            'A user-defined textual comment for the measurement'
        ]
        justifyList = [
            'center', 'center', 'center', 'center', 'center', 'center',
            'center', 'center', 'center', 'left'
        ]
        colHeadings = [
            '#', 'Resonance', 'Value', 'SD', 'Chain', 'Isotope',
            'Fig of\nMerit', 'Peaks', 'Details'
        ]
        editWidgets = [
            None, None, None, None, None, None, self.measurementMeritEntry,
            None, self.measurementDetailsEntry
        ]
        editGetCallbacks = [
            None, None, None, None, None, None, self.getMeasurementMerit,
            self.showPeaks, self.getMeasurementDetails
        ]
        editSetCallbacks = [
            None, None, None, None, None, None, self.setMeasurementMerit, None,
            self.setMeasurementDetails
        ]

        self.measurementsMatrix = ScrolledMatrix(
            frameB,
            grid=(row, 0),
            multiSelect=True,
            tipTexts=tipTexts,
            justifyList=justifyList,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            editWidgets=editWidgets,
            headingList=colHeadings,
            callback=self.selectMeasurementCell)

        row += 1
        tipTexts = [
            'Show a table containing peaks that were used to derive the selected measurements',
            'For some measurement lists (currently only shift lists) manually trigger a recalculation of values',
            'Show a table containing the resonances that relate to the selected measurements',
            'Delete the selected measurement records; cannot be done for chemical shift values still ties to peaks via assignment'
        ]
        texts = ['Show Peaks', 'Recalculate', 'Show Resonances', 'Delete']
        commands = [
            self.showPeaks, self.recalculateMeasurements, self.showResonances,
            self.deleteMeasurements
        ]
        self.measurementButtons = ButtonList(frameB,
                                             texts=texts,
                                             grid=(row, 0),
                                             commands=commands,
                                             tipTexts=tipTexts)

        # Main Frame

        self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame,
                                               helpUrl=self.help_url,
                                               grid=(0, 0),
                                               gridSpan=(1, 2),
                                               sticky='e')

        self.updateMeasurementListAfter()
        self.updateMeasurementsAfter()

        self.administerNotifiers(self.registerNotify)

    def administerNotifiers(self, notifyFunc):

        for func in ('__init__', 'delete', 'setName', 'setDipolarRelaxList',
                     'setHExchProtectionList', 'setHExchRateList',
                     'setNoeList', 'setJCouplingList', 'setRdcList',
                     'setShiftAnisotropyList', 'setShiftDifferenceList',
                     'setShiftList', 'setT1List', 'setT1RhoList', 'setT2List'):
            for clazz in ('ccp.nmr.Nmr.Experiment', ):
                notifyFunc(self.updateExperiments, clazz, func)

        for func in ('__init__', 'delete', 'setDetails', 'setName',
                     'addExperiment', 'removeExperiment', 'setExperiments'):
            for clazz in ('ccp.nmr.Nmr.DipolarRelaxList',
                          'ccp.nmr.Nmr.HExchProtectionList',
                          'ccp.nmr.Nmr.HExchRateList', 'ccp.nmr.Nmr.NoeList',
                          'ccp.nmr.Nmr.JCouplingList', 'ccp.nmr.Nmr.RdcList',
                          'ccp.nmr.Nmr.ShiftAnisotropyList',
                          'ccp.nmr.Nmr.ShiftDifferenceList',
                          'ccp.nmr.Nmr.ShiftList', 'ccp.nmr.Nmr.T1List',
                          'ccp.nmr.Nmr.T1RhoList', 'ccp.nmr.Nmr.T2List'):
                notifyFunc(self.updateMeasurementListAfter, clazz, func)

        # Measurements

        for func in ('__init__', 'delete'):
            for clazz in ('ccp.nmr.Nmr.DipolarRelaxation',
                          'ccp.nmr.Nmr.HExchProtection',
                          'ccp.nmr.Nmr.HExchRate', 'ccp.nmr.Nmr.Noe',
                          'ccp.nmr.Nmr.JCoupling', 'ccp.nmr.Nmr.Rdc',
                          'ccp.nmr.Nmr.Shift', 'ccp.nmr.Nmr.ShiftAnisotropy',
                          'ccp.nmr.Nmr.ShiftDifference', 'ccp.nmr.Nmr.T1',
                          'ccp.nmr.Nmr.T1Rho', 'ccp.nmr.Nmr.T2'):
                notifyFunc(self.updateMeasurementAfter, clazz, func)

        for func in ('__init__', 'delete', 'setDetails', 'setError',
                     'setFigOfMerit', 'setValue', 'setPeaks', 'addPeak',
                     'removePeak'):
            for clazz in ('ccp.nmr.Nmr.DipolarRelaxation',
                          'ccp.nmr.Nmr.HExchProtection',
                          'ccp.nmr.Nmr.HExchRate', 'ccp.nmr.Nmr.Noe',
                          'ccp.nmr.Nmr.JCoupling', 'ccp.nmr.Nmr.Rdc',
                          'ccp.nmr.Nmr.Shift', 'ccp.nmr.Nmr.ShiftAnisotropy',
                          'ccp.nmr.Nmr.ShiftDifference', 'ccp.nmr.Nmr.T1',
                          'ccp.nmr.Nmr.T1Rho', 'ccp.nmr.Nmr.T2'):
                self.registerNotify(self.updateMeasurementAfter, clazz, func)

    def open(self):

        self.updateMeasurementListAfter()
        self.updateMeasurementsAfter()
        BasePopup.open(self)

    def makeRandomCoilShiftList(self):

        molSystems = self.project.molSystems
        shiftList = makeRandomCoilShiftList(molSystems)

    def addShiftList(self):

        shiftList = newShiftList(self.project)
        self.setExperiment(None)

    def getName(self, measurementList):

        if measurementList:
            self.nameEntry.set(measurementList.name)

    def setName(self, event):

        text = self.nameEntry.get()
        if text and text != ' ':
            self.measurementList.setName(text)

    def getDetails(self, measurementList):

        if measurementList and measurementList.details:
            self.detailsEntry.set(measurementList.details)

    def setDetails(self, event):

        text = self.detailsEntry.get()
        if text and text != ' ':
            self.measurementList.setDetails(text)

    def setExperiment(self, experiment):

        if experiment is not self.experiment:
            self.experiment = experiment
            self.measurementList = None
            self.updateMeasurementListAfter()

    def deleteMeasurementList(self, *event):

        if self.measurementList:

            if (len(self.measurementList.experiments) >
                    0) and (self.measurementList.className == 'ShiftList'):
                showWarning(
                    'Warning',
                    'Deletion of shift lists with associated experiments prohibited',
                    parent=self)
                return
            elif len(self.measurementList.measurements) > 0:
                if showOkCancel('Confirm',
                                'List is not empty. Really delete?',
                                parent=self):
                    self.measurementList.delete()
                    self.measurementList = None
                else:
                    return

            else:
                self.measurementList.delete()
                self.measurementList = None

    def showMeasurements(self):

        self.updateMeasurements(self.measurementList)
        self.tabbedFrame.select(1)

    def selectListCell(self, object, row, col):

        self.measurementList = object
        if self.measurementList:
            self.listButtons.buttons[0].enable()
            self.listButtons.buttons[3].enable()
            self.setMeasurementList(self.measurementList)

    def updateMeasurementAfter(self, measurement):

        if (self.experiment is None) or (
                self.experiment in measurement.parentList.experiments):
            self.updateMeasurementListAfter()

        if measurement.parentList is self.measurementListB:
            self.updateMeasurementsAfter()

    def updateMeasurementListAfter(self, measurementList=None):

        self.updateListPulldown()

        if self.waitingList:
            return

        if (measurementList is None) \
         or (self.experiment is None) \
         or (self.experiment in measurementList.experiments):
            self.waitingList = True
            self.after_idle(self.updateListsTable)

    def updateExperiments(self, null=None):

        index = 0
        experiments = [
            None,
        ] + self.nmrProject.sortedExperiments()
        names = [
            '<Any>',
        ] + [e.name for e in experiments[1:]]
        experiment = self.experiment

        if experiments:
            if experiment not in experiments:
                experiment = experiments[0]

            index = experiments.index(experiment)

        else:
            experiment = None

        if self.experiment is not experiment:
            self.experiment = experiment
            self.updateMeasurementListAfter()

        self.experimentPulldown.setup(names, experiments, index)

    def updateListsTable(self, experiment=None):

        if experiment is None:
            experiment = self.experiment
        else:
            self.experiment = experiment

        if self.experiment is None:
            self.measureList = None

        self.updateExperiments()

        if self.measurementList:
            self.listButtons.buttons[0].enable()
            self.listButtons.buttons[3].enable()
        else:
            self.listButtons.buttons[0].disable()
            self.listButtons.buttons[3].disable()

        if self.experiment == None:
            measurementLists = self.nmrProject.sortedMeasurementLists()
        else:
            measurementLists = []
            lists = self.nmrProject.sortedMeasurementLists()
            for measurementList in lists:
                if self.experiment in measurementList.experiments:
                    measurementLists.append(measurementList)

        objectList = []
        textMatrix = []
        for measurementList in measurementLists:
            objectList.append(measurementList)
            names = ['%s' % (e.name) for e in measurementList.experiments]
            if len(names) > 6:
                names.insert(int(len(names) / 2), '\n')
            experimentText = ' '.join(names)
            """otherInfoText  = ''
      for attribute in measurementList.metaclass.getAllAttributes():
        name = attribute.name
        otherInfoText += '%s:%s ' % (name,getattr(measurementList, name))

      for role in measurementList.metaclass.getAllRoles():
        name = role.name
        otherInfoText += '%s:%s ' % (name,getattr(measurementList, name))"""

            datum = [
                measurementList.serial,
                measurementList.className,
                measurementList.name,
                len(measurementList.measurements),
                measurementList.unit,
                experimentText,
                #otherInfoText,
                measurementList.details
            ]

            textMatrix.append(datum)

        if not objectList:
            textMatrix.append([])
        self.listsMatrix.update(objectList=objectList, textMatrix=textMatrix)

        self.waitingList = False

    def destroy(self):

        self.administerNotifiers(self.unregisterNotify)

        BasePopup.destroy(self)

    # Measurement functions

    def deleteMeasurements(self):

        measurements = self.measurementsMatrix.currentObjects
        if measurements:

            className = self.measurementListB.className
            if className == 'ShiftList':
                msg = 'Really delete %s chemical shifts?' % len(measurements)
                if not showOkCancel('Confirm', msg, parent=self):
                    return

                untouched = set()

                for shift in measurements:
                    for peakDim in shift.peakDims:
                        shiftList = peakDim.peak.peakList.dataSource.experiment.shiftList
                        if shiftList is self.measurementListB:
                            untouched.add(shift)
                            break
                    else:
                        shift.delete()

                if untouched:
                    if len(untouched) > 1:
                        msg = 'Could not delete %d shifts because they are still assigned to peaks' % len(
                            untouched)

                    else:
                        msg = 'Could not delete shift because it is still assigned to peaks'

                    showWarning('Warning', msg, parent=self)

            else:
                msg = 'Really delete %d %s measurements?' % (len(measurements),
                                                             className[:-4])
                if not showOkCancel('Confirm', msg, parent=self):
                    return

                for measurement in measurements:
                    measurement.delete()

    def recalculateMeasurements(self):

        measurements = self.measurementsMatrix.currentObjects
        if measurements and (self.measurementListB.className == 'ShiftList'):
            for shift in measurements:
                averageShiftValue(shift)

    def showPeaks(self, *event):

        measurements = self.measurementsMatrix.currentObjects
        if measurements:
            peaksDict = {}
            for measurement in measurements:
                for peak in measurement.peaks:
                    peaksDict[peak] = 1

            peaks = peaksDict.keys()
            if len(peaks) > 0:
                self.guiParent.viewPeaks(peaks)

    def showResonances(self, *event):

        measurements = self.measurementsMatrix.currentObjects
        if measurements:
            resonances = set()

            for measurement in measurements:
                if hasattr(measurement, 'resonances'):
                    resonances.update(measurement.resonances)
                else:
                    resonances.add(measurement.resonance)

            if resonances:
                self.guiParent.viewSelectedResonances(resonances)

    def setMeasurementList(self, measurementList):

        if measurementList is not self.measurementListB:
            self.measurementListB = measurementList
            self.updateMeasurementsAfter()

    def getMeasurementMerit(self, measurement):

        if measurement:
            self.measurementMeritEntry.set(measurement.figOfMerit)

    def setMeasurementMerit(self, event):

        value = self.measurementMeritEntry.get()
        if value is not None:
            self.measurement.setFigOfMerit(max(0.0, min(1.0, float(value))))

    def getMeasurementDetails(self, measurement):

        if measurement and measurement.details:
            self.measurementDetailsEntry.set(measurement.details)

    def setMeasurementDetails(self, event):

        text = self.measurementDetailsEntry.get()
        if text and text != ' ':
            self.measurement.setDetails(text)

    def selectMeasurementCell(self, object, row, col):

        self.measurement = object
        if self.measurement:
            self.measurementButtons.buttons[0].enable()
            self.measurementButtons.buttons[2].enable()
            if self.measurementListB.className == 'ShiftList':
                self.measurementButtons.buttons[1].enable()
            else:
                self.measurementButtons.buttons[1].disable()

    def getMeasurementListName(self, measurementList):

        name = measurementList.name or \
               '%d:%s' % (measurementList.serial,measurementList.className)

        return name

    def updateListPulldown(self, null=None):

        index = 0
        measurementLists = self.nmrProject.sortedMeasurementLists()
        nameFunc = self.getMeasurementListName
        names = [nameFunc(ml) for ml in measurementLists]
        measurementList = self.measurementListB

        if measurementLists:
            if measurementList not in measurementLists:
                measurementList = measurementLists[0]

            index = measurementLists.index(measurementList)

        else:
            measurementList = None

        if self.measurementListB is not measurementList:
            self.measurementListB = measurementList
            self.updateMeasurementsAfter()

        self.listPulldown.setup(names, measurementLists, index)

    def updateMeasurementsAfter(self, *opt):

        if self.waitingMeasurement:
            return
        else:
            self.waitingMeasurement = True
            self.after_idle(self.updateMeasurements)

    def updateMeasurements(self, measurementList=None):

        headingList = [
            '#', 'Resonance', 'Value', 'SD', 'Chain', 'Isotope',
            'Fig of\nMerit', 'Peaks', 'Details'
        ]

        if measurementList is not None:
            self.measurementListB = measurementList
            self.updateListPulldown()

        if self.measurementListB is None:
            self.measurement = None
            measurements = []
        else:
            if self.measurementListB.unit:
                headingList[2] = 'Value\n(%s)' % (self.measurementListB.unit)
            measurements = self.measurementListB.sortedMeasurements()
            if measurements and hasattr(measurements[0], 'resonances'):
                headingList[1] = 'Resonances'
                headingList[5] = 'Isotopes'

        if self.measurement:
            self.measurementButtons.buttons[0].enable()
            self.measurementButtons.buttons[2].enable()
            if self.measurementListB.className == 'ShiftList':
                self.measurementButtons.buttons[1].enable()
            else:
                self.measurementButtons.buttons[1].disable()
        else:
            self.measurementButtons.buttons[0].disable()
            self.measurementButtons.buttons[1].disable()
            self.measurementButtons.buttons[2].disable()

        objectList = []
        textMatrix = []
        i = 0
        for measurement in measurements:
            i += 1
            resonanceText = ''
            isotopeText = ''
            chainText = ''
            if hasattr(measurement, 'resonances'):
                resonanceText = ' '.join(
                    [makeResonanceGuiName(r) for r in measurement.resonances])
                isotopeText = ' '.join(
                    [r.isotopeCode for r in measurement.resonances])
                residueDict = {}
                for resonance in measurement.resonances:
                    if resonance.resonanceSet:
                        residue = resonance.resonanceSet.findFirstAtomSet(
                        ).findFirstAtom().residue
                        residueDict[residue] = None

                keys = residueDict.keys()
                if len(keys) == 1:
                    residue = keys[0]
                    residueNum = residue.seqCode
                    chainText = '%s:%s' % (residue.chain.molSystem.code,
                                           residue.chain.code)

            elif hasattr(measurement, 'resonance'):
                resonance = measurement.resonance
                resonanceText = makeResonanceGuiName(resonance)
                isotopeText = measurement.resonance.isotopeCode
                if resonance.resonanceSet:
                    residue = resonance.resonanceSet.findFirstAtomSet(
                    ).findFirstAtom().residue
                    chainText = '%s:%s' % (residue.chain.molSystem.code,
                                           residue.chain.code)

            datum = [
                i, resonanceText, measurement.value, measurement.error,
                chainText, isotopeText, measurement.figOfMerit,
                len(measurement.peaks), measurement.details or ' '
            ]

            objectList.append(measurement)
            textMatrix.append(datum)

        if not objectList:
            textMatrix.append([])

        tipTexts = self.measurementsMatrix.tipTexts  # unchanged, despite variable headings

        self.measurementsMatrix.update(headingList=headingList,
                                       objectList=objectList,
                                       textMatrix=textMatrix,
                                       tipTexts=tipTexts)

        self.waitingMeasurement = False
Example #11
0
class OpenSpectrumPopup(BasePopup):
    r"""
  **Locate Spectrum Data for Use in CCPN Project**
  
  This popup window enables the user to locate spectrum data within a file
  system and associate the files (typically binary) with an experiment and
  spectrum name so that it may be visualised and accessed within the current
  CCPN project. Spectra of many different origins and file formats may be
  loaded, which currently includes Bruker, Varian, Felix, NMRPipe, NmrView,
  SPARKY/UCSF, Azara and the factorised shape format "USF3". Depending upon the
  file format of the spectrum, data loaded the user may be required to either
  select a parameter file which then refers to the actual spectrum intensity
  data; this is true for Bruker "procs" and AZARA ".par" files, or alternatively
  a spectrum data file itself that contains referencing information; this is
  the case for SPARKY/UCSF, NmrView and NMRPipe spectra.

  The layout of the popup involved two sections; the upper of which is for
  navigating to and selecting the spectrum or parameter files within the
  file-system, and the lower is for specifying how each spectrum is loaded into
  the CCPN project. It should be noted that when spectrum parameters are read
  the first time, the relevant information is copied into the CCPN project,
  where it may be adjusted independently of the original file information. No
  copies of the spectrum intensity data are made, the CCPN project merely refers
  to the spectrum data on disk, although the data file for a loaded spectrum may
  subsequently be moved or replaced.

  In normal operation the user first selects the kind of spectrum file format
  that will be loaded via the upper "File format" pulldown menu and then checks
  that the "File type" pulldown (toward the bottom of the file browser) is set
  to detect the appropriate kinds of filename; if a helpful file name filter is
  not available the user can add one via the "Manual Select" field, taking care
  to add any wild-card symbols, like the asterisk in "\*.ft3". Next the spectrum
  data or parameter files, appropriate to the selected format, are located by
  navigating within the file-system browser. When the required spectrum files are
  visible the user selects one *or more* to load. Multiple file selections may
  be made using left-click with <Ctrl> (toggle selection) or <Shift> (select
  range). It should be noted that when selecting Bruker files, when using the
  standard Bruker directory structure, the user only needs to navigate to the
  numbered spectrum directory; by default the "procs" file two levels down is
  searched for, e.g. "123/pdata/1/procs" is shown in the directory containing
  the "123" directory.

  When spectrum or parameter files are selected in the file table, the lower
  "Spectra To Open" table is filled to reflect the selection. The user should
  then be mindful of the settings within this table and may choose to edit
  various things by double-clicking on the appropriate cell. Typically the user
  just adjusts the name of the independent "Experiment" and "Spectrum" records.
  These names are usually concatenated like "expName:specName" in CCPN graphical
  displays so there is no need to repeat a name in both fields; this only takes
  up more space. The Experiment, which is a record of *what was done
  experimentally*, commonly has a short name like "HNCA" or "HSQC_298K" so the
  user readily knows how to interpret the experimental data. The Spectrum, which
  is a record of *the data that was collected*, commonly has a short name to
  identify the spectrum number or file name. An Experiment record may contain
  several Spectrum records, so the spectrum's name need minimally only identify
  it amongst others from the same experiment. The Shift List value may be
  changed if the user knows that the experiment represents a distinct set of
  conditions, with different spectrum peak/resonance positions, to existing or
  other experiments being entered. Each shift list will be curated separately,
  to give separate chemical shift values for assignments made under different
  conditions (even when relating to the same atoms). The shift list that an
  experiment uses may also be changed at any time after loading.

  When all spectra and options are specified the [Open Spectrum] button will
  load the relevant data into the CCPN project. If the "Skip verification
  dialogs" option is set it is assumed that all of the spectrum point to
  frequency referencing information, and any data file references, are correct.
  Otherwise, the user will be prompted to confirm the file details and
  referencing information for each spectrum in turn. Finally, after loading the
  user is asked to set the type of NMR experiment, in terms of general
  magnetisation transfer pathway, that was performed.

  **Caveats & Tips**

  If the name of an Experiment that is *already within the CCPN project* is
  used, then the loaded spectrum will (assuming it is compatible) be entered
  under that existing experiment record; no new experiment entity will be
  defined. The user may legitimately use this feature to load several spectra
  that relate to the same experiment; typically where spectra are different
  projections. To facilitate this the "Use shared experiment" option can be
  selected.

  Although experiments and spectra may be renamed after loading, a spectrum
  record may not be placed under a different experiment once created; deletion
  and re-loading is the only mans of achieving this, and care must be taken in
  transferring any assignments.

  """
    def __init__(self, parent, *args, **kw):

        self.experiment = None
        self.currentObject = None
        #self.currentObjects = [] # looks obsolete

        BasePopup.__init__(self,
                           parent=parent,
                           title='Experiment : Open Spectra',
                           **kw)

    def open(self):

        self.message()
        BasePopup.open(self)

    def body(self, guiFrame):

        self.fileSelect = None
        names, objects = self.getShiftLists()
        self.shiftListPulldown = PulldownList(self,
                                              callback=self.setShiftList,
                                              texts=names,
                                              objects=objects)
        self.windowPulldown = PulldownList(self,
                                           texts=WINDOW_OPTS,
                                           callback=self.setWindow)
        self.experimentEntry = Entry(self,
                                     width=16,
                                     returnCallback=self.setExperiment)
        self.spectrumEntry = Entry(self,
                                   width=16,
                                   returnCallback=self.setSpectrum)

        guiFrame.grid_columnconfigure(0, weight=1)
        guiFrame.grid_rowconfigure(0, weight=1)
        guiFrame.grid_rowconfigure(1, weight=1)

        leftFrame = LabelFrame(guiFrame, text='File Selection')
        leftFrame.grid(row=0, column=0, sticky='nsew')
        leftFrame.grid_columnconfigure(3, weight=1)

        row = 0

        label = Label(leftFrame, text='File format:')
        label.grid(row=row, column=0, sticky='w')
        tipText = 'Selects which kind of spectrum file is being loaded; what its data matrix format is'
        self.formatPulldown = PulldownList(leftFrame,
                                           callback=self.chooseFormat,
                                           texts=file_formats,
                                           tipText=tipText,
                                           grid=(row, 1))

        self.detailsLabel = Label(leftFrame, text='Show details:')
        tipText = 'Whether to show an annotation that describes the spectrum in the file selection; currently only uses comment fields from Bruker spectra'
        self.detailsSelect = CheckButton(leftFrame,
                                         selected=False,
                                         callback=self.showDetails,
                                         tipText=tipText)
        self.titleRow = row
        self.detailsSelected = False

        row = row + 1
        leftFrame.grid_rowconfigure(row, weight=1)
        file_types = [FileType('All', ['*'])]
        self.fileSelect = FileSelect(leftFrame,
                                     multiSelect=True,
                                     file_types=file_types,
                                     single_callback=self.chooseFiles,
                                     extraHeadings=('Details', ),
                                     extraJustifies=('left', ),
                                     displayExtra=False,
                                     getExtraCell=self.getDetails,
                                     manualFileFilter=True)
        self.fileSelect.grid(row=row, column=0, columnspan=6, sticky='nsew')

        rightFrame = LabelFrame(guiFrame, text='Spectra To Open')
        rightFrame.grid(row=1, column=0, sticky='nsew')
        rightFrame.grid_columnconfigure(3, weight=1)

        row = 0
        label = Label(rightFrame,
                      text='Skip verification dialogs:',
                      grid=(row, 0))
        tipText = 'Whether to allow the user to check file interpretation and referencing information before the spectrum is loaded'
        self.verifySelect = CheckButton(rightFrame,
                                        selected=False,
                                        grid=(row, 1),
                                        tipText=tipText)

        label = Label(rightFrame, text='Use shared experiment:', grid=(row, 2))
        tipText = 'When selecting multiple spectrum files, whether the loaded spectra will all belong to (derive from) the same experiment; useful for projection spectra etc.'
        self.sharedExpSelect = CheckButton(rightFrame,
                                           selected=False,
                                           tipText=tipText,
                                           callback=self.useShared,
                                           grid=(row, 3))

        row = row + 1
        rightFrame.grid_rowconfigure(row, weight=1)
        tipTexts = [
            'A short textual name for the experiment record that the loaded spectrum will belong to; may be a new experiment or the name of an existing one',
            'A short textual name to identify the spectrum within its experiment; typically a few characters or spectrum number, rather than a repeat of the experiment name',
            'The location of the file, relative to the current directory, that the spectrum data will be loaded from',
            'Sets which window or windows the spectrum will initially appear within once loaded',
            'Sets which shift list the experiment (and hence loaded spectrum) will use to curate chemical shift information; can be changed after load time'
        ]
        headingList = [
            'Experiment', 'Spectrum', 'File', 'Windows', 'Shift List'
        ]
        editWidgets = [
            self.experimentEntry, self.spectrumEntry, None,
            self.windowPulldown, self.shiftListPulldown
        ]
        editGetCallbacks = [
            self.getExperiment, self.getSpectrum, None, self.getWindow,
            self.getShiftList
        ]
        editSetCallbacks = [
            self.setExperiment, self.setSpectrum, None, self.setWindow,
            self.setShiftList
        ]
        self.scrolledMatrix = ScrolledMatrix(rightFrame,
                                             headingList=headingList,
                                             callback=self.selectCell,
                                             editWidgets=editWidgets,
                                             multiSelect=True,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks,
                                             tipTexts=tipTexts,
                                             grid=(row, 0),
                                             gridSpan=(1, 4))

        row = row + 1
        tipTexts = [
            'Load spectrum or spectra into the CCPN project using the selected file(s)',
        ]
        texts = ['Open Spectrum']
        commands = [self.openSpectra]
        bottomButtons = UtilityButtonList(guiFrame,
                                          texts=texts,
                                          tipTexts=tipTexts,
                                          doClone=False,
                                          commands=commands,
                                          helpUrl=self.help_url)
        bottomButtons.grid(row=row, column=0, columnspan=1, sticky='ew')
        self.openButton = bottomButtons.buttons[0]

        self.chooseFormat('Azara')
        self.message()

    def message(self):

        if not self.project or len(self.nmrProject.experiments) < 1:
            pass
            #self.parent.ticker.setMessage('Choose spectrum files to open....     ')

    def showDetails(self, isSelected):

        self.detailsSelected = isSelected
        self.fileSelect.updateDisplayExtra(isSelected)
        # below is so that when Details column is toggled on it will actually
        # be seen without having to use the scrollbar
        self.fileSelect.fileList.refreshSize()

    def useShared(self, isSelected):

        self.chooseFiles(forceUpdate=True)

        #if isSelected:

        #objects = self.scrolledMatrix.objectList
        #if len(objects) > 1:
        #  self.currentObject = objects[0]
        #  text = objects[0][0]
        #  self.chooseFiles()
        #  for oo in objects[1:]:
        #    oo[0] = text
        #  if self.project:
        #    self.experiment = self.nmrProject.findFirstExperiment(name=text)
        #self.update()

    def gridDetails(self, bool):

        if bool:
            self.detailsLabel.grid(row=self.titleRow, column=2, sticky='w')
            self.detailsSelect.grid(row=self.titleRow, column=3, sticky='w')
            self.fileSelect.updateDisplayExtra(self.detailsSelected)
        else:
            self.detailsLabel.grid_forget()
            self.detailsSelect.grid_forget()
            self.fileSelect.updateDisplayExtra(False)

    def openSpectra(self):

        noVerify = self.verifySelect.getSelected()

        # tracks if 'add to existing experiment' has already ben OK'ed
        self.okExpSet = set()

        directory = self.fileSelect.getDirectory()
        spectra = []
        specIndex = 0
        for obj in self.scrolledMatrix.objectList:
            fileName = uniIo.joinPath(directory, obj.fileName)
            spectrum = self.openSpectrum(obj.exptName, obj.specName, fileName,
                                         obj.window, obj.shiftListName)
            specIndex += 1

            if (spectrum):
                # check endianness if we are not verifying
                spectra.append(spectrum)
                if noVerify:
                    isBigEndian = isSpectrumBigEndian(
                        spectrum)  # according to data in file
                    if isBigEndian is not None:
                        isBigEndianCurr = getIsSpectrumBigEndian(
                            spectrum)  # according to data model
                        setIsSpectrumBigEndian(spectrum, isBigEndian)
                        if isBigEndian != isBigEndianCurr:
                            if isBigEndian:
                                s = 'big'
                            else:
                                s = 'little'
                            print 'WARNING: swapped endianess of spectrum to %s endian' % s
        #
        del self.okExpSet

        if noVerify and len(spectra) > 1 and self.sharedExpSelect.getSelected(
        ):
            # if we are using a shared experiment and not verifying,
            # set referencing to match first spectrum for all

            # get reference spectrum and set up data structure
            # use most recent pre-existing spectrum, otherwise first new one
            refSpec = spectra[0]
            for spec in spectra[0].experiment.sortedDataSources():
                if spec in spectra:
                    break
                else:
                    refSpec = spec

            ddrLists = {}
            refDdrs = []
            for dataDim in refSpec.sortedDataDims():
                for ddr in dataDim.dataDimRefs:
                    ddrLists[ddr.expDimRef] = []
                    refDdrs.append(ddr)

            # get dataDimRefs, store by ExpDimRef,
            # checking that all spectra have data dim refs for same set of xdr
            nTotal = len(ddrLists)
            for spec in spectra:
                nFound = 0
                for dataDim in spec.sortedDataDims():
                    for ddr in dataDim.dataDimRefs:
                        xdr = ddr.expDimRef
                        ll = ddrLists.get(xdr)
                        if ll is None:
                            # something did not match - do nothing
                            break
                        else:
                            ll.append(ddr)
                            nFound += 1
                else:
                    if nFound == nTotal:
                        # we are OK. Do next spectrum
                        continue
                # something did not match - do nothing
                break
            else:

                # all spectra matched. Now reset O1 references to match reference
                if refSpec is spectra[0]:
                    startAt = 1
                else:
                    startAt = 0

                for refDdr in refDdrs:
                    dataDim = refDdr.dataDim
                    centrePoint = dataDim.numPointsOrig / 2 - dataDim.pointOffset + 1
                    refValue = refDdr.pointToValue(centrePoint)

                    xdr = refDdr.expDimRef
                    for ddr in ddrLists[xdr][startAt:]:
                        dataDim = ddr.dataDim
                        centrePoint = dataDim.numPointsOrig / 2 - dataDim.pointOffset + 1
                        ddr.refPoint = centrePoint
                        ddr.refValue = refValue

        # set refExperiment if there is only one possibility
        experiments = []
        ignoreSet = set()
        showPopup = False
        for spectrum in spectra:
            experiment = spectrum.experiment
            if experiment not in ignoreSet:
                ignoreSet.add(experiment)
                if not experiment.refExperiment:
                    experiments.append(spectrum.experiment)
                    if noVerify:
                        resetCategory = False
                        if not hasattr(experiment, 'category'):
                            if (hasattr(experiment, 'pulProgName')
                                    and hasattr(experiment, 'pulProgType')):
                                # this is first time we get here, and we have external name and source
                                # use external source to set fullType
                                experiment.category = 'use external'
                                resetCategory = True
                        refExperiments = getRefExperiments(experiment)
                        if resetCategory and not refExperiments:
                            # no refExperiments match external source.
                            # unset 'use external' category
                            del experiment.category

                        if len(refExperiments) == 1:
                            # only one possibility, just set it
                            setRefExperiment(experiment, refExperiments[0])

                        # wb104: 20 Oct 2014: do not popup Experiment types dialog if noVerify
                        #else:
                        #  showPopup = True

        # Pop up refExperiment verification
        if experiments and (showPopup or not noVerify):
            self.parent.initRefExperiments(experiments)

        # set up internal Analysis data
        for spectrum in spectra:
            self.parent.finishInitSpectrum(spectrum)
            print 'finished opening spectrum', spectrum.experiment.name, spectrum.name

    def chooseFiles(self, forceUpdate=False, *file):

        directory = self.fileSelect.getDirectory()

        fileNames = self.fileSelect.fileList.currentObjects
        fullFileNames1 = [uniIo.joinPath(directory, x) for x in fileNames]

        fullFileNames2 = [x.fileName for x in self.scrolledMatrix.objectList]
        fullFileNames2 = [uniIo.joinPath(directory, x) for x in fullFileNames2]

        if fullFileNames1 == fullFileNames2 and not forceUpdate:
            return

        objectList = []
        textMatrix = []

        format = self.formatPulldown.getText()

        shiftListName = self.getShiftLists()[0][0]
        windowOpt = WINDOW_OPTS[1]
        oneUp = os.path.dirname

        if format == 'Bruker':
            if self.sharedExpSelect.getSelected():
                nameTemplate = 'Bruker_%d'
                next = self.getNextExpNum(nfiles=len(fileNames),
                                          nameTemplate=nameTemplate)

                exptName = nameTemplate % (next)
                for i, fileName in enumerate(fileNames):
                    fullFileName = fullFileNames1[i]
                    specName = os.path.basename(
                        oneUp(oneUp(oneUp(fullFileName))))
                    datum = (exptName, specName, fileName, windowOpt,
                             shiftListName)
                    dataObj = RowObject(*datum)
                    textMatrix.append(datum)
                    objectList.append(dataObj)

            else:
                for i, fileName in enumerate(fileNames):
                    fullFileName = fullFileNames1[i]
                    try:  # below should not fail
                        ss1 = oneUp(fullFileName)
                        specName = os.path.basename(ss1)
                        ss2 = os.path.basename(oneUp(oneUp(ss1)))
                        exptName = 'Bruker_' + ss2
                    except:  # just put in something
                        ss = os.path.basename(fullFileName)
                        exptName = 'Bruker_' + ss
                        specName = ss

                    datum = (exptName, specName, fileName, windowOpt,
                             shiftListName)
                    dataObj = RowObject(*datum)
                    textMatrix.append(datum)
                    objectList.append(dataObj)

        else:
            next = self.getNextExpNum(nfiles=len(fileNames))
            if self.sharedExpSelect.getSelected():
                exptName = 'Expt_%d' % (next)
                for i, fileName in enumerate(fileNames):
                    specName = re.sub('\.\w+$', '', fileName)

                    datum = (exptName, specName, fileName, windowOpt,
                             shiftListName)
                    dataObj = RowObject(*datum)
                    textMatrix.append(datum)
                    objectList.append(dataObj)

            else:
                for i, fileName in enumerate(fileNames):
                    exptName = 'Expt_%d' % (next + i)
                    specName = re.sub('\.\w+$', '', fileName)

                    datum = (exptName, specName, fileName, windowOpt,
                             shiftListName)
                    dataObj = RowObject(*datum)
                    textMatrix.append(datum)
                    objectList.append(dataObj)

        if len(fileNames) > 1:
            self.openButton.config(text='Open Spectra')

        else:
            self.openButton.config(text='Open Spectrum')

        self.scrolledMatrix.update(objectList=objectList,
                                   textMatrix=textMatrix)

    def getNextExpNum(self, nfiles=0, nameTemplate='Expt_%d'):
        """ get suitable free integer to use for exp names 
    """
        next = 1
        if self.project:
            nmrProject = self.nmrProject
            ii = len(nmrProject.experiments)

            # find first exp number that is not taken
            # NBNB TBD could consider expname = specname, specname = proc dir
            next = ii + 1
            if nfiles:
                while ii < next + nfiles:
                    ii += 1
                    if nmrProject.findFirstExperiment(name=nameTemplate % ii):
                        next = ii + 1
        #
        return next

    def getDetails(self, fullfile):

        details = ''
        if os.path.isfile(fullfile):
            format = self.formatPulldown.getText()
            detailsDir = os.path.dirname(fullfile)
            detailsFile = uniIo.joinPath(detailsDir, details_file_dict[format])
            if os.path.exists(detailsFile):
                fp = open(detailsFile)
                details = fp.read().strip().replace('\n',
                                                    ' ').replace('\r', ' ')
                fp.close()

        return (details, )

    def update(self):

        objectList = self.scrolledMatrix.objectList
        textMatrix = [(obj.exptName, obj.specName, obj.fileName, obj.window,
                       obj.shiftListName) for obj in objectList]

        self.scrolledMatrix.update(objectList=objectList,
                                   textMatrix=textMatrix)

    def selectCell(self, obj, row, col):

        self.currentObject = obj

        if self.project:
            self.experiment = self.nmrProject.findFirstExperiment(
                name=obj.exptName)
        else:
            self.experiment = None

    def getWindow(self, obj):

        if obj:
            self.windowPulldown.set(obj.window)

    def setWindow(self, opt):

        if isinstance(opt, RowObject):
            self.currentObject.window = opt.window
        else:
            self.currentObject.window = opt
        self.update()

    def setShiftList(self, obj=None):

        if self.project:
            project = self.project
            shiftList = self.shiftListPulldown.getObject()
            if shiftList is None:
                shiftList = newShiftList(project, unit='ppm')

            if self.experiment and shiftList and (
                    shiftList is not self.experiment.shiftList):
                setExperimentShiftList(self.experiment, shiftList)

            self.currentObject.shiftListName = shiftList.name

        self.update()

    def getShiftList(self, object):

        names, shiftLists = self.getShiftLists()
        if names:
            self.shiftListPulldown.setup(names, shiftLists, 0)
            if self.experiment and self.experiment.shiftList:
                name = self.experiment.shiftList.name
            else:
                name = object.shiftListName

            if name is not None:
                self.shiftListPulldown.set(name)

    def getShiftLists(self):

        if self.project:
            names = []
            objects = getShiftLists(self.nmrProject)
            for shiftList in objects:
                if not shiftList.name:
                    shiftList.name = 'ShiftList %d' % shiftList.serial
                names.append(shiftList.name)

            objects.append(None)
            names.append('<New>')

        else:
            objects = [
                None,
            ]
            names = [
                'ShiftList 1',
            ]

        return names, objects

    def chooseFormat(self, format):

        if format in ('Bruker', 'Varian'):
            self.gridDetails(True)
        else:
            self.gridDetails(False)

        file_types = []
        file_type = file_type_dict.get(format)
        if (file_type):
            file_types.extend([file_type])
        file_types.append(FileType('All', ['*']))
        file_types.append(self.fileSelect.manualFilter)
        self.fileSelect.setFileTypes(file_types)

    def getSpectrum(self, obj):

        if obj:
            self.spectrumEntry.set(obj.specName)

    def setSpectrum(self, *event):

        if self.currentObject:
            text = self.spectrumEntry.get()
            if text and text != ' ':
                for data in self.scrolledMatrix.objectList:
                    if data is self.currentObject:
                        continue
                    if (data.specName
                            == text) and (data.exptName
                                          == self.currentObject.exptName):
                        showWarning(
                            'Repeated name',
                            'Spectrum name (%s) already in use for experiment (%s)'
                            % (data.specName, data.exptName),
                            parent=self)
                        return
                    elif (self.experiment) and (
                            self.experiment.findFirstDataSource(name=text)):
                        showWarning(
                            'Repeated name',
                            'Spectrum name (%s) already in use for experiment (%s)'
                            % (data.specName, data.exptName),
                            parent=self)
                        return

                self.currentObject.specName = text
            self.update()

    def getExperiment(self, obj):

        if obj:
            self.experimentEntry.set(obj.exptName)

    def setExperiment(self, *event):

        if self.currentObject:
            text = self.experimentEntry.get()
            if text and text != ' ':
                if self.sharedExpSelect.getSelected():
                    # share one experiment for all rows
                    for oo in self.scrolledMatrix.objectList:
                        oo.exptName = text
                else:
                    #separate experiments
                    self.currentObject.exptName = text
                if self.project:
                    self.experiment = self.nmrProject.findFirstExperiment(
                        name=text)
            self.update()

    def updateShiftLists(self):

        if self.project:
            name = self.expt_entry.get()
            e = self.nmrProject.findFirstExperiment(name=name)

        else:
            e = None

        names, objects = self.getShiftLists()
        if e and e.shiftList:
            index = objects.index(e.shiftList)
        else:
            index = 0

        self.shiftListPulldown.setup(names, objects, index)

    def openSpectrum(self,
                     exptName,
                     specName,
                     file,
                     windowOpt=WINDOW_OPTS[2],
                     shiftListName='<New>',
                     extraData=None):

        # input checks
        if not file:
            showError('No file', 'Need to enter file', parent=self)
            return None

        if not exptName:
            showError('Experiment',
                      'Need to enter experiment name',
                      parent=self)
            return None

        if not specName:
            showError('Spectrum', 'Need to enter spectrum name', parent=self)
            return None

        # get or set up project
        project = self.project
        if not project:
            self.project = project = defaultProject()
            self.parent.initProject(project)
            self.nmrProject = self.parent.nmrProject
            self.analysisProject = self.parent.analysisProject
            #Default ShiftList with name 'ShiftList 1' created

        # set up shift list
        if shiftListName == '<New>':
            shiftList = None
        else:
            shiftList = self.nmrProject.findFirstMeasurementList(
                className='ShiftList', name=shiftListName)

        # read params

        format = self.formatPulldown.getText()
        clazz = params_class_dict[format]
        try:
            params = clazz(file, extraData=extraData)
        except Implementation.ApiError, e:
            showError('Reading params file',
                      'Fatal error: ' + e.error_msg,
                      parent=self)
            return None

        dim = params.pseudoDataDim()
        if dim is not None:
            if format == 'NMRPipe':
                popup = NmrPipePseudoPopup(self, params, dim, file)
                popup.destroy()
            elif format == 'Bruker':
                popup = BrukerPseudoPopup(self, params, dim)
                popup.destroy()

        # get or set up experiment

        experiment = self.nmrProject.findFirstExperiment(name=exptName)
        if experiment:
            expIsNew = False
            if experiment.findFirstDataSource(name=specName):
                showError('Duplicate name',
                          'Duplicate spectrum name "%s" in experiment %s' %
                          (specName, experiment.name),
                          parent=self)
                return None
            elif (experiment.dataSources and experiment not in self.okExpSet):
                if showOkCancel('Multiple Spectra Warning',
                                'Really put multiple '
                                'spectra into existing experiment %s?' %
                                experiment.name,
                                parent=self):
                    self.okExpSet.add(experiment)
                else:
                    return

        else:
            expIsNew = True
            try:
                # Will also work for shiftList == None
                experiment = Nmr.Experiment(self.nmrProject,
                                            name=exptName,
                                            numDim=params.ndim,
                                            shiftList=shiftList)

            except Implementation.ApiError, experiment:
                showError('Experiment', experiment.error_msg, parent=self)
                return None
Example #12
0
class CingFrame(NmrCalcRunFrame):
    def __init__(self, parent, application, *args, **kw):

        project = application.project
        self.nmrProject = nmrProject = application.nmrProject

        if project:
            calcStore = project.findFirstNmrCalcStore(name=APP_NAME, nmrProject=nmrProject) or \
                        project.newNmrCalcStore(name=APP_NAME, nmrProject=nmrProject)
        else:
            calcStore = None

        self.application = application
        self.residue = None
        self.structure = None
        self.serverCredentials = None
        self.iCingBaseUrl = DEFAULT_URL
        self.resultsUrl = None
        self.chain = None
        self.serverDone = False

        NmrCalcRunFrame.__init__(self, parent, project, calcStore, *args, **kw)

        # # # # # # New Structure Frame # # # # #

        self.structureTable.grid_forget()
        self.structureButtons.grid_forget()
        self.ensemblePulldown.grid_forget()
        self.modelButtons.grid_forget()
        self.modelPulldown.grid_forget()

        frame = self.inputTabs.frames[0]
        frame.grid_rowconfigure(0, weight=0)
        frame.grid_rowconfigure(1, weight=1)

        label = Label(frame, text='Ensemble: ', grid=(0, 0))
        self.structurePulldown = PulldownList(
            frame,
            callback=self.changeStructure,
            grid=(0, 1),
            tipText='The structure ensemble coordinates to submit')

        tipTexts = [
            'Conformational model number', 'Whether analyse this model'
        ]
        headingList = ['Model', 'Use']
        editWidgets = [None, None]
        editGetCallbacks = [None, self.toggleModel]
        editSetCallbacks = [
            None,
            None,
        ]
        self.modelTable = ScrolledMatrix(frame,
                                         grid=(1, 0),
                                         gridSpan=(1, 2),
                                         callback=self.selectStructModel,
                                         multiSelect=True,
                                         tipTexts=tipTexts,
                                         editWidgets=editWidgets,
                                         initialRows=2,
                                         editGetCallbacks=editGetCallbacks,
                                         editSetCallbacks=editSetCallbacks,
                                         headingList=headingList)

        tipTexts = [
            'Activate the selected models so that they will be consedered in the analysis',
            'Deactivate the selected models so that they will not be considered in the analysis'
        ]
        texts = ['Activate Selected', 'Inactivate Selected']
        commands = [self.activateModels, self.disableModels]
        buttons = ButtonList(frame,
                             texts=texts,
                             commands=commands,
                             grid=(2, 0),
                             gridSpan=(1, 2),
                             tipTexts=tipTexts)

        # # # # # # 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))
        self.iCingBaseUrlPulldown = PulldownList(
            frame,
            texts=URLS,
            objects=URLS,
            index=0,
            grid=(srow, 1),
            tipText='Web location of iCING server to use')

        srow += 1
        label = Label(frame, text='Results File:', grid=(srow, 0))
        self.resultFileEntry = Entry(
            frame,
            bd=1,
            text='',
            grid=(srow, 1),
            width=50,
            tipText='Name of file to store compressed CING results in')
        self.setZipFileName()
        button = Button(frame,
                        text='Choose File',
                        bd=1,
                        sticky='ew',
                        command=self.chooseZipFile,
                        grid=(srow, 2),
                        tipText='Select file to overwrite with CING results')

        srow += 1
        label = Label(frame, text='Results URL:', grid=(srow, 0))
        self.resultUrlEntry = Entry(
            frame,
            bd=1,
            text='',
            grid=(srow, 1),
            width=50,
            tipText='Web location where CING results will be posted')
        button = Button(frame,
                        text='View Results HTML',
                        bd=1,
                        sticky='ew',
                        command=self.viewHtmlResults,
                        grid=(srow, 2),
                        tipText='Open the HTML CING results in a web browser')

        srow += 1
        tipTexts = [
            'Submit the CCPN project to the CING server',
            'Determin whether the iCING job is complete, pending or has failed',
            'Remove all trace of the last submissionfrom the iCING server',
            'Download the compressed CING results, including HTML'
        ]
        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),
                                    tipTexts=tipTexts)

        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,
            tipText='Select the molecular system chain to consider')
        self.chainPulldown.grid(row=0, column=1, sticky='w')

        headingList = ['#', 'Residue', 'Linking', 'Decriptor', 'Use?']
        tipTexts = [
            'Sequence number', 'Residue type code',
            'In-chain connectivity of residue',
            'Protonation and steriochemical state',
            'Whether to consider the residue in the analysis'
        ]
        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,
                                            tipTexts=tipTexts,
                                            editWidgets=editWidgets,
                                            editGetCallbacks=editGetCallbacks,
                                            editSetCallbacks=editSetCallbacks,
                                            callback=self.selectResidue)
        self.residueMatrix.grid(row=1, column=0, columnspan=2, sticky='nsew')

        tipTexts = [
            'Use the selected residues in the analysis',
            'Do not use the selected residues in the analysis'
        ]
        texts = ['Activate Selected', 'Inactivate Selected']
        commands = [self.activateResidues, self.deactivateResidues]
        self.resButtons = ButtonList(frame,
                                     texts=texts,
                                     commands=commands,
                                     tipTexts=tipTexts)
        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(calcStore)

        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/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

        structureData = self.getStructureData()
        if not structureData:
            msg = 'No structure ensemble selected'
            showWarning('Failure', msg, parent=self)
            return

        if not structureData.models:
            msg = 'No structural models selected from ensemble'
            showWarning('Failure', msg, parent=self)
            return

        residueData = self.getResidueData()
        if not (residueData and residueData.residues):
            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.run.status = 'pending'

        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.run.status = 'failed'
            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
            self.run.status = 'failed'
            return

        result = status.get(iCingRobot.RESPONSE_RESULT)
        if result == iCingRobot.RESPONSE_DONE:
            self.serverDone = True
            self.run.status = 'completed'
            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):

        if self.project:
            zipFile = '%s_CING_report.zip' % self.project.name
            self.resultFileEntry.set(zipFile)
        else:
            self.resultFileEntry.set('CING_report.zip')

    def selectStructModel(self, model, row, col):

        self.model = model

    def selectResidue(self, residue, row, col):

        self.residue = residue

    def getResidueData(self):

        chain = self.chain.chain
        chainCode = chain.code
        msCode = chain.molSystem.code
        dataObj = self.run.findFirstData(className=RESIDUE_DATA,
                                         ioRole='input',
                                         molSystemCode=msCode,
                                         chainCode=chainCode,
                                         name=APP_NAME)

        if not dataObj:
            dataObj = self.run.newMolResidueData(molSystemCode=msCode,
                                                 chainCode=chainCode,
                                                 ioRole='input',
                                                 name=APP_NAME)

            # if not dataObj.residueSeqIds:
            seqIds = [r.seqId for r in self.chain.sortedResidues()]
            dataObj.residueSeqIds = seqIds

        return dataObj

    def getStructureData(self):

        eId = self.structure.ensembleId
        msCode = self.structure.molSystem.code
        dataObj = self.run.findFirstData(className=STRUCTURE_DATA,
                                         molSystemCode=msCode,
                                         ensembleId=eId,
                                         ioRole='input',
                                         name=APP_NAME)

        if not dataObj:
            dataObj = self.run.newStructureEnsembleData(ioRole='input',
                                                        molSystemCode=msCode,
                                                        ensembleId=eId,
                                                        name=APP_NAME)

            # if not dataObj.modelSerials:
            serials = [m.serial for m in self.structure.sortedModels()]
            dataObj.modelSerials = serials

        for dataObjB in self.run.findAllData(className=STRUCTURE_DATA,
                                             name=APP_NAME,
                                             ioRole='input'):
            if dataObjB is not dataObj:
                dataObjB.delete()

        return dataObj

    def deactivateResidues(self):

        if self.run and self.chain:
            dataObj = self.getResidueData()
            seqIds = set(dataObj.residueSeqIds)

            for residue in self.residueMatrix.currentObjects:
                seqId = residue.seqId

                if seqId in seqIds:
                    seqIds.remove(seqId)

            seqIds = list(seqIds)
            seqIds.sort()

            dataObj.residueSeqIds = seqIds

            self.updateResidues()

    def activateResidues(self):

        if self.run and self.chain:
            for residue in self.residueMatrix.currentObjects:
                dataObj = self.getResidueData()
                seqIds = set(dataObj.residueSeqIds)

                for residue in self.residueMatrix.currentObjects:
                    seqId = residue.seqId

                    if seqId not in seqIds:
                        seqIds.add(seqId)

                seqIds = list(seqIds)
                seqIds.sort()

                dataObj.residueSeqIds = seqIds

            self.updateResidues()

    def activateModels(self):

        if self.run and self.structure:
            dataObj = self.getStructureData()
            serials = set(dataObj.modelSerials)

            for model in self.modelTable.currentObjects:
                serial = model.serial

                if serial not in serials:
                    serials.add(serial)

            serials = list(serials)
            serials.sort()

            dataObj.modelSerials = serials

            self.updateModels()

    def disableModels(self):

        if self.run and self.structure:
            dataObj = self.getStructureData()
            serials = set(dataObj.modelSerials)

            for model in self.modelTable.currentObjects:
                serial = model.serial

                if serial in serials:
                    serials.remove(serial)

            serials = list(serials)
            serials.sort()

            dataObj.modelSerials = serials

            self.updateModels()

    def toggleModel(self, *opt):

        if self.model and self.run and self.structure:
            dataObj = self.getStructureData()
            serials = set(dataObj.modelSerials)

            serial = self.model.serial

            if serial in serials:
                serials.remove(serial)
            else:
                serials.add(serial)

            serials = list(serials)
            serials.sort()

            dataObj.modelSerials = serials

            self.updateModels()

    def toggleResidue(self, *opt):

        if self.residue and self.run:
            dataObj = self.getResidueData()
            seqIds = set(dataObj.residueSeqIds)
            seqId = self.residue.seqId

            if seqId in seqIds:
                seqIds.remove(seqId)
            else:
                seqIds.add(seqId)

            seqIds = list(seqIds)
            seqIds.sort()
            dataObj.residueSeqIds = seqIds

            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:
            resDataObj = self.getResidueData()
            selectedRes = set(resDataObj.residues)
            chainCode = self.chain.code

            for residue in self.chain.sortedResidues():
                msResidue = residue.residue

                if msResidue in selectedRes:
                    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:
            structures0 = [(s.ensembleId, s)
                           for s in self.project.structureEnsembles]
            structures0.sort()

            for eId, structure0 in structures0:
                name = '%s:%s' % (structure0.molSystem.code, eId)
                structures.append(structure0)
                names.append(name)

        if structures:
            if structure not in structures:
                structure = structures[-1]

            index = structures.index(structure)

        if self.structure is not structure:
            self.changeStructure(structure)

        self.structurePulldown.setup(names, structures, index)

    def updateModels(self, obj=None):

        textMatrix = []
        objectList = []
        colorMatrix = []

        if self.structure and self.run:
            strucDataObj = self.getStructureData()
            selectedSerials = set(strucDataObj.modelSerials)

            for model in self.structure.sortedModels():

                if model.serial in selectedSerials:
                    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:
                dataObj = self.getStructureData()
                serials = set(dataObj.modelSerials)
                serials2 = set([m.serial for m in structure.models])
                serials = list(serials & serials2)
                serials.sort()

                dataObj.modelSerials = serials
                dataObj.ensembleId = structure.ensembleId
                dataObj.molSystemCode = structure.molSystem.code

                # Could clean up residue data if required
                # prob OK to have haning around in case structure
                # changes back

                #for dataObj in self.run.findAllData(className=RESIDUE_DATA,
                #                                    ioRole='input',
                #                                    molSystemCode=msCode,
                #                                    name=APP_NAME)
                #  dataObj.delete()

            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 = nmrProject = project.currentNmrProject
            calcStore = project.findFirstNmrCalcStore(name='CING', nmrProject=nmrProject) or \
                        project.newNmrCalcStore(name='CING', nmrProject=nmrProject)
        else:
            calcStore = 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(calcStore)

    def update(self, calcStore=None):

        NmrCalcRunFrame.update(self, calcStore)

        run = self.run
        urls = URLS
        index = 0

        if run:
            userId = getRunTextParameter(run, iCingRobot.FORM_USER_ID)
            accessKey = getRunTextParameter(run, iCingRobot.FORM_ACCESS_KEY)
            if userId and accessKey:
                self.serverCredentials = [(iCingRobot.FORM_USER_ID, userId),
                                          (iCingRobot.FORM_ACCESS_KEY,
                                           accessKey)]

            url = getRunTextParameter(run, ICING_BASE_URL)
            if url:
                htmlUrl = getRunTextParameter(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 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()
Example #14
0
class EntryScale(Frame):
    def __init__(self,
                 parent,
                 values,
                 initial_index=0,
                 orient=Tkinter.HORIZONTAL,
                 scale_length=200,
                 entry_width=5,
                 entry_format='%2.1f',
                 set_callback=None,
                 *args,
                 **kw):

        assert len(values) > 0

        self.entry_format = entry_format
        self.values = tuple(values)
        self.set_callback = set_callback

        apply(Frame.__init__, (self, parent) + args, kw)

        if (orient == Tkinter.HORIZONTAL):
            self.grid_columnconfigure(1, weight=1)
            sticky = Tkinter.EW
            row = 0
            col = 1
        else:
            self.grid_rowconfigure(1, weight=1)
            sticky = Tkinter.NS
            row = 1
            col = 0

        self.entry = Entry(self, width=entry_width)
        self.entry.grid(row=0, column=0, sticky=sticky)
        self.entry.bind('<KeyPress>', self.keyPress)

        self.scale = Tkinter.Scale(self,
                                   orient=orient,
                                   length=scale_length,
                                   from_=0,
                                   to=len(values) - 1,
                                   label='',
                                   showvalue=0,
                                   command=self.setCallback)
        self.scale.grid(row=row, column=col, sticky=sticky)

        self.set(initial_index)

    def get(self):

        return self.scale.get()

    def getValue(self):

        return self.values[self.get()]

    def set(self, index):

        assert index >= 0 and index < len(
            self.values), 'index = %s, len(self.values) = %s' % (
                index, len(self.values))

        self.scale.set(index)
        self.setEntry()

    def setEntry(self):

        index = self.get()
        text = self.entry_format % self.values[index]
        self.entry.set(text)

    def setCallback(self, ignore):

        self.setEntry()
        if (self.set_callback):
            self.set_callback(self.get())

    def keyPress(self, event):

        if (event.keysym == 'Return'):

            text = self.entry.get()

            try:
                value = text.atof()
            except:
                return

            min_index = 0
            min_diff = abs(self.values[0] - value)

            for i in range(1, len(self.values)):

                diff = abs(self.values[i] - value)

                if (diff < min_diff):
                    min_index = i
                    min_diff = diff

            self.set(min_index)
Example #15
0
class AriaRunFrame(NmrCalcRunFrame):

  def __init__(self, parent, project, calcStore, *args, **kw):

    NmrCalcRunFrame.__init__(self, parent, project, calcStore,
                             inputTypes=(PEAK_DATA, CONSTRAINT_DATA),
                             chainSelection=True, *args, **kw)
    
    self.calcStore = calcStore
    self.optPeakList = None
    self.optConstraintList = None
        
    frame = self.tabbedFrame.frames[1]
    
    headingList = ['PeakList','Filter\nViolated?',
                   'Keep\nAssignments?','Shift List']
                   
    editWidgets      = [None, None, None, None]
    editGetCallbacks = [None, self.toggleFilterViol,
                        self.toggleKeepAssign, None]
    editSetCallbacks = [None, None, None, None]
                        
    row = 0
    subFrame = Frame(frame, grid=(row,0))
    subFrame.expandGrid(0,1)

    label = Label(subFrame, text='File Name Prefix:', grid=(0,0))
    self.filePrefixEntry = Entry(subFrame, text='aria', grid=(0,1), sticky="ew")
    self.filePrefixEntry.bind('<Leave>', self.updateEntryParams)
    
    label = Label(subFrame, text='CNS Executable:', grid=(1,0))
    self.cnsExeEntry = Entry(subFrame, text='', grid=(1,1), sticky="ew")
    self.cnsExeEntry.bind('<Leave>', self.updateEntryParams)
    button = Button(subFrame, text='Select File',bd=1,bg='#C0E0FF',
                    command=self.selectCnsExe, grid=(1,2))
    
    label = Label(subFrame, text='Working Directory:', grid=(2,0))
    self.workingDirEntry = Entry(subFrame, text='', grid=(2,1), sticky="ew")
    self.workingDirEntry.bind('<Leave>', self.updateEntryParams)
    button = Button(subFrame, text='Select File',bd=1,bg='#C0E0FF',
                    command=self.selectWorkingDir, grid=(2,2))
    
    label = Label(subFrame, text='Temporary Directory:', grid=(3,0))
    self.tempDirEntry = Entry(subFrame, text='', grid=(3,1), sticky="ew")
    self.tempDirEntry.bind('<Leave>', self.updateEntryParams)
    button = Button(subFrame, text='Select File',bd=1,bg='#C0E0FF',
                    command=self.selectTempDir, grid=(3,2))

    row += 1
    frame.expandGrid(row,0)
    self.grid_rowconfigure(row, weight=1)
    self.optPeakListMatrix = ScrolledMatrix(frame, headingList=headingList,
                                         editSetCallbacks=editSetCallbacks,
                                         editGetCallbacks=editGetCallbacks, 
                                         editWidgets=editWidgets,
                                         multiSelect=True, grid=(row,0),
                                         callback=self.selectOptPeakList)

    row += 1
    frame.expandGrid(row,0)
    headingList = ['Constraint List',
                   'Name',
                   'Filter\nViolated?',
                   'Ambiguous\nProtocol?',]
                   
    editWidgets      = [None, None, None, None]
    editGetCallbacks = [None, None, self.toggleFilterViol, self.toggleAmbig]
    editSetCallbacks = [None, None, None, None]
                        
    self.optConstraintMatrix = ScrolledMatrix(frame, headingList=headingList,
                                               editSetCallbacks=editSetCallbacks,
                                               editGetCallbacks=editGetCallbacks,
                                               editWidgets=editWidgets,
                                               multiSelect=True, grid=(row,0),
                                               callback=self.selectConstraintList)

    self.optConstraintMatrix.doEditMarkExtraRules = self.doEditMarkExtraRules

    self.update(calcStore)

  def update(self, calcStore=None):
  
    NmrCalcRunFrame.update(self, calcStore)
    self.updateSettings()
     
    # Need to run NmrCalcRunFrame.update before
    # this to get new self.run, self.project 
    if self.run:
      repository = self.project.findFirstRepository(name='userData')
      defaultDir = repository.url.path
    
      filePrefix = getRunTextParameter(self.run, FILE_PREFIX) or self.project.name
      cnsExe = getRunTextParameter(self.run, CNS_EXE) or '/usr/bin/cns'
      workingDir = getRunTextParameter(self.run, WORKING_DIR) or defaultDir
      tempDir = getRunTextParameter(self.run, TEMP_DIR) or defaultDir

      self.filePrefixEntry.set(filePrefix)
      self.cnsExeEntry.set(cnsExe)
      self.workingDirEntry.set(workingDir)
      self.tempDirEntry.set(tempDir)

      self.updateEntryParams()

  def updateEntryParams(self, event=None):
  
    if self.run:
      repository = self.project.findFirstRepository(name='userData')
      defaultDir = repository.url.path
 
      filePrefix = self.filePrefixEntry.get() or self.project.name
      cnsExe = self.cnsExeEntry.get() or '/usr/bin/cns'
      workingDir = self.workingDirEntry.get() or defaultDir
      tempDir = self.tempDirEntry.get() or defaultDir
 
      setRunParameter(self.run, FILE_PREFIX, filePrefix)
      setRunParameter(self.run, CNS_EXE, cnsExe)
      setRunParameter(self.run, WORKING_DIR, workingDir)
      setRunParameter(self.run, TEMP_DIR, tempDir)

  def selectCnsExe(self):
    
    fileTypes = [ FileType("All", ["*"]), FileType("EXE", ["*.exe"]) ]

    popup = FileSelectPopup(self, fileTypes)

    file = popup.getFile()

    if file:
      self.cnsExeEntry.set( file )
    
    popup.destroy()
    self.updateEntryParams()
    
  def selectWorkingDir(self):
    
    popup = FileSelectPopup(self, show_file=False)

    directory = popup.getDirectory()
    if directory:
      self.workingDirEntry.set( directory )
    
    popup.destroy()
    self.updateEntryParams()

  def selectTempDir(self):
    
    popup = FileSelectPopup(self, show_file=False)

    directory = popup.getDirectory()
    if directory:
      self.tempDirEntry.set( directory )
    
    popup.destroy()
    self.updateEntryParams()
    
  def getPeakLists(self):
    # overwrites superclass
    
    return getThroughSpacePeakLists(self.project)

  def administerNotifiers(self, notifyFunc):

    NmrCalcRunFrame.administerNotifiers(self, notifyFunc)
     
    for func in ('__init__','delete','setName'):
      #notifyFunc(self.updateSettings, 'ccp.nmr.NmrConstraint.AbstractConstraintList', func)
      notifyFunc(self.updateSettings, 'ccp.nmr.NmrConstraint.DistanceConstraintList', func)
      notifyFunc(self.updateSettings, 'ccp.nmr.NmrConstraint.DihedralConstraintList', func)
      notifyFunc(self.updateSettings, 'ccp.nmr.NmrConstraint.HBondConstraintList', func)
        
  def selectOptPeakList(self, obj, row, col):
  
    self.optPeakList = obj

  def selectConstraintList(self, obj, row, col):
  
    self.optConstraintList = obj
 
  def doEditMarkExtraRules(self, obj, row, col):
  
    if col in (2,3):
      cSet = obj.nmrConstraintStore
      if cSet:
        for cList in obj.constraintLists:
          if cList.className[:-14] != 'Distance':
            # i.e. ambig protocols and viol filtering
            # is only for dist constraints, not dihedral etc
            return False
                 
    return True
  
  def toggleUseInCalc(self, dataObj):

    toggleObjBooleanParameter(dataObj, USE_IN_CALC)

    self.updateSettings()

  def toggleFilterViol(self, dataObj):

    toggleObjBooleanParameter(dataObj, FILTER_VIOL)

    self.updateSettings()
    
  def toggleKeepAssign(self, dataObj):
  
    toggleObjBooleanParameter(dataObj, KEEP_ASSIGN)

    self.updateSettings()
  
  def toggleAmbig(self, dataObj):
    
    toggleObjBooleanParameter(dataObj, AMBIG_PROTOCOL)

    self.updateSettings()
  
  def updateSettings(self, obj=None):


    textMatrix = []
    objectList = []
    
    run = self.run
    if run:      
      peakListsData = []
      constraintData = []
      molSystemData = None
      
      for dataObj in run.sortedInputs():
        className = dataObj.className
      
        if className == 'PeakListData':
          peakList = dataObj.peakList
          if peakList:
            peakListsData.append((dataObj, peakList))
        
        elif className == 'MolSystemData':
          molSystem = dataObj.molSystem
          if molSystem:
            molSystemData = (dataObj, molSystem)
          
        elif className == 'ConstraintStoreData':
          nmrConstraintStore = dataObj.nmrConstraintStore
          if nmrConstraintStore:
            constraintLists = dataObj.constraintLists or \
                              nmrConstraintStore.sortedConstraintLists()
            
            # Chould be only one
            for constraintList in constraintLists:
              if constraintList is None:
                # Prob happens when serial no longer exists
                continue
              constraintData.append((dataObj, constraintList))
            
      
      for dataObj, peakList in peakListsData:

        spectrum   = peakList.dataSource
        experiment = spectrum.experiment

        filterViol = getObjBooleanParameter(dataObj, FILTER_VIOL)
        keepAssign = getObjBooleanParameter(dataObj, KEEP_ASSIGN)
  
        shiftList  = peakList.dataSource.experiment.shiftList
        if shiftList:
          shiftListName = '%d:%s' % (shiftList.serial,shiftList.name)
        else:
          shiftListName = None
 
        ident = '%s:%s:%d' % (experiment.name,spectrum.name,peakList.serial)
 
        textMatrix.append([ident,
                           filterViol and 'Yes' or 'No',
                           keepAssign and 'Yes' or 'No',
                           shiftListName])
        objectList.append(dataObj)
 
      self.optPeakListMatrix.update(textMatrix=textMatrix,objectList=objectList)
 
      textMatrix = []
      objectList = [] 
      
      for dataObj, constraintList in constraintData:
       
        #useInCalc = getObjBooleanParameter(dataObj, USE_IN_CALC)
        cSet = dataObj.constraintStoreSerial
        cType = constraintList.className[:-14]

        if cType == 'Distance':
        
          filterViol = getObjBooleanParameter(dataObj, FILTER_VIOL)
          ambigProtocol = getObjBooleanParameter(dataObj, AMBIG_PROTOCOL)

          ambigProtocol = ambigProtocol and 'Yes' or 'No'
          filterViol = filterViol and 'Yes' or 'No'

        else:
          ambigProtocol = None
          filterViol = None
 
        ident = '%s - %d:%d' % (cType, cSet, constraintList.serial)

        textMatrix.append([ident,
                          constraintList.name,
                          filterViol,
                          ambigProtocol])
 
        objectList.append(dataObj)
           
    self.optConstraintMatrix.update(textMatrix=textMatrix,
                                     objectList=objectList)
Example #16
0
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()
Example #17
0
class BackupProjectPopup(BasePopup):
    """
  **Create Automatic Project Backup**

  The purpose of this dialog is to allow the user to create backups
  of their project automatically.  The XML files for the backup go
  into a separate directory from the project itself.  If the project
  directory is called PROJECTDIR then the default for the backup
  directory is PROJECTDIR_backup, although that can be changed to
  something else in this dialog.

  Other than the backup directory, the user can specify the frequency
  of the backup, in minutes.

  The "Apply Auto Settings" does not have to be applied if the user
  has changed the on/off setting or if the user has changed the
  Auto-backup frequency and entered a carriage return.

  The "Do Immediate Backup" is in case the user wants to do a backup
  then and there.

  There is no backup for the backup.
  """

    on_off_entries = ['on', 'off']

    def __init__(self, parent, help_msg='', help_url='', *args, **kw):

        self.help_msg = help_msg
        self.help_url = help_url

        BasePopup.__init__(self, parent=parent, title='Project : Backup', **kw)

    def body(self, guiFrame):

        self.geometry('500x130')

        guiFrame.grid_columnconfigure(2, weight=1)
        guiFrame.grid_rowconfigure(3, weight=1)

        self.alarm_id = None

        row = 0
        tipText = 'Browse for the directory into which project backups will be made'
        button = Button(guiFrame,
                        text='Directory:',
                        command=self.selectDir,
                        grid=(row, 0),
                        tipText=tipText,
                        sticky='ew')

        repository = self.project.findFirstRepository(name='backup')
        if repository:
            text = repository.url.path
        else:  # this is trouble, but should not happen
            text = ''

        tipText = 'Enter the name of the directory into which project backups will be made'
        self.dir_entry = Entry(guiFrame,
                               text=text,
                               tipText=tipText,
                               width=40,
                               returnCallback=self.applyAuto,
                               grid=(row, 1),
                               gridSpan=(1, 2),
                               sticky='ew')

        row += 1
        label = Label(guiFrame, text='Auto-backup:', grid=(row, 0))
        if self.analysisProject.doAutoBackup:
            ind = 0
        else:
            ind = 1

        tipTexts = [
            'Toggle the timed automatic backup on',
            'Toggle the timed automatic backup off'
        ]
        self.on_off_buttons = RadioButtons(guiFrame,
                                           entries=self.on_off_entries,
                                           tipTexts=tipTexts,
                                           select_callback=self.applyAuto,
                                           selected_index=ind,
                                           grid=(row, 1))

        row += 1
        tipText = 'The number of minutes to wait before automatic project backups'
        label = Label(guiFrame, text='Auto-backup frequency:', grid=(row, 0))

        self.freq_entry = IntEntry(guiFrame,
                                   text=self.analysisProject.autoBackupFreq,
                                   returnCallback=self.applyAuto,
                                   tipText=tipText)
        self.freq_entry.grid(row=row, column=1)

        label = Label(guiFrame, text=' (minutes)', grid=(row, 2))

        row = row + 1
        # Blank for expansion

        row = row + 1
        texts = ['Apply Auto Settings', 'Do Immediate Backup']
        commands = [self.applyAuto, self.applyManual]
        tipTexts = [
            'Commit the specified settings and commence automated CCPN project backup',
            'Backup the CCPN project now, into the specified backup directory'
        ]
        buttons = UtilityButtonList(guiFrame,
                                    texts=texts,
                                    commands=commands,
                                    doClone=False,
                                    helpMsg=self.help_msg,
                                    helpUrl=self.help_url,
                                    tipTexts=tipTexts,
                                    grid=(row, 0),
                                    gridSpan=(1, 3),
                                    sticky='nsew')

    def selectDir(self):

        popup = FileSelectPopup(self, show_file=False)
        dir = popup.getDirectory()
        popup.destroy()

        if (dir):
            self.dir_entry.set(dir)
            self.setDir()

    def setDir(self):

        directory = self.dir_entry.get()
        if not directory:
            showWarning('No directory',
                        'No directory specified, not setting backup directory',
                        parent=self)
            return

        if not os.path.abspath(directory):
            directory = joinPath(os.getcwd(), directory)

        if os.path.exists(directory):
            if not os.path.isdir(directory):
                showWarning('Path not directory',
                            'Path "%s" exists but is not a directory' %
                            directory,
                            parent=self)
                return
        else:
            if showYesNo(
                    'Directory does not exist',
                    'Directory "%s" does not exist, should it be created?' %
                    directory,
                    parent=self):
                os.mkdir(directory)
            else:
                showWarning(
                    'Directory not created',
                    'Directory "%s" not created so not setting backup directory'
                    % directory,
                    parent=self)
                return

        repository = self.project.findFirstRepository(name='backup')
        if not repository:
            showWarning(
                'No backup repository',
                'No backup repository found (something wrong somewhere)',
                parent=self)
            return

        url = repository.url
        if url.path != directory:
            repository.url = Url(path=normalisePath(directory))

    def setFreq(self):

        freq = self.freq_entry.get()

        if (freq is None):
            freq = 0

        self.analysisProject.autoBackupFreq = freq

    def setInfo(self):

        self.setFreq()
        self.setDir()

        on_off = (self.on_off_buttons.get() == 'on')
        self.analysisProject.doAutoBackup = on_off

    def applyAuto(self, *event):

        self.setInfo()
        on_off = self.on_off_buttons.get()
        if on_off == 'on':
            self.parent.setBackupOn()
        else:
            self.parent.setBackupOff()

    def applyManual(self):

        self.setDir()
        self.parent.doBackup()
Example #18
0
class CreateContourFilePopup(BasePopup):

  """
  **Create Contour Files for Project**

  The purpose of this dialog is to allow the user to create new contour
  files for the project.  Not only the spectrum has to be specified, but
  also the two dimensions (X, Y) that are going to be contoured.  The
  table specifies the conditions that specify the region being contoured,
  in terms of what is included and excluded.

  For now, only one condition (which is an "include" condition) is allowed.
  This also means that the "Add Condition" and "Delete Condition" buttons
  are disabled.

  The contour directory is specified by the program, using the project
  directory but the file name can be specified by the user.

  The contour levels used are the ones that are current for the spectrum,
  as set in the `Contour Levels dialog`_.

  See also: `Spectrum Contour Files`_, `Add Existing Contour Files`_.

  .. _`Contour Levels dialog`: EditContourLevelsPopup.html
  .. _`Spectrum Contour Files`: EditContourFilesPopup.html
  .. _`Add Existing Contour Files`: AddContourFilePopup.html
"""

  def __init__(self, parent, *args, **kw):

    self.spectrumConditions = []
    self.col = None
    self.spectrum = None

    BasePopup.__init__(self, parent=parent, title='New Contour File', **kw)

  def body(self, master):

    self.geometry('650x200')

    master.grid_columnconfigure(1, weight=1)

    row = 0
    frame = Frame(master, grid=(row, 0), gridSpan=(1,2))
    
    label = Label(frame, text='Spectrum: ', grid=(row, 0))
    tipText = 'Selects the experiment and spectrum for which to make a contour file'
    self.expt_spectrum = PulldownList(frame, grid=(row, 1),
                                      tipText=tipText, callback=self.update)

    label = Label(frame, text=' (X-dim, Y-dim): ', grid=(row, 2))
    tipText = 'Selects which dimensions (projection) of the spectrum form the X and Y axes of the contour file'
    self.dim_menu = PulldownList(frame, grid=(row, 3), tipText=tipText,
                                 callback=self.updateFile)

    row = row + 1
    master.grid_rowconfigure(row, weight=1)
    #### for now not editable because only allow one include region
    ###self.conditionMenu = PulldownMenu(self, entries=('include', 'exclude'),
    ###                       callback=self.selectedCondition, do_initial_callback=False)
    self.regionEntry = FloatEntry(self, text='', returnCallback=self.setRegion, width=10)
    tipTexts = ['Whether to include or exclude the region in the contour file',
                '',
                '',
                '']
    headingList = ['Condition','','','','']
    editSetCallbacks = [None]
    editGetCallbacks = [None]
    ###editWidgets = [self.conditionMenu]
    editWidgets = [None]
    self.conditionTable = ScrolledMatrix(master, initialRows=6,
                                         grid=(row, 0), gridSpan=(1,2),
                                         tipTexts=tipTexts,
                                         headingList=headingList,
                                         callback=self.selectCell,
                                         editWidgets=editWidgets,
                                         editGetCallbacks=editGetCallbacks,
                                         editSetCallbacks=editSetCallbacks)

    # TBD: make directory editable
    row = row + 1
    label = Label(master, text='Contour dir: ', grid=(row, 0), sticky='e')
    tipText = 'The directory location on disk into which contour files are saved'
    self.dir_label = Label(master, text='', grid=(row, 1), tipText=tipText)

    row = row + 1
    label = Label(master, text='File name: ', grid=(row, 0), sticky='e')
    tipText = 'Sets the name of the contour file to save to disk'
    self.file_entry = Entry(master, grid=(row, 1), tipText=tipText)

    ##row = row + 1
    ##label = Label(master, text='Contour levels: ')
    ##label.grid(row=row, column=0, sticky='e')
    ##self.levels_entry = FloatEntry(master, isArray=True, returnCallback=self.saveLevels)
    ##self.levels_entry.grid(row=row, column=1, sticky='ew')

    row = row + 1
    tipTexts = ['Add a new contour region for including in or excluding from the contour file ',
                'Remove the selected contour region from the table',
                'Make the specified contour file using the input settings & regions']
    texts = [ 'Add Condition', 'Delete Condition', 'Contour and Save' ]
    commands = [ self.addCondition, self.deleteCondition, self.contourAndSaveSpectrum ]
    self.buttons = UtilityButtonList(master, texts=texts, commands=commands,
                                     doClone=False, helpUrl=self.help_url,
                                     grid=(row, 0), gridSpan=(1,2), tipTexts=tipTexts)

    ### TBD disabled for now
    for n in range(2):
      self.buttons.buttons[n].config(state='disabled')

    self.curateNotifiers(self.registerNotify)
    self.updateSpectrum()
    self.updateDimMenu()

  def destroy(self):

    self.curateNotifiers(self.unregisterNotify)

    BasePopup.destroy(self)

  def curateNotifiers(self, notifyFunc):

    for clazz in ('Experiment', 'DataSource'):
      for func in ('__init__', 'delete', 'setName'):
        notifyFunc(self.updateNotifier, 'ccp.nmr.Nmr.%s' % clazz, func)

  def update(self, spectrum):

    if spectrum is self.spectrum:
      return

    self.spectrum = spectrum

    self.updateDimMenu()
    self.updateConditionTable()
    self.updateFile()
    ##self.updateLevels()

  def updateSpectrum(self, spectrum=None):

    if not spectrum:
      spectrum = self.spectrum

    spectra = self.parent.getSpectra()
    if spectra:
      if spectrum not in spectra:
        spectrum = spectra[0]
      index = spectra.index(spectrum)
      names = ['%s:%s' % (x.experiment.name, x.name) for x in spectra]
    else:
      index = 0
      names = []

    self.expt_spectrum.setup(names, spectra, index)

    self.update(spectrum)

  def updateNotifier(self, *extra):

    self.updateSpectrum()

  def updateFile(self, *extra):

    spectrum = self.spectrum
    if not spectrum:
      return

    analysisSpectrum = spectrum.analysisSpectrum
    if not analysisSpectrum:
      return

    dims = self.dim_menu.getText()
    dims = [int(dim) for dim in dims.split(', ')]
    (xdim, ydim) = dims
    storedContour = analysisSpectrum.findFirstStoredContour(dims=dims)
    if not storedContour:
      storedContour = analysisSpectrum.findFirstStoredContour()
    if storedContour:
      fileName = storedContour.path
    else:
      fileName = '%s_%s_%d_%d.cnt' % (spectrum.experiment.name, spectrum.name, xdim, ydim)

    path = self.getContourDir()
    self.dir_label.set(path)
    self.file_entry.set(fileName)

  def getContourDir(self):

    spectrum = self.spectrum
    if not spectrum:
      return ''

    analysisSpectrum = spectrum.analysisSpectrum
    if not analysisSpectrum:
      return ''

    url = analysisSpectrum.contourDir
    if url: # should be the case since set in Analysis.py
      path = url.dataLocation
    else:
      path = ''

    return path

  """
  def saveFile(self, *extra):

    spectrum = self.spectrum
    if not spectrum:
      return

    analysisSpectrum = spectrum.analysisSpectrum
    if not analysisSpectrum:
      return

    fileName = self.file_entry.get()
    if fileName:
      
      application = self.project.application
      application.setValue(spectrum, keyword='contourFileName', value=fileName)
"""
    
  def updateDimMenu(self):

    entries = []
    spectrum = self.spectrum
    if spectrum:
      ndim = spectrum.numDim
      for xdim in range(1, ndim):
        dataDim = spectrum.findFirstDataDim(dim=xdim)
        if dataDim.className != 'SampledDataDim':
          for ydim in range(xdim+1, ndim+1):
            dataDim = spectrum.findFirstDataDim(dim=ydim)
            if dataDim.className != 'SampledDataDim':
              entries.append('%d, %d' % (xdim, ydim))
    self.dim_menu.setup(entries, objects=None, index=0)

  def updateConditionTable(self, *extra):

    spectrum = self.spectrum
    if spectrum:
      ndim = spectrum.numDim
    else:
      ndim = 0
    tipTexts = ['Whether to include or exclude the region in the contour file',]
    headingList = ['Condition']
    ###editWidgets = [self.conditionMenu] + 2*ndim*[self.regionEntry]
    ###editGetCallbacks = [self.getCondition]
    ###editSetCallbacks = [self.setCondition]
    editWidgets = [None] + 2*ndim*[self.regionEntry]
    editGetCallbacks = [None]
    editSetCallbacks = [None]
    for i in range(ndim):
      dim = i + 1
      headingList.extend(['Dim %d Min' % dim, 'Dim %d Max' % dim])
      editGetCallbacks.append(lambda obj, i=i: self.getRegionMin(obj, i))
      editGetCallbacks.append(lambda obj, i=i: self.getRegionMax(obj, i))
      editSetCallbacks.append(lambda obj, i=i: self.setRegionMin(obj, i))
      editSetCallbacks.append(lambda obj, i=i: self.setRegionMax(obj, i))
      tipTexts.append('Lower bound of dimension %d region to include or exclude' % dim)
      tipTexts.append('Upper bound of dimension %d region to include or exclude' % dim)
      
    objectList = []
    textMatrix = []
    self.spectrumConditions = self.getSpectrumConditions()
    for spectrumCondition in self.spectrumConditions:
      (condition, region) = spectrumCondition
      objectList.append(spectrumCondition)
      textRow = [condition]
      for i in range(ndim):
        r = region[i]
        if r:
          rMin = r[0]
          rMax = r[1]
        else:
          rMin = rMax = None
        textRow.append(rMin)
        textRow.append(rMax)
      textMatrix.append(textRow)

    self.conditionTable.update(objectList=objectList, textMatrix=textMatrix,
                               headingList=headingList,
                               editSetCallbacks=editSetCallbacks,
                               editGetCallbacks=editGetCallbacks,
                               editWidgets=editWidgets)

  """
  def updateLevels(self):

    spectrum = self.getSpectrum()
    if spectrum:
      analysisSpectrum = spectrum.analysisSpectrum
      levels = analysisSpectrum.posLevels + analysisSpectrum.negLevels
      scale = spectrum.scale / self.analysisProject.globalContourScale
      levels = [ level/scale for level in levels ]
    else:
      levels = []

    self.levels_entry.set(levels)

  def saveLevels(self):

    spectrum = self.spectrum
    if not spectrum:
      return
"""

  def getRegionMin(self, spectrumCondition, dim):
   
    #print 'getRegionMin'
    (condition, region) = spectrumCondition
    self.regionEntry.set(region[dim][0])

  def setRegionMin(self, spectrumCondition, dim):
   
    #print 'setRegionMin'

    (condition, region) = spectrumCondition
    (r0, r1) = region[dim]
    r = self.regionEntry.get()
    region[dim] = (r, r1)
    self.setSpectrumConditions()
    self.updateConditionTable()

  def getRegionMax(self, spectrumCondition, dim):
   
    #print 'getRegionMax'
    (condition, region) = spectrumCondition
    self.regionEntry.set(region[dim][1])

  def setRegionMax(self, spectrumCondition, dim):

    #print 'setRegionMax'
    (condition, region) = spectrumCondition
    (r0, r1) = region[dim]
    r = self.regionEntry.get()
    region[dim] = (r0, r)
    self.setSpectrumConditions()
    self.updateConditionTable()

  def setRegion(self, *extra):

    spectrumCondition = self.getCurrentObject()
    if spectrumCondition and self.col is not None:
      col = self.col - 1 # -1 because of condition
      dim = col / 2
      if col % 2: # max
        self.setRegionMax(spectrumCondition, dim)
      else: # min
        self.setRegionMin(spectrumCondition, dim)

  """ not needed for now
  def getCondition(self, spectrumCondition):
   
    #print 'getCondition'
    (condition, region) = spectrumCondition
    self.conditionMenu.set(condition)

  def setCondition(self, spectrumCondition):

    #print 'setCondition'
    spectrumCondition[0] = self.conditionMenu.get()
    self.setSpectrumConditions()

  def selectedCondition(self, ind, condition):

    spectrumCondition = self.getCurrentObject()

    if spectrumCondition is not None:
      self.setCondition(spectrumCondition)
"""

  def getSpectrumConditions(self):

    spectrum = self.spectrum
    if not spectrum:
      return []

    application = self.project.application
    spectrumConditions = application.getValue(spectrum, keyword='contourFileConditions')
    if spectrumConditions:
      spectrumConditions = eval(spectrumConditions)
    else:
      region = []
      for i in range(spectrum.numDim):
        dim = i + 1
        region.append(self.getWholeRegion(spectrum, dim))
      spectrumCondition = ['include', region]
      spectrumConditions = [spectrumCondition]
      self.setSpectrumConditions(spectrumConditions)

    return spectrumConditions

  def setSpectrumConditions(self, spectrumConditions = None):

    spectrum = self.spectrum

    if spectrum:
      if not spectrumConditions:
        spectrumConditions = self.spectrumConditions

      application = self.project.application
      application.setValue(spectrum, keyword='contourFileConditions', value=str(spectrumConditions))

  def getDimMin(self, spectrum, dim):

    dataDim = spectrum.findFirstDataDim(dim=dim)
    if dataDim.className == 'SampledDataDim':
      r = 1.0
    else:
      converter = UnitConverter.pnt2ppm
      dataDimRef = ExperimentBasic.getPrimaryDataDimRef(dataDim)
      r = converter(float(dataDim.numPoints), dataDimRef)

    return r

  def getDimMax(self, spectrum, dim):

    dataDim = spectrum.findFirstDataDim(dim=dim)
    if dataDim.className == 'SampledDataDim':
      r = float(dataDim.numPoints)
    else:
      converter = UnitConverter.pnt2ppm
      dataDimRef = ExperimentBasic.getPrimaryDataDimRef(dataDim)
      r = converter(1.0, dataDimRef)

    return r

  def getWholeRegion(self, spectrum, dim):

    rMin = self.getDimMin(spectrum, dim)
    rMax = self.getDimMax(spectrum, dim)

    return (rMin, rMax)

  def getCurrentObject(self):

    # sometimes row highlighting stops so obj passed into selectCell might no longer be current
    # so instead use direct interrogation of scrolledMatrix
    obj = self.conditionTable.currentObject

    return obj

  def selectCell(self, obj, row, col):

    # see note about obj in getCurrentObject()
    self.col = col

  def addCondition(self):

    spectrum = self.spectrum
    if spectrum:
      ndim = spectrum.numDim
      spectrumCondition = ['exclude', ndim*[(None,None)]]
      self.spectrumConditions.append(spectrumCondition)
      self.setSpectrumConditions()
      self.updateConditionTable()

  def deleteCondition(self):

    spectrumCondition = self.getCurrentObject()
    if spectrumCondition:
      self.spectrumConditions.remove(spectrumCondition)
      self.setSpectrumConditions()
      self.updateConditionTable()

  def continueIfFileNameUsed(self, fileName):

    result = True

    storedContoursToDelete = []
    for analysisSpectrum in self.analysisProject.analysisSpectra:
      for storedContour in analysisSpectrum.storedContours:
        if storedContour.fullPath == fileName:
          storedContoursToDelete.append(storedContour)

    if storedContoursToDelete:
      if len(storedContoursToDelete) == 1:
        s = ''
        t = 's'
      else:
        s = 's'
        t = ''
      result = showYesNo('File used', 'Stored contour%s already use%s this fileName, and will be deleted: continue?' % (s, t), parent=self)
      if result:
        for storedContour in storedContoursToDelete:
          try:
            storedContour.delete()
          except:
            pass

    return result

  def contourAndSaveSpectrum(self):

    spectrum = self.spectrum
    if not spectrum:
      return

    if not self.spectrumConditions:
      return

    ###self.saveFile()
    fileName = self.file_entry.get()
    if not fileName:
      showError('No filename', 'No filename given', parent=self)
      return

    contourDir = self.getContourDir()

    fullPath = joinPath(contourDir, fileName)
    if not self.continueIfFileNameUsed(fullPath):
      return

    directory = os.path.dirname(fullPath)
    if not os.path.exists(directory):
      os.makedirs(directory)

    dims = self.dim_menu.getText()
    (xdim, ydim) = [int(dim) for dim in dims.split(', ')]

    ##self.saveLevels()
    ##levels = self.levels_entry.get()
    ##if not levels:
    ##  showError('No levels', 'No contour levels given', parent=self)
    ##  return
    analysisSpectrum = spectrum.analysisSpectrum
    levels = analysisSpectrum.posLevels + analysisSpectrum.negLevels
    scale = spectrum.scale / self.analysisProject.globalContourScale
    levels = [ level/scale for level in levels ]

    spectrumCondition = self.spectrumConditions[0]
    (condition, region) = spectrumCondition

    ndim = spectrum.numDim
    firstInt = ndim * [0]
    lastInt = ndim * [0]
    for i in range(ndim):
      try:
        (firstInt[i], lastInt[i]) = self.convertToPoints(spectrum, i, region[i])
      except Exception, e:
        showError('Invalid region', str(e), parent=self)

    try:
      #print 'about to saveSpectrumContours', fullPath, xdim, ydim, levels, firstInt, lastInt
      saveSpectrumContours(spectrum, fullPath, xdim, ydim, levels, firstInt, lastInt,
                         mem_cache=self.parent.mem_cache)
    except Exception, e:
      showError('Save error', str(e), parent=self)
      return
Example #19
0
class BlackledgeModuleFrame(Frame):
    """ Frame for handling MODULE calculation.
  
  Note that the frame uses (or creates) an NmrCalcStore named 'BLACKLEDGE_MODULE'
  and linked to the current NmrProject.
  """
    def __init__(self,
                 parent,
                 project,
                 closeButton=False,
                 tempFiles=False,
                 *args,
                 **kw):

        ###########################################################################
        # INIT VARIABLES

        self.parent = parent
        self.project = project

        try:
            self.nmrProject = (project.currentNmrProject or
                               project.newNmrProject(name='BLACKLEDGE_MODULE'))
        except:
            print '&&& Running MODULE popup from outside CCPN Analysis - debug only - no NmrCalc'
            self.nmrProject = None

        if self.nmrProject:
            self.calcStore = project.findFirstNmrCalcStore(name=MODULE, nmrProject=self.nmrProject) or \
                             project.newNmrCalcStore(name=MODULE, nmrProject=self.nmrProject)

        else:
            self.calcStore = None

        self.run = None

        self.inputStructure = None
        self.inputRdcConstraintList = None
        self.inputDistanceConstraintList = [None]
        self.inputUserDescriptionText = None

        # path to the module executable
        modPath = subprocess.Popen(
            ['which', 'module'],
            stdout=subprocess.PIPE).communicate()[0].strip()
        self.moduleExePath = modPath or '    NB. MODULE executable not found    '

        self.waiting = False

        # for debug this could be False
        if tempFiles:
            self.useTempFiles = True
        else:
            self.useTempFiles = False

        # create temp files for MODULE
        if self.useTempFiles:
            self.moduleTempDir = tempfile.mkdtemp(prefix='MODULE-')
        else:
            self.moduleTempDir = os.getcwd()

        #djo35# self.calcStore = self.resetCalcStore(name='BLACKLEDGE_MODULE')

        # END INIT OF VARIABLES
        ###########################################################################

        ###########################################################################
        # START GUI CODE

        Frame.__init__(self, parent, *args, **kw)

        self.expandGrid(0, 0)

        ## Single Frame
        # frame = Frame(self, grid=(0,0))

        # or with Tabs?
        options = ['Launch', 'Output', 'Runs']
        tabbedFrame = TabbedFrame(self, options=options, grid=(0, 0))
        frameA, frameB, frameC = tabbedFrame.frames
        self.tabbedFrame = tabbedFrame

        frameA.expandGrid(14, 2)

        row = 0
        div = LabelDivider(frameA,
                           text='MODULE Setup',
                           grid=(row, 0),
                           gridSpan=(1, 4))

        row += 1
        # allow the user to choose MODULE if either the one in PATH is incorrect or not found
        button = Button(frameA, text='Select MODULE executable:',bd=1, \
                                command=self.selectExecutable,  grid=(row,0), sticky="ew")
        self.moduleExeEntry = Entry(frameA, text=self.moduleExePath, grid=(row,1), gridSpan=(1,3), \
                                width=32, sticky="ew", bd=1)
        self.moduleExePath = self.moduleExeEntry.get()

        # separator "MODULE input"
        row += 1
        div = LabelDivider(frameA,
                           text='MODULE input',
                           grid=(row, 0),
                           gridSpan=(1, 5))

        row += 1
        label = Label(frameA, text='Structure:', grid=(row, 1))
        self.inputStructurePulldown = PulldownList(frameA, self.changeInputStructure, \
                                                        grid=(row,2))
        # self.constraintsFileEntry.bind('<Leave>', self.updateEntryParams)

        row += 1
        label = Label(frameA, text='RDC constraints:', grid=(row, 1))
        self.inputRdcConstraintsPulldown = PulldownList(frameA, self.changeInputRdcConstraintList, \
                                                        grid=(row,2))
        #self.constraintsFileEntry.bind('<Leave>', self.updateEntryParams)

        row += 1
        label = Label(frameA, text='(Optional input)', grid=(row, 0))
        label = Label(frameA, text='Distance constraints:', \
                                                        grid=(row,1))
        self.inputDistanceConstraintsPulldown = PulldownList(frameA, self.changeInputDistanceConstraintList, \
                                                        grid=(row,2))
        #self.constraintsFileEntry.bind('<Leave>', self.updateEntryParams)

        row += 1

        subFrameDepth = 4
        subframe = LabelFrame(frameA, text='MODULE User Notes (store notes about how MODULE was run here)', \
                                                        grid=(row,0), gridSpan=(1,4))
        subframe.expandGrid(subFrameDepth, 0)

        self.moduleUserText = ScrolledText(subframe)
        self.moduleUserText.grid(row=subFrameDepth,
                                 column=0,
                                 columnspan=4,
                                 sticky='nsew')

        # View Results
        row += subFrameDepth

        # row += 1
        # div = LabelDivider(frameA, text='MODULE launch', grid=(row,0), gridSpan=(1,4))

        row += 1
        button = Button(frameA, text='Run MODULE', bd=1, command=self.executeModule, \
                                                        grid=(row,0), gridSpan=(1,4), sticky="ew", bg=MODULE_GREEN)
        # grid=(row,0), gridSpan=(1,2), sticky="ew", bg=MODULE_GREEN)

        ###########################################################################
        # Frame B (tab 2) Ouput
        frameB.expandGrid(4, 1)
        row = 0

        subFrameDepth = 6
        subframe = LabelFrame(frameB, text='MODULE Output', \
                                                        grid=(row,0), gridSpan=(1,5))
        #subframe.grid_columnconfigure(2, weight=1)
        subframe.expandGrid(subFrameDepth, 0)

        self.moduleOutputText = ScrolledText(subframe)
        self.moduleOutputText.setState(state=Tkinter.DISABLED)
        self.moduleOutputText.grid(row=subFrameDepth,
                                   column=0,
                                   columnspan=4,
                                   sticky='nsew')

        # separator "MODULE input"
        row += 1
        div = LabelDivider(frameB,
                           text='MODULE RDC Back Values',
                           grid=(row, 0),
                           gridSpan=(1, 5))

        row += 1
        button = Button(frameB, text='Import MODULE Back Values file', bd=1, command=self.importModuleBackValues, \
                                                        grid=(row,0), gridSpan=(1,4), sticky="ew", bg=MODULE_BLUE)
        # grid=(row,0), gridSpan=(2,4), sticky="ew", bg=MODULE_BLUE)

        row += 1
        self.rdcOutputTable = None
        frameB.grid_rowconfigure(row, weight=1)
        headings = ('#', 'Resonances', 'Value', 'Back Value', 'Diff.', 'Error')

        editWidgets = [None, None, None, None, None, None]
        editGetCallbacks = [None, None, None, None, None, None]
        editSetCallbacks = [None, None, None, None, None, None]

        self.rdcOutputTable = ScrolledMatrix(frameB,
                                             headingList=headings,
                                             multiSelect=False,
                                             editWidgets=editWidgets,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks,
                                             initialRows=4)

        self.rdcOutputTable.grid(row=row,
                                 column=0,
                                 columnspan=4,
                                 sticky='nsew')

        row += 1
        button = Button(frameB, text='Import MODULE Structure', bd=1, command=self.importModuleStructure, \
                                                        grid=(row,0), gridSpan=(1,4), sticky="ew", bg=MODULE_BLUE)
        # grid=(row,0), gridSpan=(2,4), sticky="ew", bg=MODULE_BLUE)

        ###########################################################################
        # Frame C (tab 3) NMR Calc display bits
        frameC.expandGrid(4, 1)
        row = 0

        div = LabelDivider(frameC,
                           text='Stored MODULE Runs',
                           grid=(row, 0),
                           gridSpan=(1, 5))

        # NmrCalc Run scrolled matrix
        row += 1
        self.runTable = None
        frameC.grid_rowconfigure(row, weight=1)
        headings = ('Run ID', 'notes', 'Status')

        # self.editRunNotes = DataEntry.askString('Run Notes', 'Edit notes about Run', tipText='Notes about Run', parent=self)
        # editWidgets       = [None, self.editRunNotes, None]

        editWidgets = [None, None, None]
        editGetCallbacks = [None, None, None]
        editSetCallbacks = [None, None, None]

        self.runTable = ScrolledMatrix(frameC,
                                       headingList=headings,
                                       multiSelect=False,
                                       editWidgets=editWidgets,
                                       editGetCallbacks=editGetCallbacks,
                                       editSetCallbacks=editSetCallbacks,
                                       initialRows=4)

        self.runTable.grid(row=row, column=0, columnspan=4, sticky='nsew')

        row += 4
        tipTexts = ['Load Selected Run', 'Delete Selected Run']
        texts = ['Load Selected Run', 'Delete Selected']
        commands = [self.loadRun, self.deleteRun]
        colours = [MODULE_GREEN, MODULE_RED]
        self.runButtons = ButtonList(frameC,
                                     texts=texts,
                                     tipTexts=tipTexts,
                                     commands=commands,
                                     grid=(row, 0),
                                     gridSpan=(1, 4))
        self.runButtons.buttons[0].config(bg=MODULE_GREEN)
        self.runButtons.buttons[1].config(bg=MODULE_RED)

        ###########################################################################
        # Keep GUI up to date

        self.updateAfter()
        self.administerNotifiers(self.parent.registerNotify)

    # END GUI CODE
    ###########################################################################

    ###########################################################################
    # FUNCTIONS CALLED FROM GUI

    ################
    # OS interaction
    def selectExecutable(self):
        """ Choose the MODULE executable appropriate for your system. """

        popup = FileSelectPopup(self, show_file=True)

        executable = popup.getFile()
        if executable:
            self.moduleExeEntry.set(executable)

        popup.destroy()

    def executeModule(self):
        """ Execute MODULE with all given parameters 
        Yeah it's a big function, bite me :-P
    """

        # check that all params have been set
        if not os.path.isfile(self.moduleExePath):
            popup = showWarning('MODULE',
                                'Cannot find MODULE executable.',
                                parent=self)
            return

        if self.inputStructure is None:
            popup = showWarning(
                'MODULE',
                'MODULE cannot run with out a structure for input.',
                parent=self)
            return

        if self.inputRdcConstraintList is None:
            popup = showWarning(
                'MODULE',
                'MODULE cannot run with out an RDC constraint list for input.',
                parent=self)
            return

        # write temp PDB file
        strucTempFile = tempfile.NamedTemporaryFile(mode='w',
                                                    suffix='.pdb',
                                                    dir=self.moduleTempDir,
                                                    delete=False)
        strucTempFile.close()
        makePdbFromStructure(strucTempFile.name,
                             self.inputStructure.structureEnsemble,
                             model=self.inputStructure)

        # write temp RDC file
        rdcTempFile = tempfile.NamedTemporaryFile(mode='w',
                                                  suffix='.tab',
                                                  dir=self.moduleTempDir,
                                                  delete=False)

        moduleIo.writeConstraintList(rdcTempFile, self.inputRdcConstraintList)
        rdcTempFile.close()

        # command to be executed (to start MODULE)
        moduleCommands = [
            self.moduleExePath, strucTempFile.name, rdcTempFile.name
        ]

        # if user has set Distance constraint list then fill add this (user optional)
        if self.inputDistanceConstraintList:
            distanceTempFile = tempfile.NamedTemporaryFile(
                mode='w', suffix='.tab', dir=self.moduleTempDir, delete=False)
            moduleIo.writeConstraintList(distanceTempFile,
                                         self.inputDistanceConstraintList)
            distanceTempFile.close()
            moduleCommands.append(distanceTempFile.name)

        # execute MODULE
        moduleOutput = subprocess.Popen(
            moduleCommands, stdout=subprocess.PIPE).communicate()[0]

        # clean out the blank lines
        for line in moduleOutput:
            if line == '':
                moduleOutput.pop(line)

        # send the output to our screen
        self.moduleOutputText.setState(state=Tkinter.NORMAL)
        self.moduleOutputText.setText(text=moduleOutput)
        self.moduleOutputText.setState(state=Tkinter.DISABLED)

        # clean up temp files (delete has been set to False)
        for tempFile in [strucTempFile.name, rdcTempFile.name]:
            if os.path.isfile(tempFile):
                os.unlink(tempFile)
        if self.inputDistanceConstraintList:
            if os.path.isfile(distanceTempFile.name):
                os.unlink(distanceTempFile.name)

        # create new run and store inputs
        self.newRun()
        self.updateRunInputs()

    ############################################################################
    # Outputs:

    ############################
    # Import MODULE PDB

    def findModuleExportPdbFile(self):
        """ Find the MODULE PDB export file, typically called temp%s.pdb 
      unless user has renamed it.
    """
        modulePdbFileGood = False

        def yes():
            modulePdbFileGood = True

        def cancel():
            modulePdbFileGood = False

        # MODULE writes pdb files to CWD no matter where you or it is
        possibleFiles = glob.glob(os.path.join(os.getcwd(), 'temp*'))
        # debug
        # possibleFiles = glob.glob( os.path.join( os.getcwd(), 'module', 'temp*' ) )

        if len(possibleFiles) == 1:

            if os.path.isfile(possibleFiles[0]):

                texts = ['Yes', 'No, choose another PDB file', 'Cancel']
                objects = [yes, self.selectModulePdbExport, cancel]
                func = showMulti('MODULE', 'Is this the PDB strcture you exported from MODULE?\n%s' % possibleFiles[0], \
                          texts=texts, objects=objects, parent=self)
                func()

                if modulePdbFileGood == True:
                    modulePdbFile = possibleFiles[0]
                else:
                    return None

            else:
                modulePdbFile = self.selectModulePdbExport()

        elif len(possibleFiles) > 1:

            texts = ['%s' % fileName for fileName in possibleFiles]
            objects = ['%s' % fileName for fileName in possibleFiles]
            modulePdbFile = showMulti('MODULE', 'Multiple possible MODULE export\nfiles found, please select one:' % possibleFiles, \
                      texts=texts, objects=objects, parent=self)

            if os.path.isfile(modulePdbFile):
                modulePdbFile = modulePdbFile

        else:
            modulePdbFile = self.selectModulePdbExport()

        return modulePdbFile

    def selectModulePdbExport(self):
        """ Choose the PDB file that was exported from MODULE. """

        file_types = [
            FileType("PDB structure files", ["*.pdb"]),
            FileType("All files", ["*"])
        ]
        popup = FileSelectPopup(self,
                                file_types,
                                dismiss_text='Cancel',
                                show_file=True)

        chosenPdbFile = popup.getFile()
        if os.path.isfile(chosenPdbFile):
            modulePdbFile = chosenPdbFile
        else:
            warnPopup = showWarning('MODULE',
                                    'File %s not found.' % chosenPdbFile,
                                    parent=self)
            return None

        popup.destroy()

        return modulePdbFile

    def importModuleStructure(self):
        """ Find MODULE structure file and import into Analysis (or attempt to, this will probably
      barf as MODULE pdb files are not good)
    """

        modulePdbFile = self.findModuleExportPdbFile()
        if not modulePdbFile: return

        # this stores the re-hacked MODULE pdb file and then removes it on close
        tempPdb = tempfile.NamedTemporaryFile(mode='w',
                                              suffix='.pdb',
                                              dir=self.moduleTempDir,
                                              delete=False)
        tempPdb.close()

        # if file found then add to project
        if os.path.isfile(modulePdbFile):
            moduleIo.BlackledgeToPdbConverter(modulePdbFile, tempPdb)
            structure = getStructureFromFile(
                self.inputStructure.parent.molSystem, tempPdb)
            os.unlink(tempPdb)

    ############################
    # Import MODULE Back Values

    def findModuleExportBackValuesFile(self):
        """ Find the Back Values file that the User hopefully exported from MODULE """
        def yes():
            moduleBvFileGood = True

        def cancel():
            moduleBvFileGood = False

        # back value files are helpfully appended '*.back'
        possibleFiles = glob.glob(os.path.join(os.getcwd(), '*.back'))
        possibleFiles += glob.glob(os.path.join(self.moduleTempDir, '*.back'))

        if len(possibleFiles) == 1:

            if os.path.isfile(possibleFiles[0]):

                texts = [
                    'Yes', 'No, choose another Back Values file', 'Cancel'
                ]
                objects = [yes, self.selectModuleBvExport, cancel]
                func = showMulti('MODULE', 'Is this the Back Values file that you exported from MODULE?\n%s' % possibleFiles[0], \
                          texts=texts, objects=objects, parent=self)
                func()

                if moduleBvFileGood == True:
                    moduleBackValueFile = possibleFiles[0]
                else:
                    return None

            else:
                moduleBackValueFile = self.selectModuleBvExport()

        elif len(possibleFiles) > 1:

            texts = ['%s' % fileName for fileName in possibleFiles]
            objects = ['%s' % fileName for fileName in possibleFiles]
            chosenBvFile = showMulti('MODULE', 'Multiple possible MODULE Back Value\nfiles found, please select one:' % possibleFiles, \
                      texts=texts, objects=objects, parent=self)

            if os.path.isfile(modulePdbFile):
                moduleBackValueFile = chosenBvFile

        else:
            moduleBackValueFile = self.selectModuleBvExport()

        return moduleBackValueFile

    def selectModuleBvExport(self):
        """ Choose the Back Value file that was exported from MODULE. """

        file_types = [
            FileType("Back Value files", ["*.back"]),
            FileType("All files", ["*"])
        ]
        popup = FileSelectPopup(self,
                                file_types,
                                dismiss_text='Cancel',
                                show_file=True)

        chosenBvFile = popup.getFile()
        if os.path.isfile(chosenBvFile):
            moduleBackValueFile = chosenBvFile
        else:
            warnPopup = showWarning('MODULE',
                                    'File %s not found.' % chosenBvFile,
                                    parent=self)
            return None

        popup.destroy()

        return moduleBackValueFile

    def importModuleBackValues(self):
        """ Attempt to find the Back Values file and then import it ... """

        # find the Back Values file or ask user
        backValFile = self.findModuleExportBackValuesFile()
        if not backValFile: return

        # create a new RDC list
        if self.project:
            nmrConstraintStore = self.project.newNmrConstraintStore(
                nmrProject=self.project.findFirstNmrProject())

        if self.inputStructure:
            chain = self.inputStructure.parent.molSystem.findFirstChain()
        else:
            chain = None

        if nmrConstraintStore and chain:

            rdcList = moduleIo.getBackValuesListFromFile(
                backValFile, chain, nmrConstraintStore)

            # rdcRawData = moduleIo.getRawBackValuesFromFile( backValFile )
            #
            # for run in runs:
            #   runText.append( [run.getSerial(), run.getDetails(), run.getStatus()] )

            self.rdcOutputTable.update(objectList=None, textMatrix=None)

    # end OS interaction
    ####################

    ##################################
    # get, set and update menu options

    def changeInputRun(self, run):
        self.run = run

    def changeInputStructure(self, structure):
        self.inputStructure = structure

    def changeInputRdcConstraintList(self, constraintList):
        self.inputRdcConstraintList = constraintList

    def changeInputDistanceConstraintList(self, constraintList):
        self.inputDistanceConstraintList = constraintList

    def changeInputConstraintList(self, constraintList, className):
        if className == 'RdcConstraintList':
            self.changeInputRdcConstraintList(constraintList)
        elif className == 'DistanceConstraintList':
            self.changeInputDistanceConstraintList(constraintList)

    def getInputConstraintList(self, className):
        if className == 'RdcConstraintList':
            return self.inputRdcConstraintList
        elif className == 'DistanceConstraintList':
            return self.inputDistanceConstraintList

    # end get and set
    ##################################

    ####################
    # NMR Calc runs etc.

    def loadRun(self):
        pass

    def deleteRun(self):
        pass

    def changeRun(self):
        pass

    def newRun(self):

        if self.calcStore:
            self.run = self.calcStore.newRun(status='provisional')

    def updateRunInputs(self, event=None):

        self.inputUserDescriptionText = self.moduleUserText.getText() or None

        # store input parameters in run
        if self.run:

            # set the path to the MODULE executable used
            setRunTextParameter(self.run, MODULE_EXE, self.moduleExePath)

            # set the input structure sent to MODULE
            sEnsemble = self.inputStructure.StructureEnsemble
            self.run.newStructureEnsembleData(sEnsemble.ensembleId,
                                              sEnsemble.molSystem.code,
                                              name=STRUCTURE_DATA,
                                              ioRole=INPUT)

            # set the input RDC constraint list
            rdcConst = self.inputRdcConstraintList
            self.run.newConstraintStoreData(rdcConst.nmrConstraintStore.serial,
                                            name=RDC_CONSTRAINT_DATA,
                                            ioRole=INPUT)

            # set the input RDC constraint list (optional)
            distConst = self.inputDistanceConstraintList
            if distConst:
                self.run.newConstraintStoreData(
                    distConst.nmrConstraintStore.serial,
                    name=DIST_CONSTRAINT_DATA,
                    ioRole=INPUT)

            # set the input user data (if any)
            setRunTextParameter(self.run, USER_DESCRIPTION_DATA,
                                self.inputUserDescriptionText)

    def editRunNotes(self):
        pass

    # end NMR calc stuff
    ####################

    ######################
    # update and noitfiers

    def administerNotifiers(self, notifyFunc):

        for func in ['__init__', 'delete']:
            for clazz in ['RdcConstraintList', 'DistanceConstraintList']:
                notifyFunc(self.updateAfter, 'ccp.nmr.NmrConstraint.' + clazz,
                           func)

            notifyFunc(self.updateAfter, 'ccp.nmr.NmrCalc.Run', func)

    def destroy(self):

        self.administerNotifiers(self.parent.unregisterNotify)
        Frame.destroy(self)

    def updateAll(self):

        # tab A
        self.updateModuleExecutablePath()
        self.updateInputStructure()
        self.updateInputRdcConstraintList()
        self.updateInputDistanceConstraintList()

        # tab C
        self.updateInputRuns()

        self.waiting = False

    def updateAfter(self, obj=None):

        if self.waiting:
            return
        else:
            self.waiting = True
            self.after_idle(self.updateAll)

    def updateInputRuns(self):

        if self.calcStore:
            runs = [
                r for r in self.calcStore.sortedRuns()
                if r.status == PROVISIONAL
            ]

        if not runs:
            self.newRun()
            runs = [self.run]

        runText = []

        for run in runs:
            runText.append(
                [run.getSerial(),
                 run.getDetails(),
                 run.getStatus()])

        self.runTable.update(objectList=runs, textMatrix=runText)

    def updateModuleExecutablePath(self):
        self.moduleExePath = self.moduleExeEntry.get()

    def updateInputStructure(self):

        index = None
        # names       = ['<None>']
        # structures  = [None]
        names = []
        structures = []

        for molSystem in self.project.sortedMolSystems():
            for ensemble in molSystem.sortedStructureEnsembles():
                for structure in ensemble.sortedModels():
                    structures.append(structure)

        if structures:

            for i, model in enumerate(structures):
                if model is None: continue
                ee = model.structureEnsemble
                name = '%s:%d:%d' % (ee.molSystem.code, ee.ensembleId,
                                     model.serial)
                names.append(name)

            if self.inputStructure not in structures:
                self.changeInputStructure(structures[0])

            index = structures.index(self.inputStructure)

        else:
            self.inputStructure = None

        self.inputStructurePulldown.setup(names, structures, index or -1)

    def updateInputConstraintList(self, className, obj=None):

        index = None
        # if DistanceConstraintList then None must be an option
        # names           = ['<None>']
        # constraintLists = [None]

        if className == 'DistanceConstraintList':
            names = ['<None>']
            constraintLists = [None]
        else:
            names = []
            constraintLists = []

        for nmrConstraintStore in self.parent.project.sortedNmrConstraintStores(
        ):
            for constraintList in nmrConstraintStore.sortedConstraintLists():
                if not className or constraintList.className == className:
                    constraintLists.append(constraintList)

        if constraintLists:

            for constList in constraintLists:
                if constList is None: continue
                store = constList.nmrConstraintStore
                name = '%d:%d' % (store.serial, constList.serial)
                names.append(name)

            if self.getInputConstraintList(className) not in constraintLists:
                self.changeInputConstraintList(constraintLists[0], className)

            index = constraintLists.index(
                self.getInputConstraintList(className))

        else:
            self.changeInputConstraintList(None, className)

        if className == 'RdcConstraintList':
            self.inputRdcConstraintsPulldown.setup(names, constraintLists,
                                                   index or -1)
        elif className == 'DistanceConstraintList':
            self.inputDistanceConstraintsPulldown.setup(
                names, constraintLists, index or -1)

    def updateInputRdcConstraintList(self):
        self.updateInputConstraintList('RdcConstraintList')

    def updateInputDistanceConstraintList(self):
        self.updateInputConstraintList('DistanceConstraintList')
class CloudHomologueAssignPopup(BasePopup):

  def __init__(self, parent, *args, **kw):

    self.guiParent = parent
    self.project   = parent.getProject()
    self.molSystem = None
    self.chain     = None
    self.assignment = None
    self.scores     = []

    BasePopup.__init__(self, parent, title="Cloud Threader", **kw)
  
  def body(self, guiFrame):

    guiFrame.grid_columnconfigure(3, weight=1)
    
    row = 0
    label = Label(guiFrame, text='Molecular system: ')
    label.grid(row=row, column=0, sticky=Tkinter.NW)
    self.molSysPulldown = PulldownMenu(guiFrame, self.changeMolSystem, selected_index=-1, do_initial_callback=0)
    self.molSysPulldown.grid(row=row, column=1, sticky=Tkinter.NW)

    label = Label(guiFrame, text='Clouds files: ')
    label.grid(row=row, column=2, sticky=Tkinter.NW)
    self.filenameEntry = Entry(guiFrame,text='perfect00.pdb')
    self.filenameEntry.grid(row=row, column=3, sticky=Tkinter.NW)


    row += 1
    label = Label(guiFrame, text='Chain: ')
    label.grid(row=row, column=0, sticky=Tkinter.NW)
    self.chainPulldown = PulldownMenu(guiFrame, self.changeChain, selected_index=-1, do_initial_callback=0)
    self.chainPulldown.grid(row=row, column=1, sticky=Tkinter.NW)

    label = Label(guiFrame, text='Thread steps: ')
    label.grid(row=row, column=2, sticky=Tkinter.NW)
    self.numStepsEntry = IntEntry(guiFrame,text=3000)
    self.numStepsEntry.grid(row=row, column=3, sticky=Tkinter.NW)
    row += 1

    label = Label(guiFrame, text='Homologue PDB file: ')
    label.grid(row=row, column=0, sticky=Tkinter.NW)
    self.pdbEntry = Entry(guiFrame,text='')
    self.pdbEntry.grid(row=row, column=1, sticky=Tkinter.NW)

    label = Label(guiFrame, text='Dist. Threshold: ')
    label.grid(row=row, column=2, sticky=Tkinter.NW)
    self.distEntry = FloatEntry(guiFrame,text=3.0)
    self.distEntry.grid(row=row, column=3, sticky=Tkinter.NW)

    row += 1

    label = Label(guiFrame, text='Global score: ')
    label.grid(row=row, column=0, sticky=Tkinter.NW)
    self.globalScoreLabel = Label(guiFrame, text='')
    self.globalScoreLabel.grid(row=row, column=1, sticky=Tkinter.NW)

    label = Label(guiFrame, text='Assignment Threshold: ')
    label.grid(row=row, column=2, sticky=Tkinter.NW)
    self.thresholdEntry = FloatEntry(guiFrame,text=-4.5)
    self.thresholdEntry.grid(row=row, column=3, sticky=Tkinter.NW)

    row += 1
    guiFrame.grid_rowconfigure(row, weight=1)
    self.graph = ScrolledGraph(guiFrame, width=300, height=200)
    self.graph.grid(row=row, column=0, columnspan=4, sticky = Tkinter.NSEW)

    row += 1
    texts    = ['Run','Assign!']
    commands = [self.run, self.assignSpinSystems]
    bottomButtons = createDismissHelpButtonList(guiFrame,texts=texts,commands=commands,expands=0,help_url=None)
    bottomButtons.grid(row=row, column=0, columnspan=4, sticky=Tkinter.EW)
    self.assignButton = bottomButtons.buttons[1]

    for func in ('__init__','delete'):
      Implementation.registerNotify(self.updateMolSystems, 'ccp.molecule.MolSystem.MolSystem', func)
      Implementation.registerNotify(self.updateChains, 'ccp.molecule.MolSystem.Chain', func)
    
    self.updateMolSystems()
    self.updateChains()

  def update(self):
  
    if self.assignment and self.scores:
      self.assignButton.enable()
    else:
      self.assignButton.disable()  

  def run(self):
  
    if self.chain:
      pattern = self.filenameEntry.get()
      nSteps  = self.numStepsEntry.get() or 4000
      pdbFile = self.pdbEntry.get()
      dist    =  self.distEntry.get() or 3.0
      pgb     = ProgressBar(self, text='Searching', total=nSteps)
      files   = getFileNamesFromPattern(pattern , '.')
      if not files:
        return
      clouds  = getCloudsFromFile(files, self.chain.root)
       
      score, self.scores, self.assignment = cloudHomologueAssign(self.chain, clouds, pdbFile, dist, nSteps, self.graph, pgb)
 
      pgb.destroy()
      self.globalScoreLabel.set(str(score))
      self.update()

  def assignSpinSystems(self):
   
    if self.assignment and self.scores:
      if showWarning('Query','Are you sure?'):
        threshold = self.thresholdEntry.get() or -4.0
        i = 0
 
        for residue in self.assignment.keys():
          if self.scores[residue] > threshold:
            spinSystem = self.assignment[residue]
            assignSpinSystemResidue(spinSystem,residue=None)
 
        for residue in self.assignment.keys():
          if self.scores[residue] > threshold:
            i += 1
            spinSystem = self.assignment[residue]
            assignSpinSystemResidue(spinSystem,residue=residue)
      
      showWarning('Done','%d residues assigned' % i)
      
  def getMolSystems(self):
  
    names = []
    for molSystem in self.project.molSystems:
      if molSystem.chains:
        names.append( '%s' % (molSystem.code) )
    return names


  def changeMolSystem(self, i, name):
  
    self.molSystem = self.project.findFirstMolSystem(code=name)


  def updateMolSystems(self, *opt):
  
    names = self.getMolSystems()
    if names:
      if not self.molSystem:
        self.molSystem = self.project.findFirstMolSystem(code=names[0])
      self.molSysPulldown.setup(names, names.index(self.molSystem.code))


  def getChains(self):
  
    chains = []
    if self.molSystem:
      for chain in self.molSystem.chains:
        chains.append( [chain.code, chain] )
	
    return chains


  def changeChain(self, i, name=None):
    
    if not name:
      i = self.chainPulldown.selected_index
    
    chains = self.getChains()
    if chains:
      self.chain = chains[i][1]
    
    
  def updateChains(self, *chain):
  
    chains = self.getChains()
 
    if chains:
      names = [x[0] for x in chains]
      if (not self.chain) or (self.chain.code not in names):
        self.chain = chains[0][1]
      self.chainPulldown.setup(names, names.index(self.chain.code) )

    self.update()

  def destroy(self):

    for func in ('__init__','delete'):
      Implementation.unregisterNotify(self.updateMolSystems, 'ccp.molecule.MolSystem.MolSystem', func)
      Implementation.unregisterNotify(self.updateChains, 'ccp.molecule.MolSystem.Chain', func)

    BasePopup.destroy(self)
Example #21
0
class SaveProjectFrame(Frame):
    def __init__(self,
                 guiParent,
                 project,
                 callback=None,
                 help_msg='',
                 help_url='',
                 dismiss_text='',
                 modal=False,
                 *args,
                 **kw):

        self.project = project
        self.callback = callback
        self.help_msg = help_msg
        self.help_url = help_url
        self.dismiss_text = dismiss_text
        self.modal = modal

        self.did_save = False

        Frame.__init__(self, guiParent, *args, **kw)

        projDir = Io.getUserDataPath(self.project)

        guiParent.grid_columnconfigure(1, weight=1)

        row = 0

        label = Label(guiParent, text='Project Name:')
        label.grid(row=row, column=0, sticky=Tkinter.E)

        self.proj_name_entry = Entry(
            guiParent,
            text=self.project.name,
            returnCallback=self.updateInfo,
            leaveCallback=self.updateInfo,
            tipText='The name used for the project save directory')
        self.proj_name_entry.grid(row=row, column=1, sticky=Tkinter.EW)

        row = row + 1
        label = Label(guiParent, text='Project Directory:')
        label.grid(row=row, column=0, sticky=Tkinter.E)

        label = self.proj_dir_label = Label(guiParent, text=projDir)
        label.grid(row=row, column=1, sticky=Tkinter.W)

        row = row + 1
        label = Label(
            guiParent,
            text='Note: Project Directory = Save Location + Project Name')
        label.grid(row=row, column=1, sticky=Tkinter.W)

        text = 'Save binary data with project'
        tipText = 'Copy data files (e.g. for spectra) into new project directory if not already in current project directory: careful, this can take some time'
        row = row + 1
        self.dataCheckButton = CheckButton(guiParent,
                                           text=text,
                                           tipText=tipText)
        self.dataCheckButton.grid(row=row,
                                  column=0,
                                  columnspan=2,
                                  sticky=Tkinter.W)

        row = row + 1
        guiParent.grid_rowconfigure(row, weight=1)
        labelFrame = LabelFrame(guiParent, text='Save Location')
        labelFrame.grid(row=row, column=0, columnspan=2, sticky=Tkinter.NSEW)
        labelFrame.grid_rowconfigure(0, weight=1)
        labelFrame.grid_columnconfigure(0, weight=1)

        directory = os.path.dirname(projDir)
        self.proj_dir_select = FileSelect(
            labelFrame,
            directory=directory,
            select_dir_callback=self.selectDir,
            change_dir_callback=self.updateInfo,
            should_change_dir_callback=self.shouldChangeDir,
            getRowColor=self.getEntryColor,
            show_file=False)
        self.proj_dir_select.grid(row=0, column=0, sticky=Tkinter.NSEW)

        row = row + 1
        texts = ['Save']
        tipTexts = ['Save project with specified name in specified directory']
        commands = [self.save]
        buttons = createDismissHelpButtonList(guiParent,
                                              texts=texts,
                                              tipTexts=tipTexts,
                                              commands=commands,
                                              help_msg=self.help_msg,
                                              help_url=self.help_url,
                                              dismiss_text=self.dismiss_text,
                                              expands=True)
        buttons.grid(row=row, column=0, columnspan=2, sticky=Tkinter.EW)

    def save(self):

        projName = self.proj_name_entry.get()
        directory = self.proj_dir_select.getDirectory()
        directory = joinPath(directory, projName)
        if self.isProjectDirectory(directory):
            if not showOkCancel('Overwrite directory',
                                'Overwrite existing project directory?',
                                parent=self):
                return

        self.updateInfo()

        self.did_save = False
        changeDataLocations = self.dataCheckButton.isSelected()
        done = False
        try:
            done = Io.saveProject(self.project,
                                  newPath=directory,
                                  newProjectName=projName,
                                  createFallback=True,
                                  showYesNo=showYesNo,
                                  changeDataLocations=changeDataLocations,
                                  showWarning=showWarning)

            if done:
                showInfo('Project saved', 'Project saved successfully')
                self.did_save = True
                if self.callback:
                    self.callback(self.project)
            elif self.modal:
                return  # give another chance
        except Implementation.ApiError, e:
            showError('Save project', e.error_msg)
        except IOError, e:
            showError('Save project', str(e))
Example #22
0
class ArchiveProjectPopup(BasePopup):
    """
  **Archive the Project**

  This popup window enables the user to archive the CCPN Project into a gzipped
  tar file.  By default it only includes the *.xml files which reside in the
  project directory.  If the "Include *.xml.bak files" check button is checked
  then it will also include the *.xml.bak files which reside in the project
  directory.  If the "Include data files which are in the project directory"
  check button is checked then it will also include the binary data files
  which reside in the project directory.

  **Caveats & Tips**

  The archive excludes the reference data *.xml files (quite sensibly).
"""
    def __init__(self,
                 parent,
                 project,
                 title='Project : Archive',
                 callback=None,
                 help_msg='',
                 help_url='',
                 dismiss_text='',
                 *args,
                 **kw):

        self.callback = callback
        self.help_msg = help_msg
        self.help_url = help_url
        self.dismiss_text = dismiss_text
        BasePopup.__init__(self,
                           parent=parent,
                           project=project,
                           title=title,
                           *args,
                           **kw)

    def body(self, guiParent):

        now = datetime.date.today().strftime('%y%m%d')
        filePrefix = '%s_%s' % (self.project.name, now)
        projDir = getUserDataPath(self.project)
        directory = os.path.dirname(projDir)

        guiParent.grid_rowconfigure(0, weight=1)
        guiParent.grid_columnconfigure(1, weight=1)

        row = 0
        label = Label(guiParent, text='Archive File:')
        label.grid(row=row, column=0, sticky=Tkinter.E)
        tipText = 'File name (excluding .tgz ending) for archive'
        self.fileEntry = Entry(guiParent, text=filePrefix, tipText=tipText)
        self.fileEntry.grid(row=row, column=1, sticky=Tkinter.EW)
        label = Label(guiParent, text='.tgz (automatically appended)')
        label.grid(row=row, column=2, sticky=Tkinter.W)

        row = row + 1
        self.backupCheck = CheckButton(
            guiParent,
            text='Include *.xml.bak files',
            tipText='If checked include *.xml.bak files')
        self.backupCheck.grid(row=row,
                              column=1,
                              columnspan=2,
                              sticky=Tkinter.W)

        row = row + 1
        self.dataCheck = CheckButton(
            guiParent,
            text='Include data files which are in project directory',
            tipText=
            'If checked include data files if they are located in project directory'
        )
        self.dataCheck.grid(row=row, column=1, columnspan=2, sticky=Tkinter.W)

        row = row + 1
        labelFrame = LabelFrame(guiParent, text='Archive Location')
        labelFrame.grid(row=row, column=0, columnspan=3, sticky=Tkinter.NSEW)
        labelFrame.grid_rowconfigure(0, weight=1)
        labelFrame.grid_columnconfigure(0, weight=1)

        self.dirSelect = FileSelect(labelFrame,
                                    directory=directory,
                                    show_file=False)
        self.dirSelect.grid(row=0, column=0, sticky=Tkinter.NSEW)

        guiParent.grid_rowconfigure(row, weight=1)

        row = row + 1
        texts = ['Save']
        tipTexts = ['Create archive file']
        commands = [self.save]
        buttons = createDismissHelpButtonList(guiParent,
                                              texts=texts,
                                              tipTexts=tipTexts,
                                              commands=commands,
                                              help_msg=self.help_msg,
                                              help_url=self.help_url,
                                              dismiss_text=self.dismiss_text,
                                              expands=True)
        buttons.grid(row=row, column=0, columnspan=3, sticky=Tkinter.EW)

    def save(self):

        filePrefix = self.fileEntry.get()
        directory = self.dirSelect.getDirectory()
        filePrefix = joinPath(directory, filePrefix)
        fileName = filePrefix + '.tgz'

        if os.path.exists(fileName):
            if not showYesNo('File exists',
                             'File "%s" exists, overwrite?' % fileName,
                             parent=self):
                return

        includeBackups = self.backupCheck.isSelected()
        includeData = self.dataCheck.isSelected()
        packageProject(self.project, filePrefix, includeBackups, includeData)
Example #23
0
class FilterCloudsPopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.guiParent = parent
        self.structure = None
        self.name = None
        self.clouds = []
        self.rmsds = []
        self.names = []
        self.atomTypes = None
        self.waiting = 0

        BasePopup.__init__(self, parent=parent, title="Filter Clouds", **kw)

    def body(self, guiFrame):

        row = 0
        guiFrame.grid_columnconfigure(3, weight=1)

        label = Label(guiFrame, text='Cloud file names:')
        label.grid(row=row, column=0, sticky=Tkinter.W)
        self.fileNameEntry = Entry(guiFrame,
                                   text='testHistone\d+.pdb',
                                   returnCallback=self.loadClouds)
        self.fileNameEntry.grid(row=row, column=1, sticky=Tkinter.W)

        strucLabel = Label(guiFrame, text='Comparison structure')
        strucLabel.grid(row=row, column=2, sticky=Tkinter.W)
        self.strucPulldown = PulldownMenu(guiFrame,
                                          entries=self.getStructures(),
                                          callback=self.setStructure,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.strucPulldown.grid(row=row, column=3, sticky=Tkinter.W)

        row += 1
        sdTolLabel = Label(guiFrame, text='Tolerance (SDs):')
        sdTolLabel.grid(row=row, column=0, sticky=Tkinter.W)
        self.sdToleranceEntry = FloatEntry(guiFrame, text=2.0, width=6)
        self.sdToleranceEntry.grid(row=row, column=1, stick=Tkinter.W)

        atomTypes = ['All', 'H', 'H HA', 'H HA HB']
        label = Label(guiFrame, text='RMSD Atom Types:')
        label.grid(row=row, column=2, sticky=Tkinter.W)
        self.atomsPulldown = PulldownMenu(guiFrame,
                                          entries=atomTypes,
                                          callback=self.setAtomTypes,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.atomsPulldown.grid(row=row, column=3, sticky=Tkinter.W)

        row += 1
        guiFrame.grid_rowconfigure(row, weight=1)
        colHeadings = ['#', 'File name', 'RMSD to mean']
        self.scrolledMatrix = ScrolledMatrix(guiFrame,
                                             initialRows=10,
                                             headingList=colHeadings,
                                             callback=self.selectCell,
                                             objectList=[],
                                             textMatrix=[
                                                 [],
                                             ],
                                             multiSelect=1)
        self.scrolledMatrix.grid(row=row,
                                 column=0,
                                 columnspan=4,
                                 sticky=Tkinter.NSEW)

        row += 1
        texts = [
            'Load\nClouds', 'Align\nClouds', 'Calc\nRMSD',
            'Make Cloud\nfrom structure', 'Remove', 'Remove\nbad'
        ]
        commands = [
            self.loadClouds, self.alignClouds, self.calcRmsd,
            self.makeStrucCloud, self.deleteClouds, self.filterClouds
        ]
        self.bottomButtons = createDismissHelpButtonList(
            guiFrame,
            texts=texts,
            expands=1,
            commands=commands,
            help_url=self.help_url)
        self.bottomButtons.grid(row=row,
                                column=0,
                                columnspan=4,
                                sticky=Tkinter.NSEW)
        self.update()

    def alignClouds(self):

        pattern = self.fileNameEntry.get()
        self.names = getFileNamesFromPattern(pattern, '.')
        self.clouds = getCloudsFromFile(self.names, self.guiParent.project)
        alignClouds(self.clouds, self.names)

    def loadClouds(self):

        pattern = self.fileNameEntry.get()
        self.names = getFileNamesFromPattern(pattern, '.')
        self.clouds = getCloudsFromFile(self.names, self.guiParent.project)
        self.name = None
        self.rmsds = [None for x in range(len(self.clouds))]
        self.updateAfter()

    def getStructures(self):

        names = [
            '<None>',
        ]
        for molSystem in self.project.sortedMolSystems():
            for structure in molSystem.sortedStructureEnsembles():
                names.append('%s:%d' % (molSystem.name, structure.ensembleId))

        return names

    def setStructure(self, index, name=None):

        if index < 1:
            self.structure = None
        else:
            structures = []
            for molSystem in self.project.molSystems:
                for structure in molSystem.structures:
                    structures.append(structure)

            self.structure = structures[index - 1]

        self.updateButtons()

    def setAtomTypes(self, index, name=None):

        self.atomTypes = atomTypeList[index]

    def filterClouds(self):

        if self.clouds:
            sdTolerance = self.sdToleranceEntry.get() or 2.0
            keptClouds = []

            meanRmsd = 0.0
            N = 0
            for rmsd in self.rmsds:
                meanRmsd += rmsd or 0.0
                N += 1

            if N > 0:
                meanRmsd /= float(N)

            sd = 0.0
            for r in self.rmsds:
                rmsd = r or 0.0
                sd += (rmsd - meanRmsd) * (rmsd - meanRmsd)

            if N > 0:
                sd /= float(N - 1)

            sd = sqrt(sd)

            print meanRmsd, '+/-', sd

            for i in range(len(self.clouds), 0, -1):
                rmsd = self.rmsds[i]
                if abs(rmsd - meanRmsd) > (sdTolerance * sd):
                    self.rmsds.pop(i)
                    self.names.pop(i)
                    self.clouds.pop(i)
                    #print 'Cloud %s is bad' % (cloud)

            self.updateAfter()

    def makeStrucCloud(self):

        if self.structure and self.clouds:
            pdbFileName = 'CloudForStructure.pdb'
            atomCoordList = []
            atomCoordList0 = []
            resDict = {}
            hmass = 25
            resonances = self.clouds[0].keys()
            resonances2 = []

            C = 0
            for resonance in resonances:
                if resonance == 'rmsd':
                    continue

                resonanceSet = resonance.resonanceSet
                if resonanceSet:
                    i = list(resonanceSet.resonances).index(resonance)
                    atomSet = list(resonance.resonanceSet.atomSets)[i]
                    coords = getAtomSetCoords(atomSet, self.structure)
                    coord = coords[0]
                    atomCoordList.append([coord.x, coord.y, coord.z])
                    atomCoordList0.append([coord.x, coord.y, coord.z])
                    resonances2.append(resonance)

                    C += 1

            print len(atomCoordList)
            print len(resonances), len(resonances2)

            print "Generating Mean"
            cloudsList = []
            for cloud in self.clouds:
                orderCloud = []
                for resonance in resonances2:
                    x, y, z = cloud.get(resonance) or (0.0, 0.0, 0.0)

                    orderCloud.append([-x, -y, -z])
                cloudsList.append(orderCloud)
            (meanCloud, cloudsList) = alignToMeanCloud(cloudsList)

            weights = [1.0 for x in atomCoordList]
            centerCoords(atomCoordList)
            print "init cen", getMeanCoords(atomCoordList)
            print "mean cen", getMeanCoords(meanCloud)

            print "Print aligning struct clouds to mean", len(meanCloud), len(
                atomCoordList), len(weights)
            atomCoordsList, error, rotMat = alignCoordinates(
                meanCloud, atomCoordList, weights)

            print "  Rotation", rotMat
            writeTypedPdbCloud(atomCoordList, pdbFileName, resonances2)

            print "Getting centres"
            oldCentre = getMeanCoords(atomCoordList0)
            newCentre = getMeanCoords(atomCoordList)
            delta = [
                newCentre[i] - oldCentre[i] for i in range(len(oldCentre))
            ]

            print "  New centre", newCentre
            print "  Old centre", oldCentre
            print "  Delta", delta

            #inverseRot = inverseMatrix(rotMat)

            model = self.structure.findFirstModel()
            coordinates = model.coordinates
            offset = 0
            iis = (0, 1, 2)
            for atom in self.structure.orderedAtoms:
                next = offset + 3
                coords = [coordinates[offset + ii] + delta[ii] for ii in iis]
                coords = matrixVecMultiply(rotMat, coords)
                coordinates[offset:next] = coords
                offset = next
            model.setSubmatrixData('coordinates', coordinates)

            clouds = getCloudsFromFile([
                pdbFileName,
            ], self.structure.root)
            self.clouds.append(clouds[0])
            self.rmsds.append(None)
            self.names.append(pdbFileName)

            self.updateAfter()

    def calcRmsd(self):

        if self.clouds:

            if len(self.scrolledMatrix.currentObjects) < 2:
                clouds = self.clouds
            else:
                clouds = []
                for name in self.scrolledMatrix.currentObjects:
                    clouds.append(self.clouds[self.names.index(name)])

            self.rmsds = filterClouds(clouds, atomTypes=self.atomTypes)
            self.updateAfter()

    def deleteClouds(self):

        if self.names and self.name and showOkCancel(
                'Confirm', 'Really remove selected clouds?'):
            indices = []
            for name in self.scrolledMatrix.currentObjects:
                i = self.names.index(name)
                indices.append(i)
            indices.sort()
            indices.reverse()

            for i in indices:
                self.clouds.pop(i)
                self.rmsds.pop(i)
                self.names.pop(i)

            self.name = None
            self.updateAfter()

    def selectCell(self, name, row, col):

        self.name = name
        self.updateButtons()

    def updateAfter(self, *opt):

        if self.waiting:
            return
        else:
            self.waiting = 1
            self.after_idle(self.update)

    def destroy(self):

        BasePopup.destroy(self)

    def updateButtons(self):

        if self.names:
            self.bottomButtons.buttons[1].enable()
            self.bottomButtons.buttons[2].enable()
            self.bottomButtons.buttons[5].enable()
        else:
            self.bottomButtons.buttons[1].disable()
            self.bottomButtons.buttons[2].enable()
            self.bottomButtons.buttons[5].disable()

        if self.name:
            self.bottomButtons.buttons[4].enable()
        else:
            self.bottomButtons.buttons[4].disable()

        if self.structure and self.clouds:
            self.bottomButtons.buttons[3].enable()
        else:
            self.bottomButtons.buttons[3].disable()

    def update(self):

        textMatrix = []
        objectList = self.names
        self.updateButtons()

        i = 0
        for name in objectList:
            datum = []
            datum.append(i + 1)
            datum.append(name)
            datum.append(self.rmsds[i])
            textMatrix.append(datum)
            i += 1

        if not objectList:
            textMatrix = [
                [],
            ]

        self.scrolledMatrix.update(objectList=objectList,
                                   textMatrix=textMatrix)
        self.waiting = 0
Example #24
0
class CloudsPopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.guiParent = parent
        self.project = parent.getProject()
        self.waiting = 0
        self.specFreq = 800.13
        self.maxIter = 50
        self.mixTime = 60
        self.corrTime = 11.5
        self.leakRate = 2.0
        self.peakListDict = {}
        self.noesyPeakList = None
        self.tocsyPeakList = None
        self.noesy3dPeakList = None
        self.hsqcPeakList = None
        self.maxIntens = 37000000

        self.resonances = None
        self.origResonances = None
        self.noesyPeaks = None
        self.distanceConstraintList = None
        self.antiDistConstraintList = None
        self.numClouds = 100
        self.filePrefix = 'cloud_'
        self.cloudsFiles = []
        self.adcAtomTypes = 'HN'
        self.structure = None

        # step num, initial temp, final temp, cooling steps, MD steps, MD tau, rep scale
        self.coolingScheme = []
        self.coolingScheme.append([1, 1, 1, 3, 500, 0.001, 0])
        self.coolingScheme.append([2, 80000, 4000, 19, 1000, 0.001, 0])
        self.coolingScheme.append([3, 4000, 1, 5, 500, 0.001, 0])
        self.coolingScheme.append([4, 15000, 1, 3, 1000, 0.001, 0])
        self.coolingScheme.append([5, 1, 1, 5, 500, 0.001, 0])
        self.coolingScheme.append([6, 8000, 1, 3, 1000, 0.001, 0])
        self.coolingScheme.append([7, 1, 1, 5, 500, 0.001, 0])
        self.coolingScheme.append([8, 3000, 25, 60, 2500, 0.001, 1])
        self.coolingScheme.append([9, 25, 25, 1, 7500, 0.001, 1])
        self.coolingScheme.append([10, 10, 10, 1, 7500, 0.001, 1])
        self.coolingScheme.append([11, 0.01, 0.01, 1, 7500, 0.0005, 1])

        self.coolingStep = None

        BasePopup.__init__(self,
                           parent,
                           title="Resonance Clouds Analysis",
                           **kw)

    def body(self, guiFrame):

        self.specFreqEntry = IntEntry(self,
                                      text=self.specFreq,
                                      width=8,
                                      returnCallback=self.setSpecFreq)
        self.maxIterEntry = IntEntry(self,
                                     text=self.maxIter,
                                     width=8,
                                     returnCallback=self.setMaxIter)
        self.mixTimeEntry = FloatEntry(self,
                                       text=self.mixTime,
                                       width=8,
                                       returnCallback=self.setMixTime)
        self.corrTimeEntry = FloatEntry(self,
                                        text=self.corrTime,
                                        width=8,
                                        returnCallback=self.setCorrTime)
        self.leakRateEntry = FloatEntry(self,
                                        text=self.leakRate,
                                        width=8,
                                        returnCallback=self.setLeakRate)
        self.maxIntensEntry = IntEntry(self,
                                       text=self.maxIntens,
                                       width=8,
                                       returnCallback=self.setMaxIntens)

        self.mdInitTempEntry = FloatEntry(self,
                                          text='',
                                          returnCallback=self.setMdInitTemp)
        self.mdFinTempEntry = FloatEntry(self,
                                         text='',
                                         returnCallback=self.setMdFinTemp)
        self.mdCoolStepsEntry = IntEntry(self,
                                         text='',
                                         returnCallback=self.setMdCoolSteps)
        self.mdSimStepsEntry = IntEntry(self,
                                        text='',
                                        returnCallback=self.setMdSimSteps)
        self.mdTauEntry = FloatEntry(self,
                                     text='',
                                     returnCallback=self.setMdTau)
        self.mdRepScaleEntry = FloatEntry(self,
                                          text='',
                                          returnCallback=self.setMdRepScale)

        guiFrame.grid_columnconfigure(0, weight=1)

        row = 0
        frame0 = LabelFrame(guiFrame, text='Setup peak lists')
        frame0.grid(row=row, column=0, sticky=Tkinter.NSEW)
        frame0.grid(row=row, column=0, sticky=Tkinter.NSEW)
        frame0.grid_columnconfigure(1, weight=1)

        f0row = 0
        label00 = Label(frame0, text='1H-1H NOESY spectrum')
        label00.grid(row=f0row, column=0, sticky=Tkinter.NW)
        self.noesyPulldown = PulldownMenu(frame0,
                                          entries=self.getNoesys(),
                                          callback=self.setNoesy,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.noesyPulldown.grid(row=f0row, column=1, sticky=Tkinter.NW)

        f0row += 1
        label01 = Label(frame0, text='15N HSQC spectrum')
        label01.grid(row=f0row, column=0, sticky=Tkinter.NW)
        self.hsqcPulldown = PulldownMenu(frame0,
                                         entries=self.getHsqcs(),
                                         callback=self.setHsqc,
                                         selected_index=0,
                                         do_initial_callback=0)
        self.hsqcPulldown.grid(row=f0row, column=1, sticky=Tkinter.NW)

        f0row += 1
        label02 = Label(frame0, text='15N HSQC TOCSY spectrum')
        label02.grid(row=f0row, column=0, sticky=Tkinter.NW)
        self.tocsyPulldown = PulldownMenu(frame0,
                                          entries=self.getTocsys(),
                                          callback=self.setTocsy,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.tocsyPulldown.grid(row=f0row, column=1, sticky=Tkinter.NW)

        f0row += 1
        label02 = Label(frame0, text='15N HSQC NOESY spectrum')
        label02.grid(row=f0row, column=0, sticky=Tkinter.NW)
        self.noesy3dPulldown = PulldownMenu(frame0,
                                            entries=self.getNoesy3ds(),
                                            callback=self.setNoesy3d,
                                            selected_index=0,
                                            do_initial_callback=0)
        self.noesy3dPulldown.grid(row=f0row, column=1, sticky=Tkinter.NW)

        f0row += 1
        texts = ['Setup resonances & peaks', 'Show Peaks', 'Show resonances']
        commands = [self.setupResonances, self.showPeaks, self.showResonances]
        self.setupButtons = ButtonList(frame0,
                                       expands=1,
                                       texts=texts,
                                       commands=commands)
        self.setupButtons.grid(row=f0row,
                               column=0,
                               columnspan=2,
                               sticky=Tkinter.NSEW)

        f0row += 1
        self.label03a = Label(frame0, text='Resonances found: 0')
        self.label03a.grid(row=f0row, column=0, sticky=Tkinter.NW)
        self.label03b = Label(frame0, text='NOESY peaks found: 0')
        self.label03b.grid(row=f0row, column=1, sticky=Tkinter.NW)

        row += 1
        frame1 = LabelFrame(guiFrame, text='Calculate distance constraints')
        frame1.grid(row=row, column=0, sticky=Tkinter.NSEW)
        frame1.grid_columnconfigure(3, weight=1)

        f1row = 0
        frame1.grid_rowconfigure(f1row, weight=1)
        data = [
            self.specFreq, self.maxIter, self.mixTime, self.corrTime,
            self.leakRate, self.maxIntens
        ]
        colHeadings = [
            'Spectrometer\nfrequency', 'Max\niterations', 'Mixing\ntime (ms)',
            'Correl.\ntime (ns)', 'Leak\nrate', 'Max\nintensity'
        ]
        editWidgets = [
            self.specFreqEntry,
            self.maxIterEntry,
            self.mixTimeEntry,
            self.corrTimeEntry,
            self.leakRateEntry,
            self.maxIntensEntry,
        ]
        editGetCallbacks = [
            self.getSpecFreq,
            self.getMaxIter,
            self.getMixTime,
            self.getCorrTime,
            self.getLeakRate,
            self.getMaxIntens,
        ]
        editSetCallbacks = [
            self.setSpecFreq,
            self.setMaxIter,
            self.setMixTime,
            self.setCorrTime,
            self.setLeakRate,
            self.setMaxIntens,
        ]
        self.midgeParamsMatrix = ScrolledMatrix(
            frame1,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            editWidgets=editWidgets,
            maxRows=1,
            initialCols=5,
            headingList=colHeadings,
            callback=None,
            objectList=[
                'None',
            ],
            textMatrix=[
                data,
            ])
        self.midgeParamsMatrix.grid(row=f1row,
                                    column=0,
                                    columnspan=4,
                                    sticky=Tkinter.NSEW)

        f1row += 1
        label10 = Label(frame1, text='Benchmark structure')
        label10.grid(row=f1row, column=0, sticky=Tkinter.NW)
        self.structurePulldown = PulldownMenu(frame1,
                                              entries=self.getStructures(),
                                              callback=self.setStructure,
                                              selected_index=0,
                                              do_initial_callback=0)
        self.structurePulldown.grid(row=f1row, column=1, sticky=Tkinter.NW)

        label11 = Label(frame1, text='ADC atom types:')
        label11.grid(row=f1row, column=2, sticky=Tkinter.NW)
        self.adcAtomsPulldown = PulldownMenu(frame1,
                                             entries=self.getAdcAtomTypes(),
                                             callback=self.setAdcAtomTypes,
                                             selected_index=0,
                                             do_initial_callback=0)
        self.adcAtomsPulldown.grid(row=f1row, column=3, sticky=Tkinter.NW)

        f1row += 1
        texts = [
            'Calculate distances', 'Show distance\nconstraints',
            'Show anti-distance\nconstraints'
        ]
        commands = [
            self.calculateDistances, self.showConstraints,
            self.showAntiConstraints
        ]
        self.midgeButtons = ButtonList(frame1,
                                       expands=1,
                                       texts=texts,
                                       commands=commands)
        self.midgeButtons.grid(row=f1row,
                               column=0,
                               columnspan=4,
                               sticky=Tkinter.NSEW)

        f1row += 1
        self.distConstrLabel = Label(frame1, text='Distance constraints:')
        self.distConstrLabel.grid(row=f1row,
                                  column=0,
                                  columnspan=2,
                                  sticky=Tkinter.NW)
        self.antiConstrLabel = Label(frame1, text='Anti-distance constraints:')
        self.antiConstrLabel.grid(row=f1row,
                                  column=2,
                                  columnspan=2,
                                  sticky=Tkinter.NW)

        row += 1
        guiFrame.grid_rowconfigure(row, weight=1)
        frame2 = LabelFrame(guiFrame, text='Proton cloud molecular dynamics')
        frame2.grid(row=row, column=0, sticky=Tkinter.NSEW)
        frame2.grid_columnconfigure(1, weight=1)

        f2row = 0
        frame2.grid_rowconfigure(f2row, weight=1)
        data = [
            self.specFreq, self.maxIter, self.mixTime, self.corrTime,
            self.leakRate
        ]
        colHeadings = [
            'Step', 'Initial temp.', 'Final temp.', 'Cooling steps',
            'MD steps', 'MD tau', 'Rep. scale'
        ]
        editWidgets = [
            None, self.mdInitTempEntry, self.mdFinTempEntry,
            self.mdCoolStepsEntry, self.mdSimStepsEntry, self.mdTauEntry,
            self.mdRepScaleEntry
        ]
        editGetCallbacks = [
            None, self.getMdInitTemp, self.getMdFinTemp, self.getMdCoolSteps,
            self.getMdSimSteps, self.getMdTau, self.getMdRepScale
        ]
        editSetCallbacks = [
            None, self.setMdInitTemp, self.setMdFinTemp, self.setMdCoolSteps,
            self.setMdSimSteps, self.setMdTau, self.setMdRepScale
        ]
        self.coolingSchemeMatrix = ScrolledMatrix(
            frame2,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            editWidgets=editWidgets,
            maxRows=9,
            initialRows=12,
            headingList=colHeadings,
            callback=self.selectCoolingStep,
            objectList=self.coolingScheme,
            textMatrix=self.coolingScheme)
        self.coolingSchemeMatrix.grid(row=f2row,
                                      column=0,
                                      columnspan=4,
                                      sticky=Tkinter.NSEW)

        f2row += 1
        texts = ['Move earlier', 'Move later', 'Add step', 'Remove step']
        commands = [
            self.moveStepEarlier, self.moveStepLater, self.addCoolingStep,
            self.removeCoolingStep
        ]
        self.coolingSchemeButtons = ButtonList(frame2,
                                               expands=1,
                                               commands=commands,
                                               texts=texts)
        self.coolingSchemeButtons.grid(row=f2row,
                                       column=0,
                                       columnspan=4,
                                       sticky=Tkinter.EW)

        f2row += 1
        label20 = Label(frame2, text='Number of clouds:')
        label20.grid(row=f2row, column=0, sticky=Tkinter.NW)
        self.numCloudsEntry = FloatEntry(frame2,
                                         text=100,
                                         returnCallback=self.setNumClouds,
                                         width=10)
        self.numCloudsEntry.grid(row=f2row, column=1, sticky=Tkinter.NW)
        label21 = Label(frame2, text='Cloud file prefix:')
        label21.grid(row=f2row, column=2, sticky=Tkinter.NW)
        self.filePrefixEntry = Entry(frame2,
                                     text='cloud_',
                                     returnCallback=self.setFilePrefix,
                                     width=10)
        self.filePrefixEntry.grid(row=f2row, column=3, sticky=Tkinter.NW)

        f2row += 1
        texts = ['Start molecular dynamics', 'Show dynamics progress']
        commands = [self.startMd, self.showMdProgress]
        self.mdButtons = ButtonList(frame2,
                                    expands=1,
                                    commands=commands,
                                    texts=texts)
        self.mdButtons.grid(row=f2row,
                            column=0,
                            columnspan=4,
                            sticky=Tkinter.NSEW)

        row += 1
        self.bottomButtons = createDismissHelpButtonList(guiFrame,
                                                         expands=0,
                                                         help_url=None)
        self.bottomButtons.grid(row=row, column=0, sticky=Tkinter.EW)

        self.setButtonStates()

    def getStructures(self):

        names = [
            '<None>',
        ]
        for molSystem in self.project.sortedMolSystems():
            for structure in molSystem.sortedStructureEnsembles():
                names.append('%s:%d' % (molSystem.name, structure.ensembleId))

        return names

    def setStructure(self, index, name=None):

        if index < 1:
            self.structure = None
        else:
            structures = []
            for molSystem in self.project.molSystems:
                for structure in molSystem.structureEnsembles:
                    structures.append(structure)

            self.structure = structures[index - 1]

    def getAdcAtomTypes(self):

        return ['HN', 'HN HA', 'HN HA HB']

    def setAdcAtomTypes(self, index, name=None):

        if name is None:
            name = self.adcAtomsPulldown.getSelected()

        self.adcAtomTypes = name

    def startMd(self):

        self.setNumClouds()
        self.setFilePrefix()
        if (self.distanceConstraintList and self.antiDistConstraintList
                and (self.numClouds > 0) and self.filePrefix):

            resDict = {}
            for resonance in self.guiParent.project.currentNmrProject.resonances:
                resDict[resonance.serial] = resonance

            resonances = []
            for constraint in self.distanceConstraintList.constraints:
                for item in constraint.items:
                    for fixedResonance in item.resonances:
                        if resDict.get(
                                fixedResonance.resonanceSerial) is not None:
                            resonances.append(
                                resDict[fixedResonance.resonanceSerial])
                            resDict[fixedResonance.resonanceSerial] = None

            startMdProcess(self.numClouds, self.distanceConstraintList,
                           resonances, self.coolingScheme, self.filePrefix)

            #structGen = self.distanceConstraintList.structureGeneration

            serials = []
            for resonance in resonances:
                serials.append(resonance.serial)
            clouds = []
            for i in range(self.numClouds):
                clouds.append('%s%3.3d.pdb' % (self.filePrefix, i))
            self.guiParent.application.setValues(
                self.distanceConstraintList.nmrConstraintStore,
                'clouds',
                values=clouds)
            self.guiParent.application.setValues(
                self.distanceConstraintList.nmrConstraintStore,
                'cloudsResonances',
                values=serials)

            # do better than this check for creation

    def showMdProgress(self):

        n = 0
        m = self.numClouds
        for i in range(m):
            pdbFileName = '%s%3.3d.pdb' % (self.filePrefix, i)
            if os.path.exists(pdbFileName):
                n += 1

        p = n * 100 / float(m)
        text = 'Done %d of %d clouds (%1.2f)%%' % (n, m, p)
        showInfo('MD Progress', text)

    def setFilePrefix(self, text=None):

        if not text:
            text = self.filePrefixEntry.get()

        if text:
            self.filePrefix = text

    def setNumClouds(self, n=None, *event):

        if not n:
            n = self.numCloudsEntry.get()

        if n:
            self.numClouds = int(n)

    def calculateDistances(self):

        # setup normalisation factor intensityMax

        # self.maxIter
        # what if failure ?

        resDict = {}
        for resonance in self.project.currentNmrProject.resonances:
            resDict[resonance.serial] = resonance

        self.resonances = self.origResonances
        intensityFactors = [1.0 for x in range(len(self.resonances))]

        # optimiseRelaxation will remove unconstrained resonances
        self.distanceConstraintList = optimiseRelaxation(
            self.resonances,
            self.noesyPeaks,
            intensityMax=self.maxIntens,
            intensityFactors=intensityFactors,
            tmix=self.mixTime,
            sf=self.specFreq,
            tcor=self.corrTime,
            rleak=self.leakRate)

        constrainSpinSystems(self.distanceConstraintList)
        # for testing calculate distances from structure overrides any resonances: uses assigned ones
        #(self.distanceConstraintList, self.resonances) = self.cheatForTesting()
        #self.antiDistConstraintList = self.distanceConstraintList
        protonNumbs = {'CH3': 3, 'Haro': 2, 'HN': 1, 'H': 1}

        PI = 3.1415926535897931
        GH = 2.6752e4
        HB = 1.05459e-27
        CONST = GH * GH * GH * GH * HB * HB
        tc = 1.0e-9 * self.corrTime
        wh = 2.0 * PI * self.specFreq * 1.0e6
        j0 = CONST * tc
        j1 = CONST * tc / (1.0 + wh * wh * tc * tc)
        j2 = CONST * tc / (1.0 + 4.0 * wh * wh * tc * tc)
        #jself = 6.0*j2 + 3.0*j1 + j0
        jcross = 6.0 * j2 - j0

        if self.distanceConstraintList:
            constraintStore = self.distanceConstraintList.nmrConstraintStore

            dict = {
                'HN': ['H'],
                'HN HA': ['H', 'HA', 'HA1', 'HA2'],
                'HN HA HB': ['H', 'HA', 'HA1', 'HA2', 'HB', 'HB2', 'HB3']
            }

            self.antiDistConstraintList = makeNoeAdcs(
                self.resonances,
                self.noesyPeakList.dataSource,
                constraintStore,
                allowedAtomTypes=dict[self.adcAtomTypes])

            if self.structure:

                N = len(self.resonances)
                sigmas = [[] for i in range(N)]
                for i in range(N):
                    sigmas[i] = [0.0 for j in range(N)]

                for constraint in self.distanceConstraintList.constraints:
                    resonances = list(constraint, findFirstItem().resonances)

                    ri = resDict[resonances[0].resonanceSerial]
                    rj = resDict[resonances[1].resonanceSerial]
                    i = self.resonances.index(ri)
                    j = self.resonances.index(rj)
                    atomSets1 = list(ri.resonanceSet.atomSets)
                    atomSets2 = list(rj.resonanceSet.atomSets)
                    if atomSets1 == atomSets2:
                        ass = list(atomSets1)
                        atomSets1 = [
                            ass[0],
                        ]
                        atomSets2 = [
                            ass[-1],
                        ]

                    distance = getAtomSetsDistance(atomSets1, atomSets2,
                                                   self.structure)
                    r = distance * 1e-8
                    nhs = protonNumbs[rj.name]
                    sigma = 0.1 * jcross * nhs / (r**6)
                    sigmas[i][j] = sigma

                    constraint.setDetails('Known Dist: %4.3f' % (distance))
                    #for constraint in self.antiDistConstraintList.constraints:
                    #  atomSets1 = list(resonances[0].resonanceSet.atomSets)
                    #  atomSets2 = list(resonances[1].resonanceSet.atomSets)
                    #  distance = getAtomSetsDistance(atomSets1, atomSets2, self.structure)
                    #  constraint.setDetails('Known Dist: %4.3f' % (distance))

                fp = open('sigmas.out', 'w')
                for i in range(N - 1):
                    for j in range(i + 1, N):
                        if sigmas[i][j] != 0.0:
                            fp.write('%3.1d  %3.1d   %9.2e\n' %
                                     (i, j, sigmas[i][j]))
                    #fp.write('\n')
                fp.close()

        self.setButtonStates()

    def cheatForTesting(self, atomSelection='H'):
        """ Makes a perfect cloud from a structure. """

        project = self.project
        structure = self.guiParent.argumentServer.getStructure()

        constraintStore = makeNmrConstraintStore(project)
        distConstraintList = NmrConstraint.DistanceConstraintList(
            constraintStore)

        chain = structure.findFirstCoodChain()
        structureGeneration.hydrogenResonances = []

        molSystem = structure.molSystem
        atomSets = []
        resonances = []
        i = 0
        for resonance in project.currentNmrProject.resonances:

            if resonance.isotopeCode == '1H':

                if resonance.resonanceSet:

                    atomSet = resonance.resonanceSet.findFirstAtomSet()
                    atom = atomSet.findFirstAtom()
                    seqId = atom.residue.seqId
                    if (seqId < 9) or (seqId > 78):
                        continue

                    if atom.residue.chain.molSystem is molSystem:

                        if atomSelection == 'methyl':
                            if len(atomSet.atoms) == 3:
                                if atom.residue.ccpCode not in ('Ala', 'Val',
                                                                'Ile', 'Leu',
                                                                'Thr', 'Met'):
                                    continue
                            elif atom.name != 'H':
                                continue

                        elif atomSelection == 'amide':
                            if atom.name != 'H':
                                continue

                        if atom.name == 'H':
                            resonance.name = 'HN'
                        else:
                            resonance.name = 'H'

                        resonances.append(resonance)
                        atomSets.append(list(resonance.resonanceSet.atomSets))
                        i += 1

        print "Found %d atomSets" % (len(atomSets))
        weight = 1
        adcWeight = 1
        constrDict = {}
        N = len(atomSets)
        for i in range(N - 1):
            atomSets0 = atomSets[i]
            residue0 = atomSets0[0].findFirstAtom().residue.seqId
            print "R", residue0

            for j in range(i + 1, N):
                if j == i:
                    continue
                atomSets1 = atomSets[j]

                dist = getAtomSetsDistance(atomSets0, atomSets1, structure)
                if not dist:
                    continue

                if dist < 5.5:
                    fixedResonance0 = getFixedResonance(
                        constraintStore, resonances[i])
                    fixedResonance1 = getFixedResonance(
                        constraintStore, resonances[j])
                    constrDict[i] = 1
                    constrDict[j] = 1
                    constraint = NmrConstraint.DistanceConstraint(
                        distConstraintList,
                        weight=weight,
                        targetValue=dist,
                        upperLimit=dist + (dist / 10),
                        lowerLimit=dist - (dist / 10),
                        error=dist / 5)
                    item = NmrConstraint.DistanceConstraintItem(
                        constraint,
                        resonances=[fixedResonance0, fixedResonance1])

                elif (atomSets1[0].findFirstAtom().name
                      == 'H') and (atomSets0[0].findFirstAtom().name
                                   == 'H') and (dist > 7):
                    #else:
                    fixedResonance0 = getFixedResonance(
                        constraintStore, resonances[i])
                    fixedResonance1 = getFixedResonance(
                        constraintStore, resonances[j])
                    constrDict[i] = 1
                    constrDict[j] = 1
                    constraint = NmrConstraint.DistanceConstraint(
                        distConstraintList,
                        weight=adcWeight,
                        targetValue=75,
                        upperLimit=175,
                        lowerLimit=5.0,
                        error=94.5)
                    item = NmrConstraint.DistanceConstraintItem(
                        constraint,
                        resonances=[fixedResonance0, fixedResonance1])

        return (distConstraintList, resonances)

    def showConstraints(self):

        if self.distanceConstraintList:
            self.guiParent.browseConstraints(
                constraintList=self.distanceConstraintList)

    def showAntiConstraints(self):

        if self.antiDistConstraintList:
            self.guiParent.browseConstraints(
                constraintList=self.antiDistConstraintList)

    def showPeaks(self):

        self.guiParent.viewPeaks(peaks=self.noesyPeaks)

    def showResonances(self):

        pass
        #self.guiParent.viewResonances(resonances=self.resonances)

    def setupResonances(self):

        if self.noesyPeakList and self.noesy3dPeakList and self.tocsyPeakList and self.hsqcPeakList:

            disambiguateNoesyPeaks(self.noesyPeakList, self.noesy3dPeakList,
                                   self.tocsyPeakList, self.hsqcPeakList)

            (self.origResonances, self.noesyPeaks,
             null) = getCloudsResonanceList(self.guiParent.argumentServer,
                                            hsqcPeakList=self.hsqcPeakList,
                                            tocsy3dPeakList=self.tocsyPeakList,
                                            noesy2dPeakList=self.noesyPeakList)
            self.setButtonStates()

    def setButtonStates(self):

        if self.origResonances:
            self.label03a.set('Resonances found: %d' %
                              (len(self.origResonances)))

        if self.noesyPeaks:
            self.label03b.set('NOESY peaks found: %d' % (len(self.noesyPeaks)))

        if self.noesyPeakList and self.tocsyPeakList and self.hsqcPeakList:
            self.setupButtons.buttons[0].enable()
        else:
            self.setupButtons.buttons[0].disable()

        if self.noesyPeaks:
            self.setupButtons.buttons[1].enable()
        else:
            self.setupButtons.buttons[1].disable()

        if self.origResonances:
            self.setupButtons.buttons[2].enable()
        else:
            self.setupButtons.buttons[2].disable()

        if self.noesyPeaks and self.origResonances:
            self.midgeButtons.buttons[0].enable()
        else:
            self.midgeButtons.buttons[0].disable()

        if self.distanceConstraintList:
            self.midgeButtons.buttons[1].enable()
            self.distConstrLabel.set(
                'Distance constraints: %d' %
                len(self.distanceConstraintList.constraints))
        else:
            self.distConstrLabel.set('Distance constraints:')
            self.midgeButtons.buttons[1].disable()

        if self.antiDistConstraintList:
            self.antiConstrLabel.set(
                'Anti-distance constraints: %d' %
                len(self.antiDistConstraintList.constraints))
            self.midgeButtons.buttons[2].enable()
        else:
            self.antiConstrLabel.set('Anti-distance constraints:')
            self.midgeButtons.buttons[2].disable()

        if (self.distanceConstraintList and self.antiDistConstraintList
                and (self.numClouds > 0) and self.filePrefix):
            self.mdButtons.buttons[0].enable()
            self.mdButtons.buttons[1].enable()
        else:
            self.mdButtons.buttons[0].disable()
            self.mdButtons.buttons[1].disable()

    def getNoesys(self):

        names = []
        spectra = getSpectraByType(self.project, '2dNOESY')
        for spectrum in spectra:
            for peakList in spectrum.peakLists:
                name = '%s:%s:%s' % (spectrum.experiment.name, spectrum.name,
                                     peakList.serial)
                names.append(name)
                self.peakListDict[name] = peakList
                if not self.noesyPeakList:
                    self.noesyPeakList = peakList

        return names

    def setNoesy(self, index, name=None):

        if not name:
            name = self.noesyPulldown.getSelected()

        self.noesyPeakList = self.peakListDict[name]
        self.setButtonStates()

    def getTocsys(self):

        names = []
        spectra = getSpectraByType(self.project, '3dTOCSY')
        for spectrum in spectra:
            for peakList in spectrum.peakLists:
                name = '%s:%s:%s' % (spectrum.experiment.name, spectrum.name,
                                     peakList.serial)
                names.append(name)
                self.peakListDict[name] = peakList
                if not self.tocsyPeakList:
                    self.tocsyPeakList = peakList

        return names

    def getNoesy3ds(self):

        names = []
        spectra = getSpectraByType(self.project, '3dNOESY')
        for spectrum in spectra:
            for peakList in spectrum.peakLists:
                name = '%s:%s:%s' % (spectrum.experiment.name, spectrum.name,
                                     peakList.serial)
                names.append(name)
                self.peakListDict[name] = peakList
                if not self.noesy3dPeakList:
                    self.noesy3dPeakList = peakList

        return names

    def setTocsy(self, index, name=None):

        if not name:
            name = self.tocsyPulldown.getSelected()

        self.tocsyPeakList = self.peakListDict[name]
        self.setButtonStates()

    def setNoesy3d(self, index, name=None):

        if not name:
            name = self.noesy3dPulldown.getSelected()

        self.noesy3dPeakList = self.peakListDict[name]
        self.setButtonStates()

    def getHsqcs(self):

        names = []
        spectra = getSpectraByType(self.project, 'HSQC')
        for spectrum in spectra:
            for peakList in spectrum.peakLists:
                name = '%s:%s:%s' % (spectrum.experiment.name, spectrum.name,
                                     peakList.serial)
                names.append(name)
                self.peakListDict[name] = peakList
                if not self.hsqcPeakList:
                    self.hsqcPeakList = peakList

        return names

    def setHsqc(self, index, name=None):

        if not name:
            name = self.hsqcPulldown.getSelected()

        self.hsqcPeakList = self.peakListDict[name]
        self.setButtonStates()

    def getMdInitTemp(self, coolingStep):

        self.mdInitTempEntry.set(coolingStep[1])

    def getMdFinTemp(self, coolingStep):

        self.mdFinTempEntry.set(coolingStep[2])

    def getMdCoolSteps(self, coolingStep):

        self.mdCoolStepsEntry.set(coolingStep[3])

    def getMdSimSteps(self, coolingStep):

        self.mdSimStepsEntry.set(coolingStep[4])

    def getMdTau(self, coolingStep):

        self.mdTauEntry.set(coolingStep[5])

    def getMdRepScale(self, coolingStep):

        self.mdRepScaleEntry.set(coolingStep[6])

    def setMdInitTemp(self, event):

        value = self.mdInitTempEntry.get()
        if value is not None:
            self.coolingStep[1] = value

        self.updateCoolingScheme()

    def setMdFinTemp(self, event):

        value = self.mdFinTempEntry.get()
        if value is not None:
            self.coolingStep[2] = value

        self.updateCoolingScheme()

    def setMdCoolSteps(self, event):

        value = self.mdCoolStepsEntry.get()
        if value is not None:
            self.coolingStep[3] = value

        self.updateCoolingScheme()

    def setMdSimSteps(self, event):

        value = self.mdSimStepsEntry.get()
        if value is not None:
            self.coolingStep[4] = value

        self.updateCoolingScheme()

    def setMdTau(self, event):

        value = self.mdTauEntry.get()
        if value is not None:
            self.coolingStep[5] = value

        self.updateCoolingScheme()

    def setMdRepScale(self, event):

        value = self.mdRepScaleEntry.get()
        if value is not None:
            self.coolingStep[6] = value

        self.updateCoolingScheme()

    def selectCoolingStep(self, object, row, col):

        self.coolingStep = object

    def moveStepEarlier(self):

        if self.coolingStep:
            i = self.coolingStep[0] - 1
            if i > 0:
                coolingStep = self.coolingScheme[i - 1]
                coolingStep[0] = i + 1
                self.coolingStep[0] = i
                self.coolingScheme[i - 1] = self.coolingStep
                self.coolingScheme[i] = coolingStep

                self.updateCoolingScheme()
                self.coolingSchemeMatrix.hilightObject(self.coolingStep)

    def moveStepLater(self):

        if self.coolingStep:
            i = self.coolingStep[0] - 1
            if i < len(self.coolingScheme) - 1:
                coolingStep = self.coolingScheme[i + 1]
                coolingStep[0] = i + 1
                self.coolingStep[0] = i + 2
                self.coolingScheme[i + 1] = self.coolingStep
                self.coolingScheme[i] = coolingStep

                self.updateCoolingScheme()
                self.coolingSchemeMatrix.hilightObject(self.coolingStep)

    def addCoolingStep(self):

        i = len(self.coolingScheme) + 1
        datum = [i, 3000, 100, 10, 2500, 0.001, 1]

        self.coolingScheme.append(datum)
        self.updateCoolingScheme()

    def removeCoolingStep(self):

        if self.coolingStep:
            coolingScheme = []
            i = 0
            for coolingStep in self.coolingScheme:
                if coolingStep is not self.coolingStep:
                    i += 1
                    coolingStep[0] = i
                    coolingScheme.append(coolingStep)

            self.coolingScheme = coolingScheme
            self.updateCoolingScheme()

    def updateCoolingScheme(self):

        objectList = self.coolingScheme
        textMatrix = self.coolingScheme
        self.coolingSchemeMatrix.update(objectList=objectList,
                                        textMatrix=textMatrix)

    def updateMidgeParams(self):

        data = [
            self.specFreq, self.maxIter, self.mixTime, self.corrTime,
            self.leakRate, self.maxIntens
        ]

        self.midgeParamsMatrix.update(textMatrix=[
            data,
        ])

    def getSpecFreq(self, obj):

        self.specFreqEntry.set(self.specFreq)

    def getMaxIter(self, obj):

        self.maxIterEntry.set(self.maxIter)

    def getMixTime(self, obj):

        self.mixTimeEntry.set(self.mixTime)

    def getCorrTime(self, obj):

        self.corrTimeEntry.set(self.corrTime)

    def getLeakRate(self, obj):

        self.leakRateEntry.set(self.leakRate)

    def getMaxIntens(self, obj):

        self.maxIntensEntry.set(self.maxIntens)

    def setSpecFreq(self, event):

        value = self.specFreqEntry.get()
        if value is not None:
            self.specFreq = value

        self.updateMidgeParams()

    def setMaxIter(self, event):

        value = self.maxIterEntry.get()
        if value is not None:
            self.maxIter = value

        self.updateMidgeParams()

    def setMixTime(self, event):

        value = self.mixTimeEntry.get()
        if value is not None:
            self.mixTime = value

        self.updateMidgeParams()

    def setCorrTime(self, event):

        value = self.corrTimeEntry.get()
        if value is not None:
            self.corrTime = value

        self.updateMidgeParams()

    def setLeakRate(self, event):

        value = self.leakRateEntry.get()
        if value is not None:
            self.leakRate = value

        self.updateMidgeParams()

    def setMaxIntens(self, event):

        value = self.maxIntensEntry.get()
        if value is not None:
            self.maxIntens = value

        self.updateMidgeParams()

    def destroy(self):

        BasePopup.destroy(self)
Example #25
0
class PCSPopup(BasePopup):
    def __init__(self, parent, *args, **kw):
        BasePopup.__init__(self, parent, *args, **kw)

    def body(self, guiFrame):

        spectraFrame = LabelFrame(guiFrame, text='Spectra', grid=(0, 0))

        Label(spectraFrame, text='Diamagnetic Spectrum:', grid=(0, 0))
        self.diaSpecPulldown = PulldownList(spectraFrame,
                                            callback=self.changeDiaSpec,
                                            grid=(0, 1))

        Label(spectraFrame, text='Paramagnetic Spectrum:', grid=(1, 0))
        self.paraSpecPulldown = PulldownList(spectraFrame,
                                             callback=self.changeParaSpec,
                                             grid=(1, 1))

        pcsIOFrame = LabelFrame(guiFrame, text='PCS', grid=(1, 0))

        Label(pcsIOFrame, text='Write Experimental PCS:', grid=(0, 0))
        self.expPCSEntry = Entry(pcsIOFrame,
                                 text='pcsexp.npc',
                                 width=32,
                                 grid=(0, 1))
        Button(pcsIOFrame,
               command=self.writePCSFileChange,
               grid=(0, 2),
               text='Choose File')

        Label(pcsIOFrame, text='Read Calculated PCS:', grid=(1, 0))
        self.calPCSEntry = Entry(pcsIOFrame,
                                 text='pcscal.npc',
                                 width=32,
                                 grid=(1, 1))
        Button(pcsIOFrame,
               command=self.readPCSFileChange,
               grid=(1, 2),
               text='Choose File')

        scriptFrame = LabelFrame(guiFrame,
                                 text='Paramagpy Script',
                                 grid=(2, 0))

        Label(scriptFrame, text='PCS fitting script:', grid=(0, 0))
        self.scriptEntry = Entry(scriptFrame,
                                 text='paramagpy_fit_pcs.py',
                                 width=32,
                                 grid=(0, 1))
        Button(scriptFrame,
               command=self.writeScriptFileChange,
               grid=(0, 2),
               text='Choose File')

        commandFrame = LabelFrame(guiFrame, text='Commands', grid=(3, 0))

        Button(commandFrame,
               command=self.writePCS,
               grid=(0, 0),
               text='Write PCS')
        Button(commandFrame,
               command=self.fitTensor,
               grid=(0, 1),
               text='Fit Tensor')
        Button(commandFrame,
               command=self.readPCS,
               grid=(0, 2),
               text='Read PCS')

        self.updateSpecPulldown()

    def updateSpecPulldown(self):
        spectra = ExperimentBasic.getSpectra(self.project)
        names = []
        for spectrum in spectra:
            names.append("{}:{}".format(spectrum.experiment.name,
                                        spectrum.name))

        self.diaSpecPulldown.setup(names, spectra, 0)
        self.paraSpecPulldown.setup(names, spectra, 0)

        if len(spectra) > 1:
            self.diaSpec = spectra[0]
            self.paraSpec = spectra[1]

    def changeDiaSpec(self, spectrum):
        self.diaSpec = spectrum

    def changeParaSpec(self, spectrum):
        self.paraSpec = spectrum

    def writePCSFileChange(self):
        fileTypes = [FileType('PCS', ['*.npc']), FileType('All', ['*'])]
        fileSelectPopup = FileSelectPopup(
            self,
            file=os.path.basename(self.expPCSEntry.get()),
            directory=os.path.dirname(self.expPCSEntry.get()),
            file_types=fileTypes,
            title='Save PCS values to file',
            dismiss_text='Cancel',
            selected_file_must_exist=False,
            multiSelect=False,
        )

        self.expPCSEntry.set(fileSelectPopup.getFile())

    def readPCSFileChange(self):
        fileTypes = [FileType('PCS', ['*.npc']), FileType('All', ['*'])]
        fileSelectPopup = FileSelectPopup(
            self,
            file=os.path.basename(self.calPCSEntry.get()),
            directory=os.path.dirname(self.calPCSEntry.get()),
            file_types=fileTypes,
            title='Save PCS values to file',
            dismiss_text='Cancel',
            selected_file_must_exist=False,
            multiSelect=False,
        )

        self.calPCSEntry.set(fileSelectPopup.getFile())

    def writeScriptFileChange(self):
        fileTypes = [FileType('python', ['*.py']), FileType('All', ['*'])]
        fileSelectPopup = FileSelectPopup(
            self,
            file=os.path.basename(self.scriptEntry.get()),
            directory=os.path.dirname(self.scriptEntry.get()),
            file_types=fileTypes,
            title='Paramagpy script',
            dismiss_text='Cancel',
            selected_file_must_exist=False,
            multiSelect=False,
        )

        self.scriptEntry.set(fileSelectPopup.getFile())

    def writePCS(self):
        diaPeaks = self.diaSpec.getActivePeakList()
        paraPeaks = self.paraSpec.getActivePeakList()
        deltaPeaks = self.subtract_peak_lists(diaPeaks, paraPeaks)
        self.write_npc(deltaPeaks)

    def readPCS(self):
        print(self.diaSpec.experiment.name)
        print(self.paraSpec.experiment.name)

        calPCSName = os.path.abspath(self.calPCSEntry.get())
        if not os.path.isfile(calPCSName):
            showWarning(
                "PCS file not found",
                "Cound not find backcalculated PCS values. Please ensure the following file exists:\n{}"
                .format(calPCSName))
            return

        pcs_values = {}
        with open(calPCSName) as o:
            for line in o:
                try:
                    sequence, atomName, pcsValue, error = line.split()
                    key = int(sequence), atomName
                    pcs_values[key] = float(pcsValue)
                except ValueError:
                    print("Line ignored in calculated PCS file:\n{}".format(
                        line))

        peakListDia = self.diaSpec.getActivePeakList()
        newPeakList = self.paraSpec.newPeakList(isSimulated=True)
        newPeakList.analysisPeakList.setSymbolColor("#FF0000")
        newPeakList.setDetails("Back-calculated PCS")

        for diaPeak in peakListDia.sortedPeaks():
            paraPeak = newPeakList.newPeak()
            paraPeak.setAnnotation(diaPeak.getAnnotation())
            for ddim, pdim in zip(diaPeak.sortedPeakDims(),
                                  paraPeak.sortedPeakDims()):
                pdim.setAnnotation(ddim.getAnnotation())
                if not ddim.dataDimRef:
                    paraPeak.delete()
                    break

                contrib = ddim.findFirstPeakDimContrib()
                if not contrib:
                    paraPeak.delete()
                    break
                resonance = contrib.getResonance()
                if not resonance:
                    paraPeak.delete()
                    break
                if not resonance.resonanceSet:
                    paraPeak.delete()
                    break

                residue = getResonanceResidue(resonance)
                sequence = residue.seqCode
                atomName = resonance.getAssignNames()[0]
                key = sequence, atomName

                if key in pcs_values:
                    newShift = ddim.getValue() + pcs_values[key]
                    if self.within_axis(pdim, newShift):
                        pdim.setValue(newShift)
                    else:
                        paraPeak.delete()
                        break
                else:
                    paraPeak.delete()
                    break

    def fitTensor(self):
        scriptName = os.path.abspath(self.scriptEntry.get())
        expPCSName = os.path.abspath(self.expPCSEntry.get())
        if not os.path.isfile(scriptName):
            showWarning(
                "Script not found",
                "Could not find paramagpy script. Please ensure the following script exists:\n{}"
                .format(scriptName))
            return

        if not os.access(scriptName, os.X_OK):
            showWarning(
                "Invalid permissions",
                "The paramagpy script does not have executable permissions. Please run in the terminal:\nchmod +x {}"
                .format(scriptName))
            return

        if not os.path.isfile(expPCSName):
            showWarning(
                "PCS file not found",
                "Cound not find experimental PCS file.\nEnsure the following file exists:{}"
                .format(expPCSName))
            return

        subprocess.call([scriptName, expPCSName])

    def write_npc(self, pcsValues):
        fileName = os.path.abspath(self.expPCSEntry.get())
        with open(fileName, 'w') as o:
            for key in sorted(pcsValues):
                seq, atom = key
                value = pcsValues[key]
                line = "{0:<4d}{1:<2}{2:15.8f}  0.0\n".format(seq, atom, value)
                o.write(line)
            o.close()
        showInfo("Wrote PCS", "Wrote experimental PCS to: {}".format(fileName))

    @staticmethod
    def extract_peaks(peakList):
        out = []
        for peak in peakList.sortedPeaks():
            tmp = {}
            for peakDim in peak.sortedPeakDims():
                if not peakDim.dataDimRef:
                    continue

                contrib = peakDim.findFirstPeakDimContrib()
                if not contrib:
                    continue
                resonance = contrib.getResonance()
                if not resonance:
                    continue
                if not resonance.resonanceSet:
                    continue

                residue = getResonanceResidue(resonance)
                sequence = residue.seqCode
                atomName = resonance.getAssignNames()[0]
                tmp[(sequence, atomName)] = peakDim
            out.append((peak, tmp))
        return out

    @staticmethod
    def within_axis(peakDim, value):
        dataDim = peakDim.getDataDim()
        dr = dataDim.findFirstDataDimRef()
        diff = dr.spectralWidthOrig - dr.spectralWidth
        low = dr.refValue - dr.spectralWidth + dr.spectralWidthOrig / 2.
        high = dr.refValue + dr.spectralWidthOrig / 2.
        return low < value < high

    def subtract_peak_lists(self, diamagPeaks, paramagPeaks):

        dpeaks = self.extract_peaks(diamagPeaks)
        ppeaks = self.extract_peaks(paramagPeaks)

        dvals = {}
        pvals = {}

        for peak, dic in dpeaks:
            dvals.update(dic)

        for peak, dic in ppeaks:
            pvals.update(dic)

        out = {}
        for key in set(dvals) & set(pvals):
            out[key] = pvals[key].value - dvals[key].value

        return out
Example #26
0
class MeccanoPopup(BasePopup):

  def __init__(self, parent, project, *args, **kw):
  
    self.alignMedium = None
    self.chain = None
    self.constraint = None
    self.constraintSet = None
    self.molSystem = None
    self.project = project
    self.run = None
    self.shiftList = None
    self.tensor = None

    
    BasePopup.__init__(self, parent=parent, title='MECCANO', *args, **kw)

    self.curateNotifiers(self.registerNotify)

  def body(self, guiFrame):
  
    guiFrame.grid_columnconfigure(0, weight=1)
    guiFrame.grid_rowconfigure(0, weight=1)

    options = ['Parameters','Restraints','Alignment Media & Tensors','About Meccano']
    tabbedFrame = TabbedFrame(guiFrame, options=options)
    tabbedFrame.grid(row=0, column=0, sticky='nsew')
    
    frameA, frameB, frameC, frameD = tabbedFrame.frames
    frameA.grid_columnconfigure(1, weight=1)
    frameA.grid_rowconfigure(13, weight=1)
    frameB.grid_columnconfigure(1, weight=1)
    frameB.grid_rowconfigure(1, weight=1)
    frameC.grid_columnconfigure(0, weight=1)
    frameC.grid_rowconfigure(1, weight=1)
    frameD.grid_columnconfigure(0, weight=1)
    frameD.grid_rowconfigure(0, weight=1)
    
    texts = ['Run MECCANO!']
    commands = [self.runMeccano]
    bottomButtons = createDismissHelpButtonList(guiFrame, texts=texts,
                                                commands=commands, expands=True)
    bottomButtons.grid(row=1, column=0, sticky='ew')

    if not Meccano:
      bottomButtons.buttons[0].disable()
  
    # Parameters
        
    row = 0
    label = Label(frameA, text='Calculation Run:')
    label.grid(row=row,column=0,sticky='w')
    self.runPulldown = PulldownList(frameA, callback=self.selectRun)
    self.runPulldown.grid(row=row,column=1,sticky='w')
    
    row += 1    
    label = Label(frameA, text='Shift List (for CO):')
    label.grid(row=row,column=0,sticky='w')
    self.shiftListPulldown = PulldownList(frameA, callback=self.selectShiftList)
    self.shiftListPulldown.grid(row=row,column=1,sticky='w')
           
    row += 1    
    label = Label(frameA, text='Keep Copy of Used Shifts:')
    label.grid(row=row,column=0,sticky='w')
    self.toggleCopyShifts = CheckButton(frameA)
    self.toggleCopyShifts.grid(row=row,column=1,sticky='w')
    self.toggleCopyShifts.set(True)
        
    row += 1    
    label = Label(frameA, text='Molecular System:')
    label.grid(row=row,column=0,sticky='w')
    self.molSystemPulldown = PulldownList(frameA, callback=self.selectMolSystem)
    self.molSystemPulldown.grid(row=row,column=1,sticky='w')
        
    row += 1    
    label = Label(frameA, text='Chain:')
    label.grid(row=row,column=0,sticky='w')
    self.chainPulldown = PulldownList(frameA, callback=self.selectChain)
    self.chainPulldown.grid(row=row,column=1,sticky='w')
    self.chainPulldown.bind('<Leave>', self.updateRunParams) 
        
    row += 1    
    label = Label(frameA, text='First Peptide Plane:')
    label.grid(row=row,column=0,sticky='w')
    self.firstResEntry = IntEntry(frameA, text=None, width=8)
    self.firstResEntry.grid(row=row,column=1,sticky='w')
    self.firstResEntry.bind('<Leave>', self.updateRunParams) 
        
    row += 1    
    label = Label(frameA, text='Last Peptide Plane:')
    label.grid(row=row,column=0,sticky='w')
    self.lastResEntry = IntEntry(frameA, text=None, width=8)
    self.lastResEntry.grid(row=row,column=1,sticky='w')
    self.lastResEntry.bind('<Leave>', self.updateRunParams) 
        
    row += 1    
    label = Label(frameA, text='Max Num Optimisation Steps:')
    label.grid(row=row,column=0,sticky='w')
    self.maxOptStepEntry = IntEntry(frameA, text=500, width=8)
    self.maxOptStepEntry.grid(row=row,column=1,sticky='w')
    self.maxOptStepEntry.bind('<Leave>', self.updateRunParams) 
        
    row += 1    
    label = Label(frameA, text='Num Optimisation Peptide Planes:')
    label.grid(row=row,column=0,sticky='w')
    self.numOptPlaneEntry = IntEntry(frameA, text=2, width=8)
    self.numOptPlaneEntry.grid(row=row,column=1,sticky='w')
    self.numOptPlaneEntry.bind('<Leave>', self.updateRunParams) 
        
    row += 1    
    label = Label(frameA, text='Min Num Optimisation Hits:')
    label.grid(row=row,column=0,sticky='w')
    self.numOptHitsEntry = IntEntry(frameA, text=5, width=8)
    self.numOptHitsEntry.grid(row=row,column=1,sticky='w')
    self.numOptHitsEntry.bind('<Leave>', self.updateRunParams) 

    row += 1    
    label = Label(frameA, text='File Name Prefix:')
    label.grid(row=row,column=0,sticky='w')
    self.pdbFileEntry = Entry(frameA, text='Meccano', width=8)
    self.pdbFileEntry.grid(row=row,column=1,sticky='w')
    self.pdbFileEntry.bind('<Leave>', self.updateRunParams) 
           
    row += 1    
    label = Label(frameA, text='Write Output File (.out):')
    label.grid(row=row,column=0,sticky='w')
    self.toggleWriteOutFile = CheckButton(frameA)
    self.toggleWriteOutFile.grid(row=row,column=1,sticky='w')
    self.toggleWriteOutFile.set(False)
    self.toggleWriteOutFile.bind('<Leave>', self.updateRunParams) 
           
    row += 1    
    label = Label(frameA, text='Write PDB File (.pdb):')
    label.grid(row=row,column=0,sticky='w')
    self.toggleWritePdbFile = CheckButton(frameA)
    self.toggleWritePdbFile.grid(row=row,column=1,sticky='w')
    self.toggleWritePdbFile.set(True)
    self.toggleWritePdbFile.bind('<Leave>', self.updateRunParams) 
    
    if not Meccano:
      row += 1    
      label = Label(frameA, text='The Meccano executable is not available (it needs to be compiled)', fg='red')
      label.grid(row=row,column=0,columnspan=2,sticky='w')

    # Restraints
    
    label = Label(frameB, text='Constraint Set:')
    label.grid(row=0,column=0,sticky='w')
    
    self.constraintSetPulldown = PulldownList(frameB, callback=self.selectConstraintSet)
    self.constraintSetPulldown.grid(row=0,column=1,sticky='w')
    
    self.alignMediumPulldown= PulldownList(self, callback=self.setAlignMedium)
    
    headingList = ['#','List Type','Use?','Alignment\nMedium','Num\nRestraints']
    editWidgets      = [None,None,None,self.alignMediumPulldown,None]
    editGetCallbacks = [None,None,self.toggleUseRestraints,self.getAlignMedium,None]
    editSetCallbacks = [None,None,None,self.setAlignMedium,None]
    self.restraintMatrix = ScrolledMatrix(frameB,
                                          headingList=headingList,
                                          editSetCallbacks=editSetCallbacks,
                                          editGetCallbacks=editGetCallbacks, 
                                          editWidgets=editWidgets,
                                          callback=None,
                                          multiSelect=True)
    self.restraintMatrix.grid(row=1,column=0,columnspan=2,sticky='nsew')
    
    
    # Alignment Media
    
    div = LabelDivider(frameC,text='Alignment Media')
    div.grid(row=0,column=0,sticky='ew')
    
    self.mediumNameEntry = Entry(self, returnCallback=self.setMediumName)
    self.mediumDetailsEntry = Entry(self, returnCallback=self.setMediumDetails)
    
    headingList = ['#','Name','Details','Static Tensor','Dynamic Tensor']
    editWidgets      = [None, self.mediumNameEntry, self.mediumDetailsEntry, None, None]
    editGetCallbacks = [None, self.getMediumName, self.getMediumDetails, None, None]
    editSetCallbacks = [None, self.setMediumName, self.setMediumDetails, None, None]
    self.mediaMatrix = ScrolledMatrix(frameC,
                                      headingList=headingList,
                                      editSetCallbacks=editSetCallbacks,
                                      editGetCallbacks=editGetCallbacks, 
                                      editWidgets=editWidgets,
                                      callback=self.selectAlignMedium,
                                      multiSelect=True)
                                 
    self.mediaMatrix.grid(row=1,column=0,sticky='nsew')
     
    
    texts = ['Add Alignment medium','Remove Alignment Medium']
    commands = [self.addAlignMedium,self.removeAlignMedium]
    buttonList = ButtonList(frameC, texts=texts, commands=commands, expands=True)
    buttonList.grid(row=2,column=0,sticky='nsew')
    
    self.editAxialEntry = FloatEntry(self, returnCallback=self.setAxial)
    self.editRhombicEntry = FloatEntry(self, returnCallback=self.setRhombic)
    self.editAlphaEulerEntry = FloatEntry(self, returnCallback=self.setEulerAlpha)
    self.editBetaEulerEntry = FloatEntry(self, returnCallback=self.setEulerBeta)
    self.editGammaEulerEntry = FloatEntry(self, returnCallback=self.setEulerGamma)
    
    
    div = LabelDivider(frameC,text='Alignment Tensors')
    div.grid(row=3,column=0,sticky='ew')
    
    headingList = ['Type', u'Axial (\u03B6)',u'Rhombic (\u03B7)',
                   u'Euler \u03B1',u'Euler \u03B2',u'Euler \u03B3']
    editWidgets      = [None,self.editAxialEntry,
                        self.editRhombicEntry,self.editAlphaEulerEntry,
                        self.editBetaEulerEntry,self.editGammaEulerEntry]
    editSetCallbacks = [None,self.setAxial,self.setRhombic,
                        self.setEulerAlpha,self.setEulerBeta,self.setEulerGamma]
    editGetCallbacks = [None,self.getAxial,self.getRhombic,
                        self.getEulerAlpha,self.getEulerBeta,self.getEulerGamma]
                   
    self.tensorMatrix = ScrolledMatrix(frameC, maxRows=2,
                                       headingList=headingList,
                                       editSetCallbacks=editSetCallbacks,
                                       editGetCallbacks=editGetCallbacks, 
                                       editWidgets=editWidgets,
                                       callback=self.selectTensor,
                                       multiSelect=True)
                                          
    self.tensorMatrix.grid(row=4,column=0,sticky='nsew')
    
    texts = ['Add Static Tensor','Add Dynamic Tensor','Remove Tensor']
    commands = [self.addStaticTensor,self.addDynamicTensor,self.removeTensor]
    buttonList = ButtonList(frameC,texts=texts, commands=commands, expands=True)
    buttonList.grid(row=5,column=0,sticky='ew')
       
    # About
    
    label = Label(frameD, text='About Meccano...')
    label.grid(row=0,column=0,sticky='w')
  
    #
  
    self.geometry('500x400')

    self.updateShiftLists()
    self.updateMolSystems()
    self.updateResidueRanges()
    self.updateConstraintSets()
    self.updateAlignMedia()
    self.updateRuns()
    
  def close(self):
  
    self.updateRunParams()
    
    BasePopup.close(self)
  
  def destroy(self):
  
    self.updateRunParams()
    self.curateNotifiers(self.unregisterNotify)
    
    BasePopup.destroy(self)
  
  def curateNotifiers(self, notifyFunc):
  
    for func in ('__init__', 'delete'):
      notifyFunc(self.updateConstraintSetsAfter, 'ccp.nmr.NmrConstraint.NmrConstraintStore', func)
    
    for func in ('__init__', 'delete','setName','setConditionState'):
      for clazz in ('ccp.nmr.NmrConstraint.CsaConstraintList',
                    'ccp.nmr.NmrConstraint.DihedralConstraintList',
                    'ccp.nmr.NmrConstraint.DistanceConstraintList',
                    'ccp.nmr.NmrConstraint.HBondConstraintList',
                    'ccp.nmr.NmrConstraint.JCouplingConstraintList',
                    'ccp.nmr.NmrConstraint.RdcConstraintList'):
        notifyFunc(self.updateConstraintListsAfter, clazz, func)
        
    for func in ('__init__', 'delete',):
      for clazz in ('ccp.nmr.NmrConstraint.CsaConstraint',
                    'ccp.nmr.NmrConstraint.DihedralConstraint',
                    'ccp.nmr.NmrConstraint.DistanceConstraint',
                    'ccp.nmr.NmrConstraint.HBondConstraint',
                    'ccp.nmr.NmrConstraint.JCouplingConstraint',
                    'ccp.nmr.NmrConstraint.RdcConstraint'):
        notifyFunc(self.updateConstraintsAfter, clazz, func)    
    
    for func in ('__init__', 'delete'):
      notifyFunc(self.updateShiftListsAfter,'ccp.nmr.Nmr.ShiftList', func)

    for func in ('__init__', 'delete'):
      notifyFunc(self.updateMolSystemsAfter,'ccp.molecule.MolSystem.MolSystem', func)

    for func in ('__init__', 'delete'):
      notifyFunc(self.updateChainsAfter,'ccp.molecule.MolSystem.Chain', func)

    for func in ('__init__', 'delete','setDynamicAlignment',
                 'setStaticAlignment','setName','setDetails'):
      notifyFunc(self.updateAlignMediaAfter,'ccp.nmr.NmrConstraint.ConditionState', func)

  def updateAlignMediaAfter(self, alignMedium):
  
     if alignMedium.nmrConstraintStore is self.constraintSet:
       self.after_idle(self.updateAlignMedia)
 
       if alignMedium is self.alignMedium:
         self.after_idle(self.updateTensors)

  def updateConstraintSetsAfter(self, constraintSet):
  
     self.after_idle(self.updateConstraintSets)

  def updateShiftListsAfter(self, shiftList):
  
     self.after_idle(self.updateShiftLists)

  def updateMolSystemsAfter(self, molSystem):
  
     self.after_idle(self.updateMolSystems)

  def updateChainsAfter(self, chain):
  
     self.after_idle(self.updateChains)
  
  def updateConstraintsAfter(self, constraint):
  
     if constraint.parent.parent is self.constraintSet:
       self.after_idle(self.updateConstraintLists)
  
  def updateConstraintListsAfter(self, constraintList):
  
     if constraintList.parent is self.constraintSet:
       self.after_idle(self.updateConstraintLists)
    
  def runMeccano(self):
    
    #
    #
    # Input checks first
    #
    #
  
    warning = ''
    if not self.molSystem:
      warning += 'No molecular system selected\n'
    
    if not self.chain:
      warning += 'No chain selected\n'
  
    if not self.constraintSet:
      warning += 'No selected constraint set\n'  
    else:
      constraintLists = [cl for cl in self.constraintSet.constraintLists if cl.useForMeccano]  
      if not constraintLists:
        warning += 'No constraint lists selected for use\n'   
 
    first, last = self.updateResidueRanges()
    if (last-first) < 2:
      warning += 'Too few peptide planes selected\n'         
  
    if warning:
      showWarning('Cannot run MECCANO','Encountered the following problems:\n' + warning)
      return
      
    if not self.run:
      self.run = self.makeSimRun()
      
    self.updateRunParams()
    
    if self.toggleCopyShifts.get() and self.shiftList:
      shiftList = self.run.findFirstOutputMeasurementList(className='ShiftList')
      
      if not shiftList:
        shiftList = self.project.currentNmrProject.newShiftList(name='Meccano Input')
        
      self.run.setOutputMeasurementLists([shiftList,])
    
      shiftDict = {}
      for shift in shiftList.shifts:
        shiftDict[shift.resonance] = shift
      
    
      for shift in self.shiftList.shifts:
        resonance = shift.resonance
        resonanceSet = resonance.resonanceSet
        
        if resonanceSet:
          atom = resonanceSet.findFirstAtomSet().findFirstAtom()
          
          if (atom.name == 'C') and (atom.residue.molResidue.molType == 'protein'):
            shift2 = shiftDict.get(resonance)
            if shift2:
              shift2.value = shift.value
              shift2.error = shift.error
              
            else:
              shiftList.newShift(resonance=resonance, value=shift.value, error=shift.error)  
    
    #
    #
    # Accumulate data from CCPN data model & GUI
    #
    #

    # Sequence

    residues = self.chain.sortedResidues()
    residueDict = {}
    
    seqData = []
    for residue in residues:
      molResidue = residue.molResidue
      
      code1Letter = molResidue.chemComp.code1Letter
      
      if not code1Letter:
        msg = 'Encountered non-standard residue type: %s'
        showWarning('Cannot run MECCANO', msg % residue.ccpCode)
        return
     
      seqCode = residue.seqCode
      seqData.append((seqCode, code1Letter))
      residueDict[seqCode] = residue.chemCompVar.chemComp.code3Letter

    # Media, RDCs & Dihedrals

    rdcLists = []
    dihedralLists = []

    for constraintList in constraintLists:
      if constraintList.className == 'RdcConsraintList':
        if constraintList.conditionState:
          rdcLists.append(constraintList)
      
      elif constraintList.className == 'DihedralConstraintList':
        dihedralLists.append(dihedralLists)
    
    f = PI_OVER_180  
    mediaData = []
    for constraintList in rdcLists:
      medium = constraintList.conditionState
      dynamicTensor = medium.dynamicAlignment
      staticTensor = medium.staticAlignment
    
      if not (dynamicTensor or staticTensor):
        continue
    
      if dynamicTensor:
        dynamicTensorData = ['Dynamic', dynamicTensor.aAxial, dynamicTensor.aRhombic,
                             f*dynamicTensor.alpha, f*dynamicTensor.beta, f*dynamicTensor.gamma]
   
      if staticTensor:
        staticTensorData = ['Static', staticTensor.aAxial, staticTensor.aRhombic,
                            f*staticTensor.alpha, f*staticTensor.beta, f*staticTensor.gamma]
      
      if not dynamicTensor:
        dynamicTensorData = staticTensorData
      
      elif not staticTensor:
        staticTensorData = dynamicTensorData
      
      rdcData = []
      for restraint in constraintList.constraints:
        items = list(restraint.items)
        
        if len(items) != 1:
          continue
          
        resonanceA, resonanceB = [fr.resonance for fr in items[0].resonances] 
        
        resonanceSetA = resonanceA.resonanceSet
        if not resonanceSetA:
          continue
        
        resonanceSetB = resonanceB.resonanceSet
        if not resonanceSetB:
          continue
        
        resNameA = getResonanceName(resonanceA)
        resNameB = getResonanceName(resonanceB)
          
        residueA = resonanceSetA.findFirstAtomSet().findFirstAtom().residue  
        residueB = resonanceSetB.findFirstAtomSet().findFirstAtom().residue  
        
        seqA = residueA.seqCode
        seqB = residueB.seqCode
        
        value = restraint.targetValue
        error = restraint.error
        
        if error is None:
          key = [resNameA,resNameB]
          key.sort()
          sigma = DEFAULT_ERRORS.get(tuple(key), 1.0)
        
        rdcData.append([seqA, resNameA, seqB, resNameB, value, error])
      
      mediaData.append((dynamicTensorData,staticTensorData,rdcData))
      
    oneTurn = 360.0
    dihedralDict = {}
    for constraintList in dihedralLists:
      for restraint in constraintList.constraints:
        items = list(restraint.items)
        
        if len(items) != 1:
          continue
        
        item = items[0]
        resonances = [fr.resonance for fr in item.resonances] 
        
        resonanceSets = [r.resonanceSet for r in resonances]
        
        if None in resonanceSets:
          continue
          
        atoms = [rs.findFirstAtomSet().findFirstAtom() for rs in resonanceSets]  
    
        atomNames = [a.name for a in atoms]
        
        if atomNames == PHI_ATOM_NAMES:
          isPhi = True
        elif atomNames == PSI_ATOM_NAMES:
          isPhi = False
        else:
          continue
    
        residue = atoms[2].residue
        
        if residue.chain is not self.chain:
          continue
        
        if isPhi:
          residuePrev = getLinkedResidue(residue, linkCode='prev')
          
          if not residuePrev:
            continue
            
          atomC0 = residuePrev.findFirstAtom(name='C')
          atomN  = residue.findFirstAtom(name='N')
          atomCa = residue.findFirstAtom(name='CA')
          atomC  = residue.findFirstAtom(name='C')
          atoms2 = [atomC0, atomN, atomCa, atomC]
          
        else:
          residueNext = getLinkedResidue(residue, linkCode='next')
          
          if not residueNext:
            continue
          
          atomN  = residue.findFirstAtom(name='N')
          atomCa = residue.findFirstAtom(name='CA')
          atomC  = residue.findFirstAtom(name='C')
          atomN2 = residueNext.findFirstAtom(name='N')
          atoms2 = [atomN, atomCa, atomC, atomN2]
          
        if atoms != atoms2:
          continue
        
        value = item.targetValue
        error = item.error
        
        if error is None:
          upper = item.upperLimit
          lower = item.lowerLimit
          
          if (upper is not None) and (lower is not None):
            dUpper = angleDifference(value, lower, oneTurn)
            dLower = angleDifference(upper, value, oneTurn)
            error  = max(dUpper, dLower)
            
          elif lower is not None:
            error = angleDifference(value, lower, oneTurn)
            
          elif upper is not None:
            error = angleDifference(upper, value, oneTurn)
            
          else:
            error = 30.0 # Arbitrary, but sensible for TALOS, DANGLE
        
        seqCode = residue.seqCode
        if not dihedralDict.has_key(seqCode):
          dihedralDict[seqCode] = [None, None, None, None] # Phi, Psi, PhiErr, PsiErr
        
        if isPhi:
          dihedralDict[seqCode][0] = value
          dihedralDict[seqCode][2] = error
        else:
          dihedralDict[seqCode][1] = value
          dihedralDict[seqCode][3] = error
          
          
    phipsiData = []
    seqCodes = dihedralDict.keys()
    seqCodes.sort()
    
    for seqCode in seqCodes:
      data = dihedralDict[seqCode]
      
      if None not in data:
        phi, psi, phiErr, psiErr = data
        phipsiData.append((seqCode, phi, psi, phiErr, psiErr))
        
    
    # User options
    
    firstPPlaneFrag = self.firstResEntry.get() or 1
    lastPPlaneFrag  = self.lastResEntry.get() or 1
    ppNbMin         = self.numOptPlaneEntry.get() or 1
    minValueBest    = self.numOptHitsEntry.get() or 2
    maxValueBest    = self.maxOptStepEntry.get() or 5

    strucData = Meccano.runFwd(firstPPlaneFrag, lastPPlaneFrag, ppNbMin,
                               minValueBest, maxValueBest, RAMACHANDRAN_DATABASE,
                               seqData, mediaData, phipsiData)
   
    if strucData:
      fileName = 'CcpnMeccanoPdb%f.pdb' % time.time()
      fileObj = open(fileName, 'w')
 
      ch = self.chain.pdbOneLetterCode.strip()
      if not ch:
        ch = self.chain.code[0].upper()
 
        i = 1
        for atomType, resNb, x, y, z in strucData:
          resType = residueDict.get(resNb, '???')
          line = PDB_FORMAT % ('ATOM',i,'%-3s' % atomType,'',resType,ch,resNb,'',x,y,z,1.0,1.0)
 
          i += 1

      fileObj.close()
      
      ensemble = getStructureFromFile(self.molSystem, fileName)
      
      
      if not self.toggleWritePdbFile.get():
        os.unlink(fileName)
         
      self.run.outputEnsemble = ensemble
      self.run = None
    
    self.updateRuns()

  def getMediumName(self, alignMedium):
  
    self.mediumNameEntry.set(alignMedium.name)
    
  def getMediumDetails(self, alignMedium):
  
    self.mediumDetailsEntry.set(alignMedium.details)
    
  def setMediumName(self, event): 

    value = self.mediumNameEntry.get()
    self.alignMedium.name = value or None
    
  def setMediumDetails(self, event): 

    value = self.mediumDetailsEntry.get()
    self.alignMedium.details = value or None
      
  def setAlignMedium(self, alignMedium):

    if self.constraintSet:
      self.constraintSet.conditionState = alignMedium
    
  def getAlignMedium(self, constraintList):

    media = self.getAlignmentMedia()
    names = [am.name for am in media]
    
    if constraintList.conditionState in media:
      index = media.index(constraintList.conditionState)
    else:
      index = 0
  
    self.alignMediumPulldown.setup(names, media, index)

  def toggleUseRestraints(self, constraintList):
 
    bool = constraintList.useForMeccano
    bool = not bool
 
    if bool and (not constraintList.conditionState) \
     and (constraintList.className == 'RdcConsraintList'):
      msg = 'Cannot use RDC restraint list for Meccano '
      msg += 'unless it is first associated with an amigment medium'
      showWarning('Warning', msg, parent=self)
    else:
      constraintList.useForMeccano = bool
      
    self.updateConstraintLists()
 
  def addStaticTensor(self):
  
    if self.alignMedium:
      tensor = Implementation.SymmTracelessMatrix(aAxial=0.0,aRhombic=0.0,
                                                  alpha=0.0,beta=0.0,
                                                  gamma=0.0)
      

      self.alignMedium.staticAlignment = tensor
 
      self.updateAlignMediaAfter(self.alignMedium)
 
  def addDynamicTensor(self):
  
    if self.alignMedium:
      tensor = Implementation.SymmTracelessMatrix(aAxial=0.0,aRhombic=0.0,
                                                  alpha=0.0,beta=0.0,
                                                  gamma=0.0)
      self.alignMedium.dynamicAlignment = tensor
      
      self.updateAlignMediaAfter(self.alignMedium)
  
  def removeTensor(self):
  
    if self.alignMedium and self.tensor:
      if self.tensor is self.alignMedium.dynamicAlignment:
        self.alignMedium.dynamicAlignment = None
        
      elif self.tensor is self.alignMedium.staticAlignment:
        self.alignMedium.staticAlignment = None
      
      self.updateAlignMediaAfter(self.alignMedium)
        
  def addAlignMedium(self):
  
    if self.constraintSet:
      medium = self.constraintSet.newConditionState()
      medium.name = 'Align Medium %d' % medium.serial   
  
  def removeAlignMedium(self):

    if self.alignMedium:
      self.alignMedium.delete()

  def updateTensor(self, aAxial=None, aRhombic=None, alpha=None, beta=None, gamma=None):
  
    aAxial   = aAxial   or self.tensor.aAxial
    aRhombic = aRhombic or self.tensor.aRhombic
    alpha    = alpha    or self.tensor.alpha
    beta     = beta     or self.tensor.beta
    gamma    = gamma    or self.tensor.gamma
    
    tensor = Implementation.SymmTracelessMatrix(aAxial=aAxial,
                                                aRhombic=aRhombic,
                                                alpha=alpha,beta=beta,
                                                gamma=gamma)
 
    if self.alignMedium:
      if self.tensor is self.alignMedium.dynamicAlignment:
        self.alignMedium.dynamicAlignment = tensor
        
      elif self.tensor is self.alignMedium.staticAlignment:
        self.alignMedium.staticAlignment = tensor
 
    self.tensor = tensor
 
  def setAxial(self, event): 
  
    value = self.editAxialEntry.get()
    self.updateTensor(aAxial=value)
    self.updateTensors()
    
  def setRhombic(self,  event): 
  
    value = self.editRhombicEntry.get()
    self.updateTensor(aRhombic=value)
    self.updateTensors()
   
  def setEulerAlpha(self,  event): 
  
    value = self.editAlphaEulerEntry.get()
    self.updateTensor(alpha=value)
    self.updateTensors()
    
  def setEulerBeta(self,  event): 
  
    value = self.editBetaEulerEntry.get()
    self.updateTensor(beta=value)
    self.updateTensors()
    
  def setEulerGamma(self,  event): 
  
    value = self.editGammaEulerEntry.get()
    self.updateTensor(gamma=value)
    self.updateTensors()

  def getAxial(self, tensor): 
  
    value = tensor.aAxial
    self.editAxialEntry.set(value)
     
  def getRhombic(self, tensor): 
  
    value = tensor.aRhombic
    self.editRhombicEntry.set(value)
     
  def getEulerAlpha(self, tensor): 
  
    value = tensor.alpha
    self.editAlphaEulerEntry.set(value)
     
  def getEulerBeta(self, tensor): 
  
    value = tensor.beta
    self.editBetaEulerEntry.set(value)
     
  def getEulerGamma(self, tensor): 
  
    value = tensor.gamma
    self.editGammaEulerEntry.set(value)
 
  def selectTensor(self, tensor, row, col):
  
    self.tensor = tensor
 
  def selectAlignMedium(self, alignMedium, row, col):
  
    self.alignMedium = alignMedium
    self.updateTensors()
 
  def getAlignmentMedia(self):
  
    if self.constraintSet:
      return self.constraintSet.sortedConditionStates()
    else:
      return []
 
  def updateAlignMedia(self):

    textMatrix = []
    objectList = []
    
    if self.constraintSet:
      objectList = self.getAlignmentMedia()
        
      for conditionState in objectList:
         
         staticTensor = None
         dyamicTensor = None
         tensor = conditionState.dynamicAlignment
         if tensor:
           vals = (tensor.aAxial, tensor.aRhombic, tensor.alpha, tensor.beta, tensor.gamma)
           dyamicTensor = u'\u03B6:%.3f \u03B7:%.3f \u03B1:%.3f \u03B2:%.3f \u03B3:%.3f ' % vals

         tensor = conditionState.staticAlignment
         if tensor:
           vals = (tensor.aAxial, tensor.aRhombic, tensor.alpha, tensor.beta, tensor.gamma)
           staticTensor = u'\u03B6:%.3f \u03B7:%.3f \u03B1:%.3f \u03B2:%.3f \u03B3:%.3f ' % vals
           
         datum = [conditionState.serial,
                  conditionState.name,
                  conditionState.details,
                  dyamicTensor,
                  staticTensor]
         textMatrix.append(datum)

         if dyamicTensor or staticTensor:
           if not self.alignMedium:
             self.alignMedium = conditionState
   
    self.mediaMatrix.update(textMatrix=textMatrix, objectList=objectList)
      
    if self.alignMedium:
      self.mediaMatrix.selectObject(self.alignMedium)
 
  def updateTensors(self):
    
    textMatrix = []
    objectList = []
    conditionState = self.alignMedium
    
    if conditionState:
    
      tensor = conditionState.dynamicAlignment
      if tensor:
        datum = ['Dynamic', tensor.aAxial, tensor.aRhombic,
                 tensor.alpha, tensor.beta, tensor.gamma]
        textMatrix.append(datum)
        objectList.append(tensor)
      
      tensor = conditionState.staticAlignment
      if tensor:
        datum = ['Static', tensor.aAxial, tensor.aRhombic,
                 tensor.alpha, tensor.beta, tensor.gamma]
        textMatrix.append(datum)
        objectList.append(tensor)

    self.tensorMatrix.update(textMatrix=textMatrix, objectList=objectList)  
 
  def getMolSystems(self):
  
    molSystems = []
    
    for molSystem in self.project.sortedMolSystems():
      if molSystem.chains:
        molSystems.append(molSystem)
        
    return molSystems    
     
     
  def updateMolSystems(self, *notifyObj):
  
    index = 0
    names = []
    
    molSystems = self.getMolSystems()
    molSystem = self.molSystem
    
    if molSystems:
      if molSystem not in molSystems:
        molSystem = molSystems[0]
      
      index = molSystems.index(molSystem)
      names = [ms.code for ms in molSystems] 
    
    else:
      self.molSystem = None
    
    if self.molSystem is not molSystem:
      if self.run:
        self.run.molSystem = molSystem
        
      self.molSystem = molSystem
      self.updateChains()
    
    self.molSystemPulldown.setup(texts=names, objects=molSystems, index=index)
    
  
  def selectMolSystem(self, molSystem):
  
    if self.molSystem is not molSystem:
      if self.run:
        self.run.molSystem = molSystem
        
      self.molSystem = molSystem
      self.updateChains()
     
     
  def updateChains(self, *notifyObj):
  
    index = 0
    names = []
    chains = []
    chain = self.chain
    
    if self.molSystem:
      chains = [c for c in self.molSystem.sortedChains() if c.residues]
    
    if chains: 
      if chain not in chains:
        chain = chains[0]
        
      index = chains.index(chain)
      names = [c.code for c in chains]
    
    if chain is not self.chain:
      self.chain = chain
      self.updateResidueRanges()
    
    self.chainPulldown.setup(texts=names, objects=chains, index=index)
     
  def selectChain(self, chain):
  
    if chain is not self.chain:
      self.chain = chain
      self.updateResidueRanges()

  def updateResidueRanges(self):
  
    first = self.firstResEntry.get()
    last = self.lastResEntry.get()
    
    if self.chain:
      residues = self.chain.sortedResidues()
      firstSeq = residues[0].seqCode
      lastSeq = residues[-2].seqCode
      
      if first < firstSeq:
        first = firstSeq
     
      if last == first:
        last = lastSeq
      
      elif last > lastSeq:
        last = lastSeq
        
      if first > last:
        last, first = first, last    
      
  
    self.firstResEntry.set(first)
    self.lastResEntry.set(last)
 
    return first, last

  def getConstraintSets(self):
  
    constraintSets = []
    nmrProject = self.project.currentNmrProject
    
    for constraintSet in nmrProject.sortedNmrConstraintStores():
      for constraintList in constraintSet.constraintLists:
        if constraintList.className not in ('ChemShiftConstraintList','somethingElse'):
          constraintSets.append(constraintSet)
          break
    
    return constraintSets
  
  def updateConstraintSets(self, *notifyObj):

    index = 0
    names = []
    constraintSets = self.getConstraintSets()
    constraintSet = self.constraintSet

    if constraintSets:
      if constraintSet not in constraintSets:
        constraintSet = constraintSets[0]
        
      index = constraintSets.index(constraintSet)
      names = ['%d' % cs.serial for cs in constraintSets]
    
    if constraintSet is not self.constraintSet:
      if self.run:
        self.run.inputConstraintStore = constraintSet
    
      self.constraintSet = constraintSet
      self.updateConstraintLists()    
    
    self.constraintSetPulldown.setup(texts=names, objects=constraintSets, index=index)

  def selectConstraintSet(self, constraintSet):
  
    if self.constraintSet is not constraintSet:
      if self.run:
        self.run.inputConstraintStore = constraintSet
        
      self.constraintSet = constraintSet
      self.updateConstraintLists() 
  
  def getConstraintLists(self):
  
    constraintLists = []
    if self.constraintSet:
      for constraintList in self.constraintSet.sortedConstraintLists():
        if constraintList.className not in ('ChemShiftConstraintList','somethingElse'):
          constraintLists.append(constraintList)
  
    return constraintLists
    
  def updateConstraintLists(self, *notifyObj):
  
    textMatrix = []
    objectList = self.getConstraintLists()
    
    for constraintList in objectList:
      if not hasattr(constraintList, 'useForMeccano'):
        if constraintList.conditionState \
         or (constraintList.className != 'RdcConstraintList'):
          bool = True
        else:
          bool = False  
      
        constraintList.useForMeccano = bool
    
      if constraintList.conditionState:
        alignMedium = constraintList.conditionState.name
      else:
        alignMedium = None
    
      datum = [constraintList.serial,
               constraintList.className[:-14],
               constraintList.useForMeccano and 'Yes' or 'No',
               alignMedium,
               len(constraintList.constraints)]
  
      textMatrix.append(datum)
  
    self.restraintMatrix.update(textMatrix=textMatrix, objectList=objectList)
  
  def selectConstraint(self, obj, row, column):
  
    if self.constraint is not obj:
      self.constraint = obj

  def getSimStore(self):
  
    simStore = self.project.findFirstNmrSimStore(name='meccano')
    if not simStore:
      simStore = self.project.newNmrSimStore(name='meccano')
    
    return simStore

  def getRuns(self):
  
    runs = [None, ]
    
    if self.molSystem and self.constraintSet:
      simStore = self.getSimStore()
      runs += simStore.sortedRuns()
    
    return runs
  
  def updateRuns(self, *notifyObj):
  
    index = 0
    names = ['<New>']
    runs = self.getRuns()
    run = self.run

    if runs:
      if run not in runs:
        run = runs[0]
    
      index = runs.index(run)
      names += [r.serial for r in runs if r]
    
    if run is not self.run:
      self.updateConstraintSets()
      self.updateMolSystems()
      self.updateShiftLists()
    
    self.runPulldown.setup(names, runs, index)
  
  def updateRunParams(self, event=None):
  
    if self.run and self.molSystem and self.constraintSet:
      simRun = self.run
      
      simRun.inputConstraintStore = self.constraintSet
      simRun.molSystem = self.molSystem
      
      if self.shiftList:
        simRun.setInputMeasurementLists([self.shiftList,])                 

      simRun.newRunParameter(code='FirstPepPlane',id=1, 
                             intValue=self.firstResEntry.get() or 0)
      simRun.newRunParameter(code='LastPepPlane' ,id=1, 
                             intValue=self.lastResEntry.get() or 0)
      simRun.newRunParameter(code='MaxOptSteps',  id=1, 
                             intValue=self.maxOptStepEntry.get() or 0)
      simRun.newRunParameter(code='NumOptPlanes', id=1, 
                             intValue=self.numOptPlaneEntry.get() or 0)
      simRun.newRunParameter(code='MinOptHits',   id=1, 
                             intValue=self.numOptHitsEntry.get() or 0)
  
  def makeSimRun(self, template=None):

    simStore = self.getSimStore()
   
    if template:
      molSystem = template.molSystem
      constraintSet = template.inputConstraintStore
      shiftList = template.findFirstInputMeasurementList(className='ShiftList')
      protocol = template.annealProtocol
    else:
      molSystem = self.molSystem
      constraintSet = self.constraintSet
      shiftList = self.shiftList
      protocol = self.annealProtocol
    
    simRun = simStore.newRun(annealProtocol=protocol,
                             molSystem=molSystem,
                             inputConstraintStore=protocol)
    
    if shiftList:
      simRun.addInputMeasurementList(shiftList)                 
    
    if template:
      for param in template.runParameters:
        simRun.newRunParameter(code=param.code,
                               id=param.id,
                               booleanValue=param.booleanValue,
                               floatValue=param.floatValue,
                               intValue=param.intValue,
                               textValue=param.textValue)
    else:
       if self.chain:
         chainCode = self.chain.code
       else:
         chaincode = 'A'
    
       simRun.newRunParameter(code='FirstPepPlane',id=1, 
                              intValue=self.firstResEntry.get() or 0)
       simRun.newRunParameter(code='LastPepPlane' ,id=1, 
                              intValue=self.lastResEntry.get() or 0)
       simRun.newRunParameter(code='MaxOptSteps',  id=1, 
                              intValue=self.maxOptStepEntry.get() or 0)
       simRun.newRunParameter(code='NumOptPlanes', id=1, 
                              intValue=self.numOptPlaneEntry.get() or 0)
       simRun.newRunParameter(code='MinOptHits',   id=1, 
                              intValue=self.numOptHitsEntry.get() or 0)
       simRun.newRunParameter(code='ChainCode',    id=1,
                              textValue=chainCode)

    return simRun
 
  def selectRun(self, simRun):
  
    if self.run is not simRun:
      if simRun:
        if simRun.outputEnsemble:
          msg  = 'Selected run has already been used to generate a structure.'
          msg += 'A new run will be setup based on the selection.'
          showWarning('Warning',msg)
          simRun = self.makeSimRun(template=simRun)
 
        molSystem = simRun.molSystem
        constraintSet = simRun.inputConstraintStore
        shiftList = simRun.findFirstInputMeasurementList(className='ShiftList')
 
        if molSystem and (self.molSystem is not molSystem):
          self.molSystem = molSystem
          self.updateMolSystems()
 
        if constraintSet and (self.constraintSet is not constraintSet):
          self.constraintSet = constraintSet
          self.updateConstraintSets()
    
        if shiftList and (self.shiftList is not shiftList): 
          self.shiftList = shiftList
          self.updateShiftLists()
        
        firstPepPlane = simRun.findFirstrunParameter(code='FirstPepPlane')
        lastPepPlane = simRun.findFirstrunParameter(code='LastPepPlane')
        maxOptSteps = simRun.findFirstrunParameter(code='MaxOptSteps')
        numOptPlanes = simRun.findFirstrunParameter(code='NumOptPlanes')
        minOptHits = simRun.findFirstrunParameter(code='MinOptHits')
        chainCode = simRun.findFirstrunParameter(code='ChainCode')

        
        if firstPepPlane is not None:
          self.firstResEntry.set(firstPepPlane.intValue or 0)
        
        if lastPepPlane is not None:
          self.lastResEntry.set(lastPepPlane.intValue or 0)
          
        if maxOptSteps is not None:
          self.maxOptStepEntry.set(maxOptSteps.intValue or 0)
            
        if numOptPlanes is not None:
          self.numOptPlaneEntry.set(numOptPlanes.intValue or 0)
          
        if minOptHits is not None:
          self.numOptHitsEntry.set(minOptHits.intValue or 0)
           
        if chainCode is not None:
          chainCode = chainCode.textValue or 'A'
          if self.molSystem:
            chain = self.molSystem.findFirsChain(code=chainCode)
 
            if chain:
              self.selectChain(chain) 
                 
      self.run = simRun

  def updateShiftLists(self, *notifyObj):
    
    index = 0
    names = []
    nmrProject = self.project.currentNmrProject
    
    shiftLists = nmrProject.findAllMeasurementLists(className='ShiftList')
    shiftLists = [(sl.serial, sl) for sl in shiftLists]
    shiftLists.sort()
    shiftLists = [x[1] for x in shiftLists]
    
    shiftList = self.shiftList

    if shiftLists:
      if shiftList not in shiftLists:
        shiftList = shiftLists[0]
    
      index = shiftLists.index(shiftList)
      names = ['%d'% sl.serial for sl in shiftLists]
    
    if shiftList is not self.shiftList:
      if self.run:
        self.run.setInputMeasurementLists([shiftList])
  
    self.shiftListPulldown.setup(texts=names, objects=shiftLists, index=index)

  def selectShiftList(self, shiftList):
  
    if shiftList is not self.shiftList:
      if self.run:
        self.run.setInputMeasurementLists([shiftList])
      
      self.shiftList = shiftList                   
Example #27
0
class CingGui(BasePopup):
    def __init__(self, parent, options, *args, **kw):

        # Fill in below variable once run generates some results
        self.haveResults = None
        # store the options
        self.options = options

        BasePopup.__init__(self, parent=parent, title='CING Setup', **kw)

        #    self.setGeometry(850, 750, 50, 50)

        self.project = None

        #    self.tk_strictMotif( True)

        self.updateGui()

    # end def __init__

    def body(self, guiFrame):

        row = 0
        col = 0
        #    frame = Frame( guiFrame )
        #    frame.grid(row=row, column=col, sticky='news')
        self.menuBar = Menu(guiFrame)
        self.menuBar.grid(row=row, column=col, sticky='ew')

        #----------------------------------------------------------------------------------
        # Project frame
        #----------------------------------------------------------------------------------

        #    guiFrame.grid_columnconfigure(row, weight=1)
        #    frame = LabelFrame(guiFrame, text='Project', font=medFont)
        row = +1
        col = 0
        frame = LabelFrame(guiFrame, text='Project', **labelFrameAttributes)
        print '>', frame.keys()
        frame.grid(row=row, column=col, sticky='nsew')
        frame.grid_columnconfigure(2, weight=1)
        #    frame.grid_rowconfigure(0, weight=1)

        srow = 0
        self.projectOptions = [
            'old', 'new from PDB', 'new from CCPN', 'new from CYANA'
        ]
        self.projOptionsSelect = RadioButtons(frame,
                                              selected_index=0,
                                              entries=self.projectOptions,
                                              direction='vertical',
                                              select_callback=self.updateGui)
        self.projOptionsSelect.grid(row=srow,
                                    column=0,
                                    rowspan=len(self.projectOptions),
                                    columnspan=2,
                                    sticky='w')

        if self.options.name:
            text = self.options.name
        else:
            text = ''
        # end if
        self.projEntry = Entry(frame,
                               bd=1,
                               text=text,
                               returnCallback=self.updateGui)
        self.projEntry.grid(row=srow, column=2, columnspan=2, sticky='ew')
        #    self.projEntry.bind('<Key>', self.updateGui)
        self.projEntry.bind('<Leave>', self.updateGui)

        projButton = Button(frame,
                            bd=1,
                            command=self.chooseOldProjectFile,
                            text='browse')
        projButton.grid(row=srow, column=3, sticky='ew')

        srow += 1
        self.pdbEntry = Entry(frame, bd=1, text='')
        self.pdbEntry.grid(row=srow, column=2, sticky='ew')
        self.pdbEntry.bind('<Leave>', self.updateGui)

        pdbButton = Button(frame,
                           bd=1,
                           command=self.choosePdbFile,
                           text='browse')
        pdbButton.grid(row=srow, column=3, sticky='ew')

        srow += 1
        self.ccpnEntry = Entry(frame, bd=1, text='')
        self.ccpnEntry.grid(row=srow, column=2, sticky='ew')
        self.ccpnEntry.bind('<Leave>', self.updateGui)

        ccpnButton = Button(frame,
                            bd=1,
                            command=self.chooseCcpnFile,
                            text='browse')
        ccpnButton.grid(row=srow, column=3, sticky='ew')

        srow += 1
        self.cyanaEntry = Entry(frame, bd=1, text='')
        self.cyanaEntry.grid(row=srow, column=2, sticky='ew')
        self.cyanaEntry.bind('<Leave>', self.updateGui)

        cyanaButton = Button(frame,
                             bd=1,
                             command=self.chooseCyanaFile,
                             text='browse')
        cyanaButton.grid(row=srow, column=3, sticky='ew')

        #Empty row
        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow, column=0, sticky='nw')

        srow += 1
        label = Label(frame, text='Project name:')
        label.grid(row=srow, column=0, sticky='nw')
        self.nameEntry = Entry(frame, bd=1, text='')
        self.nameEntry.grid(row=srow, column=2, sticky='w')

        #Empty row
        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow, column=0, sticky='nw')

        srow += 1
        self.openProjectButton = Button(frame,
                                        command=self.openProject,
                                        text='Open Project',
                                        **actionButtonAttributes)
        self.openProjectButton.grid(row=srow,
                                    column=0,
                                    columnspan=4,
                                    sticky='ew')

        #----------------------------------------------------------------------------------
        # status
        #----------------------------------------------------------------------------------
        #    guiFrame.grid_columnconfigure(1, weight=0)
        srow = 0
        frame = LabelFrame(guiFrame, text='Status', **labelFrameAttributes)
        frame.grid(row=srow, column=1, sticky='wnes')
        self.projectStatus = Text(frame,
                                  height=11,
                                  width=70,
                                  borderwidth=0,
                                  relief='flat')
        self.projectStatus.grid(row=0, column=0, sticky='wen')

        #Empty row
        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow, column=0, sticky='nw')

        srow += 1
        self.closeProjectButton = Button(frame,
                                         command=self.closeProject,
                                         text='Close Project',
                                         **actionButtonAttributes)
        self.closeProjectButton.grid(row=srow,
                                     column=0,
                                     columnspan=4,
                                     sticky='ew')

        #----------------------------------------------------------------------------------
        # Validate frame
        #----------------------------------------------------------------------------------

        row += 1
        col = 0
        frame = LabelFrame(guiFrame, text='Validate', **labelFrameAttributes)
        #    frame = LabelFrame(guiFrame, text='Validate', font=medFont)
        frame.grid(row=row, column=col, sticky='nsew')
        #    frame.grid_columnconfigure(2, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        srow = 0
        #    label = Label(frame, text='validation')
        #    label.grid(row=srow,column=0,sticky='nw')
        #
        #    self.selectDoValidation = CheckButton(frame)
        #    self.selectDoValidation.grid(row=srow, column=1,sticky='nw' )
        #    self.selectDoValidation.set(True)
        #
        #    srow += 1
        #    label = Label(frame, text='')
        #    label.grid(row=srow,column=0,sticky='nw')
        #
        #    srow += 1
        label = Label(frame, text='checks')
        label.grid(row=srow, column=0, sticky='nw')

        self.selectCheckAssign = CheckButton(frame)
        self.selectCheckAssign.grid(row=srow, column=1, sticky='nw')
        self.selectCheckAssign.set(True)
        label = Label(frame, text='assignments and shifts')
        label.grid(row=srow, column=2, sticky='nw')

        #    srow += 1
        #    self.selectCheckQueen = CheckButton(frame)
        #    self.selectCheckQueen.grid(row=srow, column=4,sticky='nw' )
        #    self.selectCheckQueen.set(False)
        #    label = Label(frame, text='QUEEN')
        #    label.grid(row=srow,column=5,sticky='nw')
        #
        #    queenButton = Button(frame, bd=1,command=None, text='setup')
        #    queenButton.grid(row=srow,column=6,sticky='ew')

        srow += 1
        self.selectCheckResraint = CheckButton(frame)
        self.selectCheckResraint.grid(row=srow, column=1, sticky='nw')
        self.selectCheckResraint.set(True)
        label = Label(frame, text='restraints')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        self.selectCheckStructure = CheckButton(frame)
        self.selectCheckStructure.grid(row=srow, column=1, sticky='nw')
        self.selectCheckStructure.set(True)
        label = Label(frame, text='structural')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        self.selectMakeHtml = CheckButton(frame)
        self.selectMakeHtml.grid(row=srow, column=1, sticky='nw')
        self.selectMakeHtml.set(True)
        label = Label(frame, text='generate HTML')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        self.selectCheckScript = CheckButton(frame)
        self.selectCheckScript.grid(row=srow, column=1, sticky='nw')
        self.selectCheckScript.set(False)
        label = Label(frame, text='user script')
        label.grid(row=srow, column=0, sticky='nw')

        self.validScriptEntry = Entry(frame, bd=1, text='')
        self.validScriptEntry.grid(row=srow,
                                   column=2,
                                   columnspan=3,
                                   sticky='ew')

        scriptButton = Button(frame,
                              bd=1,
                              command=self.chooseValidScript,
                              text='browse')
        scriptButton.grid(row=srow, column=5, sticky='ew')

        srow += 1
        label = Label(frame, text='ranges')
        label.grid(row=srow, column=0, sticky='nw')
        self.rangesEntry = Entry(frame, text='')
        self.rangesEntry.grid(row=srow, column=2, columnspan=3, sticky='ew')

        #    self.validScriptEntry = Entry(frame, bd=1, text='')
        #    self.validScriptEntry.grid(row=srow,column=3,sticky='ew')
        #
        #    scriptButton = Button(frame, bd=1,command=self.chooseValidScript, text='browse')
        #    scriptButton.grid(row=srow,column=4,sticky='ew')

        srow += 1
        texts = ['Run Validation', 'View Results', 'Setup QUEEN']
        commands = [self.runCing, None, None]
        buttonBar = ButtonList(frame,
                               texts=texts,
                               commands=commands,
                               expands=True)
        buttonBar.grid(row=srow, column=0, columnspan=6, sticky='ew')
        for button in buttonBar.buttons:
            button.config(**actionButtonAttributes)
        # end for
        self.runButton = buttonBar.buttons[0]
        self.viewResultButton = buttonBar.buttons[1]
        self.queenButton = buttonBar.buttons[2]

        #----------------------------------------------------------------------------------
        # Miscellaneous frame
        #----------------------------------------------------------------------------------

        row += 0
        col = 1
        #    frame = LabelFrame(guiFrame, text='Miscellaneous', font=medFont)
        frame = LabelFrame(guiFrame,
                           text='Miscellaneous',
                           **labelFrameAttributes)
        frame.grid(row=row, column=col, sticky='news')
        frame.grid_columnconfigure(2, weight=1)
        frame.grid_columnconfigure(4, weight=1, minsize=30)
        frame.grid_rowconfigure(0, weight=1)

        # Exports

        srow = 0
        label = Label(frame, text='export to')
        label.grid(row=srow, column=0, sticky='nw')

        self.selectExportXeasy = CheckButton(frame)
        self.selectExportXeasy.grid(row=srow, column=1, sticky='nw')
        self.selectExportXeasy.set(True)
        label = Label(frame, text='Xeasy, Sparky, TALOS, ...')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        self.selectExportCcpn = CheckButton(frame)
        self.selectExportCcpn.grid(row=srow, column=1, sticky='nw')
        self.selectExportCcpn.set(True)
        label = Label(frame, text='CCPN')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        self.selectExportQueen = CheckButton(frame)
        self.selectExportQueen.grid(row=srow, column=1, sticky='nw')
        self.selectExportQueen.set(True)
        label = Label(frame, text='QUEEN')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        self.selectExportRefine = CheckButton(frame)
        self.selectExportRefine.grid(row=srow, column=1, sticky='nw')
        self.selectExportRefine.set(True)
        label = Label(frame, text='refine')
        label.grid(row=srow, column=2, sticky='nw')

        srow += 1
        label = Label(frame, text='')
        label.grid(row=srow, column=0, sticky='nw')

        # User script

        srow += 1
        label = Label(frame, text='user script')
        label.grid(row=srow, column=0, sticky='nw')

        self.selectMiscScript = CheckButton(frame)
        self.selectMiscScript.grid(row=srow, column=1, sticky='nw')
        self.selectMiscScript.set(False)

        self.miscScriptEntry = Entry(frame, bd=1, text='')
        self.miscScriptEntry.grid(row=srow, column=3, sticky='ew')

        script2Button = Button(frame,
                               bd=1,
                               command=self.chooseMiscScript,
                               text='browse')
        script2Button.grid(row=srow, column=4, sticky='ew')

        srow += 1
        texts = ['Export', 'Run Script']
        commands = [None, None]
        buttonBar = ButtonList(frame,
                               texts=texts,
                               commands=commands,
                               expands=True)
        buttonBar.grid(row=srow, column=0, columnspan=5, sticky='ew')
        for button in buttonBar.buttons:
            button.config(**actionButtonAttributes)
        # end for
        self.exportButton = buttonBar.buttons[0]
        self.scriptButton = buttonBar.buttons[1]

        #----------------------------------------------------------------------------------
        # Textarea
        #----------------------------------------------------------------------------------
        row += 1
        guiFrame.grid_rowconfigure(row, weight=1)
        self.outputTextBox = ScrolledText(guiFrame)
        self.outputTextBox.grid(row=row, column=0, columnspan=2, sticky='nsew')

        self.redirectConsole()

        #----------------------------------------------------------------------------------
        # Buttons
        #----------------------------------------------------------------------------------
        row += 1
        col = 0
        texts = ['Quit', 'Help']
        commands = [self.close, None]
        self.buttonBar = ButtonList(guiFrame,
                                    texts=texts,
                                    commands=commands,
                                    expands=True)
        self.buttonBar.grid(row=row, column=col, columnspan=2, sticky='ew')

        #    self.openProjectButton = self.buttonBar.buttons[0]
        #    self.closeProjectButton = self.buttonBar.buttons[1]
        #    self.runButton = self.buttonBar.buttons[0]
        #    self.viewResultButton = self.buttonBar.buttons[1]

        for button in self.buttonBar.buttons:
            button.config(**actionButtonAttributes)
        # end for

    # end def body

    def getGuiOptions(self):

        projectName = self.projEntry.get()

        index = self.projOptionsSelect.getIndex()

        if index > 0:
            makeNewProject = True
            projectImport = None

            if index > 1:
                i = index - 2
                format = ['PDB', 'CCPN', 'CYANA'][i]
                file = [self.pdbEntry, self.ccpnEntry,
                        self.cyanaEntry][i].get()

                if not file:
                    showWarning('Failure', 'No %s file selected' % format)
                    return
                # end if

                projectImport = (format, file)
            # end if

        else:
            # Chould also check that any old project file exists

            makeNewProject = False
            projectImport = None
        # end if

        doValidation = self.selectDoValidation.get()
        checks = []

        if doValidation:
            if self.selectCheckAssign.get():
                checks.append('assignments')
            # end if

            if self.selectCheckResraint.get():
                checks.append('restraints')
            # end if

            if self.selectCheckStructure.get():
                checks.append('structural')
            # end if

            if self.selectMakeHtml.get():
                checks.append('HTML')
            # end if

            if self.selectCheckScript.get():
                script = self.validScriptEntry.get()

                if script:
                    checks.append(('script', script))
                # end if
            # end if

            if self.selectCheckQueen.get():
                checks.append('queen')
            # end if
        # end if

        exports = []

        if self.selectExportXeasy.get():
            exports.append('Xeasy')
        # end if

        if self.selectExportCcpn.get():
            exports.append('CCPN')
        # end if

        if self.selectExportQueen.get():
            exports.append('QUEEN')
        # end if

        if self.selectExportRefine.get():
            exports.append('refine')
        # end if

        miscScript = None

        if self.selectMiscScript.get():
            script = self.miscScriptEntry.get()

            if script:
                miscScript = script
            # end if
        # end if

        return projectName, makeNewProject, projectImport, doValidation, checks, exports, miscScript

    # end def getGuiOptions

    def runCing(self):

        options = self.getGuiOptions()

        if options:

            projectName, makeNewProject, projectImport, doValidation, checks, exports, miscScript = options

            print 'Project name:', projectName
            print 'Make new project?', makeNewProject
            print 'Import source:', projectImport
            print 'Do vailidation?', doValidation
            print 'Validation checks:', ','.join(checks)
            print 'Export to:', ','.join(exports)
            print 'User script:', miscScript
        # end if

    # end def runCing

    # else there was already an error message

    def chooseOldProjectFile(self):

        fileTypes = [FileType('CING', ['project.xml']), FileType('All', ['*'])]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                title='Select CING project file',
                                dismiss_text='Cancel',
                                selected_file_must_exist=True)

        fileName = popup.getFile()
        #    dirName  = popup.getDirectory()

        if len(fileName) > 0:
            # Put text into entry,name widgets
            dummy, name = cing.Project.rootPath(fileName)
            self.projEntry.configure(state='normal')
            self.projEntry.set(fileName)

            self.nameEntry.configure(state='normal')
            self.nameEntry.set(name)
            self.nameEntry.configure(state='disabled')
            # choose the correct radiobutton
            self.projOptionsSelect.setIndex(0)
            self.updateGui()
        # end if
        #nd if

        popup.destroy()

    # end def chooseOldProjectFile

    def choosePdbFile(self):

        fileTypes = [FileType('PDB', ['*.pdb']), FileType('All', ['*'])]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                title='PDB file',
                                dismiss_text='Cancel',
                                selected_file_must_exist=True)

        fileName = popup.getFile()
        if len(fileName) > 0:
            # Put text into entry widget
            self.pdbEntry.configure(state='normal')
            self.pdbEntry.set(fileName)
            # Put text into name widget
            _dir, name, dummy = nTpath(fileName)
            self.nameEntry.configure(state='normal')
            self.nameEntry.set(name)
            # choose the correct radiobutton
            self.projOptionsSelect.setIndex(1)
            self.updateGui()
        #end if

        popup.destroy()

    # end def choosePdbFile

    def chooseCcpnFile(self):

        fileTypes = [FileType('XML', ['*.xml']), FileType('All', ['*'])]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                title='CCPN project XML file',
                                dismiss_text='Cancel',
                                selected_file_must_exist=True)

        fileName = popup.getFile()
        if len(fileName) > 0:
            self.pdbEntry.configure(state='normal')
            self.pdbEntry.set(fileName)
            self.projOptionsSelect.setIndex(1)

            _dir, name, dummy = nTpath(fileName)
            self.nameEntry.set(name)
        #end if
        self.ccpnEntry.set(fileName)
        self.projOptionsSelect.setIndex(2)

        popup.destroy()

    # end def chooseCcpnFile

    def chooseCyanaFile(self):

        # Prepend default Cyana file extension below
        fileTypes = [
            FileType('All', ['*']),
        ]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                title='CYANA fproject file',
                                dismiss_text='Cancel',
                                selected_file_must_exist=True)

        fileName = popup.getFile()
        self.cyanaEntry.set(fileName)
        self.projOptionsSelect.setIndex(3)

        popup.destroy()

    # end def chooseCyanaFile

    def chooseValidScript(self):

        # Prepend default Cyana file extension below
        fileTypes = [
            FileType('All', ['*']),
        ]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                title='Script file',
                                dismiss_text='Cancel',
                                selected_file_must_exist=True)

        fileName = popup.getFile()
        self.validScriptEntry.set(fileName)
        popup.destroy()

    # end def chooseValidScript

    def chooseMiscScript(self):

        # Prepend default Cyana file extension below
        fileTypes = [
            FileType('All', ['*']),
        ]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                title='Script file',
                                dismiss_text='Cancel',
                                selected_file_must_exist=True)

        fileName = popup.getFile()
        self.miscScriptEntry.set(fileName)
        popup.destroy()

    # end def chooseMiscScript

    def openProject(self):
        projOption = self.projOptionsSelect.get()
        if projOption == self.projectOptions[0]:
            self.openOldProject()
        elif projOption == self.projectOptions[1]:
            self.initPdb()
        # end if

        if self.project:
            self.project.gui = self
        # end if
        self.updateGui()

    #end def

    def openOldProject(self):
        fName = self.projEntry.get()
        if not os.path.exists(fName):
            nTerror('Error: file "%s" does not exist\n', fName)
        #end if

        if self.project:
            self.closeProject()
        # end if
        self.project = cing.Project.open(name=fName,
                                         status='old',
                                         verbose=False)

    #end def

    def initPdb(self):
        fName = self.pdbEntry.get()
        if not os.path.exists(fName):
            nTerror('Error: file "%s" does not exist\n', fName)
        #end if
        self.project = cing.Project.open(self.nameEntry.get(), status='new')
        self.project.initPDB(pdbFile=fName, convention='PDB')

    #end def

    def closeProject(self):
        if self.project:
            self.project.close()
        # end if
        self.project = None
        self.updateGui()

    #end def

    def updateGui(self, event=None):

        projOption = self.projOptionsSelect.get()
        buttons = self.buttonBar.buttons

        # Disable entries
        for e in [
                self.projEntry, self.pdbEntry, self.ccpnEntry, self.cyanaEntry,
                self.nameEntry
        ]:
            e.configure(state='disabled')
        #end for

        if projOption == self.projectOptions[0]:
            # Enable entries
            self.projEntry.configure(state='normal')

            if (len(self.projEntry.get()) > 0):
                self.openProjectButton.enable()
                self.runButton.enable()
            else:
                self.openProjectButton.disable()
                self.runButton.disable()
            #end if

        elif projOption == self.projectOptions[1]:
            # Enable entries
            self.pdbEntry.configure(state='normal')
            self.nameEntry.configure(state='normal')

            if (len(self.pdbEntry.get()) > 0
                    and len(self.nameEntry.get()) > 0):
                buttons[0].enable()
                buttons[1].enable()
            else:
                buttons[0].disable()
                buttons[1].disable()
            #end if
        #end if

        elif projOption == self.projectOptions[2]:
            # Enable entries
            self.ccpnEntry.configure(state='normal')
            self.nameEntry.configure(state='normal')

            if (len(self.ccpnEntry.get()) > 0
                    and len(self.nameEntry.get()) > 0):
                buttons[0].enable()
                buttons[1].enable()
            else:
                buttons[0].disable()
                buttons[1].disable()
            #end if
        #end if

        elif projOption == self.projectOptions[3]:
            # Enable entries
            self.cyanaEntry.configure(state='normal')
            self.nameEntry.configure(state='normal')

            if (len(self.cyanaEntry.get()) > 0
                    and len(self.nameEntry.get()) > 0):
                buttons[0].enable()
                buttons[1].enable()
            else:
                buttons[0].disable()
                buttons[1].disable()
            #end if
        #end if

        self.projectStatus.clear()
        if not self.project:
            self.projectStatus.setText('No open project')
            self.closeProjectButton.setText('Close Project')
            self.closeProjectButton.disable()
        else:
            self.projectStatus.setText(self.project.format())
            self.closeProjectButton.enable()
            self.closeProjectButton.setText(
                sprintf('Close Project "%s"', self.project.name))
        #end if

    #end def

    def redirectConsole(self):

        #pipe = TextPipe(self.inputTextBox.text_area)
        #sys.stdin = pipe

        pipe = TextPipe(self.outputTextBox.text_area)
        sys.stdout = pipe
        nTmessage.stream = pipe

    # end def redirectConsole
#    sys.stderr = pipe

    def resetConsole(self):
        #sys.stdin   = stdin
        nTmessage.stream = stdout
        sys.stdout = stdout
        sys.stderr = stderr

    # end def resetConsole

    def open(self):

        self.redirectConsole()
        BasePopup.open(self)

    # end def open

    def close(self):

        geometry = self.getGeometry()
        self.resetConsole()
        BasePopup.close(self)

        print 'close:', geometry
        sys.exit(0)  # remove later

    # end def close

    def destroy(self):

        geometry = self.getGeometry()
        self.resetConsole()
        BasePopup.destroy(self)

        print 'destroy:', geometry
        sys.exit(0)  # remove later
Example #28
0
class HelpFrame(Frame):
    def __init__(self,
                 parent,
                 width=70,
                 height=20,
                 xscroll=False,
                 yscroll=True,
                 *args,
                 **kw):

        apply(Frame.__init__, (self, parent) + args, kw)

        self.grid_columnconfigure(1, weight=1)

        row = 0
        texts = ('back', 'forward', 'load')
        commands = (self.prevUrl, self.nextUrl, self.loadUrl)
        self.buttons = ButtonList(self, texts=texts, commands=commands)
        self.buttons.grid(row=row, column=0)
        self.url_entry = Entry(self, returnCallback=self.loadUrl)
        self.url_entry.grid(row=row, column=1, columnspan=2, sticky=Tkinter.EW)
        row = row + 1

        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=3, sticky=Tkinter.W)
        self.createFindFrame(frame)
        row = row + 1

        self.grid_rowconfigure(row, weight=1)
        self.help_text = ScrolledHtml(self,
                                      width=width,
                                      height=height,
                                      xscroll=xscroll,
                                      yscroll=yscroll,
                                      startUrlCallback=self.startOpenUrl,
                                      endUrlCallback=self.endOpenUrl,
                                      enterLinkCallback=self.setLinkLabel,
                                      leaveLinkCallback=self.setLinkLabel)
        self.help_text.grid(row=row,
                            column=0,
                            columnspan=3,
                            sticky=Tkinter.NSEW)
        row = row + 1

        self.link_label = Label(self)
        self.link_label.grid(row=row, column=0, columnspan=2, sticky=Tkinter.W)
        button = memops.gui.Util.createDismissButton(self,
                                                     dismiss_cmd=self.close)
        button.grid(row=row, column=2)

        self.urls = []
        self.current = -1
        self.updateUrlList = True

        self.setButtonState()

    def close(self):

        if (self.popup):
            if (self.popup.modal):
                self.popup.do_grab()

        popup = self.parent
        while (not hasattr(popup, 'top')):
            popup = popup.parent
        popup.close()

    def createFindFrame(self, master):

        frame = Frame(master)
        frame.grid(row=0, column=0, sticky=Tkinter.W)

        arrow = ToggleArrow(frame, callback=self.toggleFindFrame)
        arrow.grid(row=0, column=0)
        button = Button(frame, text='find:', command=self.findPhrase)
        button.grid(row=0, column=1)
        self.find_entry = Entry(frame,
                                width=20,
                                returnCallback=self.findPhrase)
        self.find_entry.grid(row=0, column=2)

        self.find_frame = frame = Frame(master)

        entries = ('search forwards', 'search backwards')
        self.direction_buttons = PulldownMenu(frame, entries=entries)
        self.direction_buttons.grid(row=0, column=0, sticky=Tkinter.W, padx=5)

        self.forwards_entries = entries = ('wrap search', 'stop at end')
        self.backwards_entries = ('wrap search', 'stop at beginning')
        self.wrap_buttons = PulldownMenu(frame, entries=entries)
        self.wrap_buttons.grid(row=0, column=1, sticky=Tkinter.W, padx=5)

        self.direction_buttons.callback = self.setWrapText

        entries = ('case insensitive', 'case sensitive')
        self.case_buttons = PulldownMenu(frame, entries=entries)
        self.case_buttons.grid(row=0, column=2, sticky=Tkinter.W, padx=5)

        entries = ('literal search', 'regex search')
        self.pattern_buttons = PulldownMenu(frame, entries=entries)
        self.pattern_buttons.grid(row=0, column=3, sticky=Tkinter.W, padx=5)

        self.countVar = Tkinter.IntVar()

    def setWrapText(self, entry_ind, entry):

        if (entry_ind == 0):
            entries = self.forwards_entries
        else:
            entries = self.backwards_entries

        self.wrap_buttons.replace(
            entries, selected_index=self.wrap_buttons.getSelectedIndex())

    def findPhrase(self, *extra):

        phrase = self.find_entry.get()
        if (not phrase):
            showError('No find phrase', 'Enter phrase in entry box.')
            return

        if (self.direction_buttons.getSelectedIndex() == 0):
            forwards = 1
            backwards = 0
        else:
            forwards = 0
            backwards = 1

        if (self.case_buttons.getSelectedIndex() == 0):
            nocase = 1
        else:
            nocase = 0

        if (self.pattern_buttons.getSelectedIndex() == 0):
            exact = 1
            regexp = 0
        else:
            exact = 0
            regexp = 1

        start = self.help_text.tag_nextrange(Tkinter.SEL, '1.0')
        if (start):
            start = start[0]
            if (forwards):
                start = '%s+1c' % start
            else:
                start = '%s-1c' % start
        else:
            start = Tkinter.CURRENT

        if (self.wrap_buttons.getSelectedIndex() == 0):
            match = self.help_text.search(phrase,
                                          start,
                                          count=self.countVar,
                                          forwards=forwards,
                                          backwards=backwards,
                                          nocase=nocase,
                                          exact=exact,
                                          regexp=regexp)
        elif (forwards):
            match = self.help_text.search(phrase,
                                          start,
                                          count=self.countVar,
                                          forwards=forwards,
                                          backwards=backwards,
                                          nocase=nocase,
                                          exact=exact,
                                          regexp=regexp,
                                          stopindex=Tkinter.END)
        else:
            match = self.help_text.search(phrase,
                                          start,
                                          count=self.countVar,
                                          forwards=forwards,
                                          backwards=backwards,
                                          nocase=nocase,
                                          exact=exact,
                                          regexp=regexp,
                                          stopindex='1.0')

        if (match):
            self.help_text.see(match)
            self.help_text.setSelection(
                match, '%s+%dc' % (match, self.countVar.get()))
            self.help_text.tag_config(Tkinter.SEL, background='gray70')
        else:
            showInfo('No match', 'No match found for phrase.')

    def toggleFindFrame(self, isClosed):

        if (isClosed):
            self.find_frame.grid_forget()
        else:
            self.find_frame.grid(row=1, column=0, sticky=Tkinter.W)

    def setButtonState(self):

        n = len(self.urls)

        if ((n >= 2) and (self.current > 0)):
            state = Tkinter.NORMAL
        else:
            state = Tkinter.DISABLED
        self.buttons.buttons[0].config(state=state)

        if ((n >= 2) and (self.current < (n - 1))):
            state = Tkinter.NORMAL
        else:
            state = Tkinter.DISABLED
        self.buttons.buttons[1].config(state=state)

    def setLinkLabel(self, url=''):

        self.link_label.set(url)

    def loadUrl(self, *extra):

        url = self.url_entry.get()
        if (url):
            if (url.find(':') == -1):
                if (url[:2] != '//'):
                    url = '//' + url
                url = 'http:' + url
            self.showUrl(url, forceLoad=True)

    def newUrl(self, url):

        self.current = self.current + 1
        self.urls[self.current:] = [[url, 0.0]]
        self.setButtonState()
        #print 'newUrl', self.current, self.urls

    def prevUrl(self):

        if (self.current > 0):  # True if called via button
            (url, offset) = self.urls[self.current - 1]
            self.updateUrlList = False
            self.showUrl(url, offset=offset, allowModifyPath=False)
            self.updateUrlList = True
            self.current = self.current - 1
            self.setButtonState()
        #print 'prevUrl', self.current, self.urls

    def nextUrl(self):

        if (self.current < (len(self.urls) - 1)):  # True if called via button
            (url, offset) = self.urls[self.current + 1]
            self.updateUrlList = False
            self.showUrl(url, offset=offset, allowModifyPath=False)
            self.updateUrlList = True
            self.current = self.current + 1
            self.setButtonState()
        #print 'nextUrl', self.current, self.urls

    def showText(self, message, popup=None):

        self.popup = popup
        if (popup):
            self.parent.modal = popup.modal
        self.help_text.setState(Tkinter.NORMAL)  # so that can add text
        self.help_text.clear()  # clear existing text
        self.help_text.append(message)
        self.help_text.setState(Tkinter.DISABLED)  # make text read-only
        self.open()

    def startOpenUrl(self, yview):

        if (self.urls):
            self.urls[self.current][1] = yview[0]

    def endOpenUrl(self, url):

        #print 'endOpenUrl', url, self.updateUrlList
        self.url_entry.set(url)
        if (self.updateUrlList):
            self.newUrl(url)
        self.setLinkLabel()
        self.open()

    def showUrl(self,
                url,
                offset=None,
                forceLoad=False,
                allowModifyPath=True,
                popup=None):

        self.popup = popup
        if (popup):
            self.parent.modal = popup.modal
        self.help_text.openUrl(url,
                               forceLoad=forceLoad,
                               allowModifyPath=allowModifyPath)
        if (offset is not None):
            self.help_text.yview(Tkinter.MOVETO, str(offset))
Example #29
0
class CreateAxisUnitPopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        BasePopup.__init__(self,
                           parent=parent,
                           title='Create axis unit',
                           modal=True,
                           **kw)

    def body(self, master):

        master.grid_columnconfigure(1, weight=1)

        row = 0
        label = Label(master, text='Axis unit name: ', grid=(row, 0))
        tipText = 'Short textual name for the unit, e.g. "KPa" or "ms"'
        self.nameEntry = Entry(master,
                               width=10,
                               grid=(row, 1),
                               tipText=tipText)

        row += 1
        label = Label(master, text='Unit is backwards: ', grid=(row, 0))
        tipText = 'Whether the axis values decrease left to right & bottom to top. For example "ppm" does, but most units do not'
        self.backwardsMenu = BooleanPulldownMenu(master,
                                                 grid=(row, 1),
                                                 tipText=tipText)

        row += 1
        tipTexts = [
            'Make a new unit specification using the stated options and close this popup'
        ]
        texts = ['Create']
        commands = [self.ok]
        buttons = UtilityButtonList(master,
                                    texts=texts,
                                    commands=commands,
                                    closeText='Cancel',
                                    helpUrl=self.help_url,
                                    grid=(row, 0),
                                    gridSpan=(1, 2),
                                    tipTexts=tipTexts)

        master.grid_rowconfigure(row, weight=1)

    def apply(self):

        unit = self.nameEntry.get()
        if (not unit):
            showError('No unit', 'Need to enter unit')
            return False

        units = [axisUnit.unit for axisUnit in self.analysisProject.axisUnits]
        if (unit in units):
            showError('Repeated unit', 'Unit already used')
            return False

        isBackwards = self.backwardsMenu.getSelected()

        self.analysisProject.newAxisUnit(unit=unit, isBackwards=isBackwards)

        return True
Example #30
0
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)
Example #31
0
class PrintFrame(LabelFrame):
    def __init__(self,
                 parent,
                 getOption=None,
                 setOption=None,
                 text='Print Options',
                 haveTicks=False,
                 doOutlineBox=True,
                 *args,
                 **kw):

        self.getOption = getOption
        self.setOption = setOption
        self.haveTicks = haveTicks
        self.doOutlineBox = doOutlineBox

        LabelFrame.__init__(self, parent=parent, text=text, *args, **kw)

        self.file_select_popup = None

        self.getOptionValues()

        try:
            size_index = self.paper_types.index(self.paper_type)
        except:
            size_index = 0

        try:
            other_unit_index = self.paper_units.index(self.other_unit)
        except:
            other_unit_index = 0

        try:
            orientation_index = self.paper_orientations.index(self.orientation)
        except:
            orientation_index = 0

        try:
            style_index = self.style_choices.index(self.output_style)
        except:
            style_index = 0

        try:
            format_index = self.format_choices.index(self.output_format)
        except:
            format_index = 0

        if haveTicks:
            try:
                tick_location_index = self.tick_locations.index(
                    self.tick_location)
            except:
                tick_location_index = 0

        self.grid_columnconfigure(2, weight=1)

        row = 0
        label = Label(self, text='File:')
        label.grid(row=row, column=0, sticky='e')
        self.file_entry = Entry(self, width=40, text=self.file_name)
        self.file_entry.grid(row=row, column=1, columnspan=2, sticky='ew')
        button = Button(self, text='Choose File', command=self.findFile)
        button.grid(row=row, column=3, rowspan=2, sticky='nsew')

        row += 1
        label = Label(self, text='Title:')
        label.grid(row=row, column=0, sticky='e')
        self.title_entry = Entry(self, width=40, text=self.title)
        self.title_entry.grid(row=row, column=1, columnspan=2, sticky='ew')

        row += 1
        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=4, sticky='ew')
        frame.grid_columnconfigure(4, weight=1)

        label = Label(frame, text='Paper size:')
        label.grid(row=0, column=0, sticky='e')
        entries = []
        for t in paper_types:
            if t == Output.other_paper_type:
                entry = t
            else:
                (w, h, u) = paper_sizes[t]
                entry = t + ' (%2.1f %s x %2.1f %s)' % (w, u, h, u)
            entries.append(entry)
        self.size_menu = PulldownList(frame,
                                      callback=self.changedSize,
                                      texts=entries,
                                      index=size_index)
        self.size_menu.grid(row=0, column=1, sticky='w')

        self.other_frame = Frame(frame)

        self.other_frame.grid_columnconfigure(0, weight=1)
        self.other_entry = FloatEntry(self.other_frame,
                                      text=self.other_size,
                                      isArray=True)
        self.other_entry.grid(row=0, column=0, sticky='ew')
        self.other_unit_menu = PulldownList(self.other_frame,
                                            texts=paper_units,
                                            index=other_unit_index)
        self.other_unit_menu.grid(row=0, column=1, sticky='ew')

        row += 1
        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=4, sticky='ew')
        frame.grid_columnconfigure(1, weight=1)
        frame.grid_columnconfigure(3, weight=1)
        frame.grid_columnconfigure(5, weight=1)

        label = Label(frame, text='Orientation:')
        label.grid(row=0, column=0, sticky='e')
        self.orientation_menu = PulldownList(frame,
                                             texts=paper_orientations,
                                             index=orientation_index)
        self.orientation_menu.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='  Style:')
        label.grid(row=0, column=2, sticky='e')
        self.style_menu = PulldownList(frame,
                                       texts=style_choices,
                                       index=style_index)
        self.style_menu.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='  Format:')
        label.grid(row=0, column=4, sticky='e')
        self.format_menu = PulldownList(frame,
                                        callback=self.changedFormat,
                                        texts=format_choices,
                                        index=format_index)

        self.format_menu.grid(row=0, column=5, sticky='w')

        if haveTicks:

            row += 1
            frame = Frame(self)
            frame.grid(row=row, column=0, columnspan=4, sticky='ew')
            frame.grid_columnconfigure(1, weight=1)
            frame.grid_columnconfigure(3, weight=1)

            label = Label(frame, text='Tick Location:')
            label.grid(row=0, column=0, sticky='e')
            self.tick_menu = PulldownList(frame,
                                          texts=tick_locations,
                                          index=tick_location_index)
            self.tick_menu.grid(row=0, column=1, sticky='w')

            label = Label(frame, text='  Tick Placement:')
            label.grid(row=0, column=2, sticky='e')
            self.tick_buttons = CheckButtons(frame,
                                             entries=tick_placements,
                                             selected=self.tick_placement)
            self.tick_buttons.grid(row=0, column=3, sticky='w')

        row += 1
        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=4, sticky='ew')
        frame.grid_columnconfigure(3, weight=1)

        label = Label(frame, text='Include:')
        label.grid(row=0, column=0, sticky='e')
        self.border_buttons = CheckButtons(frame,
                                           entries=border_decorations,
                                           selected=self.border_decoration)
        self.border_buttons.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='  Scaling:')
        label.grid(row=0, column=2, sticky='e')
        self.scaling_scale = Scale(frame,
                                   orient=Tkinter.HORIZONTAL,
                                   value=self.scaling)
        self.scaling_scale.grid(row=0, column=3, sticky='ew')

    def destroy(self):

        self.setOptionValues()

        if self.file_select_popup:
            self.file_select_popup.destroy()

        Frame.destroy(self)

    def getOptionValues(self):

        getOption = self.getOption
        if getOption:

            file_name = getOption('FileName', defaultValue='')
            title = getOption('Title', defaultValue='')
            paper_type = getOption('PaperSize', defaultValue=paper_types[0])
            paper_type = paper_type_dict.get(paper_type, paper_types[0])
            other_height = getOption('OtherHeight', defaultValue=10)
            other_width = getOption('OtherWidth', defaultValue=10)
            other_size = [other_height, other_width]
            other_unit = getOption('OtherUnit', defaultValue=paper_units[0])
            orientation = getOption('Orientation',
                                    defaultValue=paper_orientations[0])
            in_color = getOption('InColor', defaultValue=True)
            if in_color:
                output_style = style_choices[0]
            else:
                output_style = style_choices[1]
            format_option = getOption('OutputFormat',
                                      defaultValue=format_options[0])
            output_format = format_choices[format_options.index(format_option)]
            if self.haveTicks:
                tick_outside = getOption('TickOutside',
                                         defaultValue=tick_locations[0])
                if tick_outside:
                    tick_location = tick_locations.index(PrintTicks.Outside)
                else:
                    tick_location = tick_locations.index(PrintTicks.Inside)
                tick_placement = getTickPlacement1(
                    getOption('TickPlacement', defaultValue='nsew'))
            dateTime = getOption('ShowsDateTime', defaultValue=True)
            fileName = getOption('ShowsFileName', defaultValue=True)
            border_decoration = []
            if dateTime:
                border_decoration.append(border_decorations[0])
            if fileName:
                border_decoration.append(border_decorations[1])
            scaling = getOption('Scaling', defaultValue=0.9)
            scaling = int(round(100.0 * scaling))

        else:

            file_name = ''
            title = ''
            paper_type = paper_types[0]
            other_unit = paper_units[0]
            other_size = ''
            orientation = paper_orientations[0]
            output_style = style_choices[0]
            output_format = format_choices[0]
            if self.haveTicks:
                tick_location = tick_locations[0]
                tick_placement = tick_placements
            border_decoration = border_decorations
            scaling = 90

        if not self.haveTicks:
            tick_location = None
            tick_placement = None

        self.file_name = file_name
        self.title = title
        self.paper_type = paper_type
        self.other_unit = other_unit
        self.other_size = other_size
        self.orientation = orientation
        self.output_style = output_style
        self.output_format = output_format
        self.tick_location = tick_location
        self.tick_placement = tick_placement
        self.border_decoration = border_decoration
        self.scaling = scaling

    def setOptionValues(self):

        self.file_name = file_name = self.file_entry.get()
        self.title = title = self.title_entry.get()

        n = self.size_menu.getSelectedIndex()
        self.paper_type = paper_type = paper_types[n]
        if paper_type == Output.other_paper_type:
            other_size = self.other_entry.get()
            other_unit = self.other_unit_menu.getText()
        else:
            other_size = None
            other_unit = None
        self.other_size = other_size
        self.other_unit = other_unit

        self.paper_orientation = paper_orientation = self.orientation_menu.getText(
        )
        self.output_style = output_style = self.style_menu.getText()
        self.output_format = output_format = self.format_menu.getText()

        if self.haveTicks:
            tick_location = self.tick_menu.getText()
            tick_placement = self.tick_buttons.getSelected()
        else:
            tick_location = tick_placement = None
        self.tick_location = tick_location
        self.tick_placement = tick_placement

        self.border_decoration = border_decoration = self.border_buttons.getSelected(
        )
        scaling = self.scaling_scale.get()
        self.scaling = scaling = int(round(scaling))

        setOption = self.setOption
        if setOption:
            setOption('FileName', value=file_name)
            setOption('Title', value=title)
            if paper_type == Output.other_paper_type:
                setOption('OtherHeight', value=other_size[0])
                setOption('OtherWidth', value=other_size[1])
                setOption('OtherUnit', value=other_unit)
            else:
                paper_type = paper_type_inverse_dict[paper_type]
                setOption('PaperSize', value=paper_type)
            setOption('Orientation', value=paper_orientation)
            in_color = (output_style == style_choices[0])
            setOption('InColor', value=in_color)
            output_format = format_options[format_choices.index(output_format)]
            setOption('OutputFormat', value=output_format)
            if self.haveTicks:
                tick_outside = (tick_location == PrintTicks.Outside)
                setOption('TickOutside', value=tick_outside)
                tick_placement = getTickPlacement2(tick_placement)
                setOption('TickPlacement', value=tick_placement)
            dateTime = (border_decorations[0] in border_decoration)
            fileName = (border_decorations[1] in border_decoration)
            setOption('ShowsDateTime', value=dateTime)
            setOption('ShowsFileName', value=fileName)
            setOption('Scaling', value=0.01 * scaling)

    def findFile(self):

        if self.file_select_popup:
            self.file_select_popup.open()
        else:
            file_types = [
                FileType('All', ['*']),
                FileType('PostScript', ['*.ps', '*.eps']),
                FileType('PDF', ['*.pdf', '*.ai'])
            ]
            self.file_select_popup = FileSelectPopup(self,
                                                     file_types=file_types)

        file = self.file_select_popup.getFile()
        if file:
            self.file_entry.set(file)

    def changedSize(self, entry):

        if entry == Output.other_paper_type:
            self.other_frame.grid(row=0, column=2, columnspan=2, sticky='w')
        else:
            self.other_frame.grid_forget()

    def changedFormat(self, entry):

        file_suffix = file_suffixes.get(entry)
        if not file_suffix:
            return

        file_name = self.file_entry.get()
        if not file_name:
            return

        for suffix in format_suffixes:
            if file_name.endswith(suffix):
                if suffix != file_suffix:
                    n = len(suffix)
                    file_name = file_name[:-n] + file_suffix
                    self.file_entry.set(file_name)
                break
        else:
            file_name = file_name + file_suffix
            self.file_entry.set(file_name)

    # width and height are of plot, in pixels
    def getOutputHandler(self, width, height, fonts=None):

        if not fonts:
            fonts = []
        else:
            fonts = list(fonts)

        for n in range(len(fonts)):
            if fonts[n] == 'Times':
                fonts[n] = 'Times-Roman'

        self.setOptionValues()

        if not self.file_name:
            showError('No file', 'No file specified', parent=self)
            return None

        if os.path.exists(self.file_name):
            if not showYesNo('File exists',
                             'File "%s" exists, overwrite?' % self.file_name,
                             parent=self):
                return None

        if (self.paper_type == Output.other_paper_type):
            paper_size = self.other_size + [self.other_unit]
        else:
            paper_size = paper_sizes[self.paper_type]
        output_scaling = self.scaling / 100.0

        font = 'Times-Roman'
        border_text = {}
        for decoration in self.border_decoration:
            if (decoration == 'Time & date'):
                location = 'se'
                text = time.ctime(time.time())
            elif (decoration == 'File name'):
                location = 'sw'
                text = self.file_name
            else:
                continue  # should not be here
            border_text[location] = (text, font, 12)
        if (self.title):
            location = 'n'
            border_text[location] = (self.title, font, 18)

        if font not in fonts:
            fonts.append(font)

        outputHandler = PrintHandler.getOutputHandler(
            self.file_name,
            width,
            height,
            output_scaling=output_scaling,
            paper_size=paper_size,
            paper_orientation=self.paper_orientation,
            output_style=self.output_style,
            output_format=self.output_format,
            border_text=border_text,
            fonts=fonts,
            do_outline_box=self.doOutlineBox)

        return outputHandler

    def getAspectRatio(self):

        self.setOptionValues()

        if self.paper_type == Output.other_paper_type:
            paper_size = self.other_size
        else:
            paper_size = paper_sizes[self.paper_type]

        r = paper_size[1] / paper_size[0]
        if self.paper_orientation == 'Landscape':
            r = 1.0 / r

        return r