Beispiel #1
0
class CalcHeteroNoePopup(BasePopup):
  """
  **Calculate Heteronuclear NOE Values From Peak Intensities**
  
  The purpose of this popup window is to calculate the heteronuclear NOE for
  amide resonances based upon a comparison of the peak intensities in spectra
  that derive from an NOE saturated experiment and an unsaturated (reference)
  experiment. The basic idea of this tool is that three peak lists are chosen,
  two of which are for heteronuclear NOE experiments (H,N axes); unsaturated
  reference and saturated, and one which is the source of assignments and peak
  locations. This last "Assignment" peak list may be the same as one of the NOE
  peak lists, but may also be entirely separate.

  The "Assignment" peak list is used to specify which peak assignments and
  locations should be used for the calculation of the heteronuclear NOE values,
  and thus can be used to specify only a subset of the resonances for
  measurement. For example, it is common to copy an HQSC peak list for use as
  the "Assignment" peak list but remove overlapped and NH2 peaks so that the NOE
  values are only calculated for separated backbone amides. The calculation
  process involves taking each of these assigned peaks and finding peaks with
  the same assignment in the NOE peak lists, or if that fails finding peaks with
  a similar position (within the stated tolerances); new peaks may be picked if
  the "Pick new peaks?" option is set.

  The first "Peak Lists & Settings" tab allows the user to choose the peak lists
  and various options that will be used in the peak-finding and NOE calculation.
  The "Peaks" table allows the peaks from each of the three peak list selections
  to be displayed when one of the "Show" buttons is clicked. The [Separate Peak
  Table] function allows these peaks to be displayed in the main, separate `Peak
  Lists`_ table, which has many more peak manipulation options. The options
  below the table may be used to locate selected peaks within the spectrum
  window displays.

  The second "Peak Intensity Comparison" tab is where the heteronuclear NOE
  values are actually calculated. Assuming that two NOE experiment peak lists
  have been chosen and that some of their peaks match the assigned peak
  positions then the peak intensities are extracted and NOE values automatically
  calculated when the tab is opened. Although, a refresh of the table can be
  forced with [Find Matching Peaks] at the bottom

  If pairs of NOE saturated and reference peaks are found then the actual
  heteronuclear NOE value is displayed as the "Intensity Ratio" in the last,
  rightmost, column of the table. To store these values as a NOE measurement
  list; so that the data can be saved in the CCPN project without need for
  recalculation, the [Create Hetero NOE List] function can be used. The results
  are then available to view at any time via the `Measurement Lists`_ table.

  **Caveats & Tips**

  Erroneous peak intensity comparisons may be removed with the [Remove Pairs]
  function, but its is common to curate the "Assign" peak list first and
  avoid tidying afterwards.

  The "Closeness score" can be used to find peak positions where the compared
  NOE peaks are unexpectedly far from one another.

  .. _`Peak Lists`: EditPeakListsPopup.html
  .. _`Measurement Lists`: EditMeasurementListsPopup.html
  
  """

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

    self.guiParent      = parent
    self.peakPairs      = []
    self.intensityType  = 'height'
    self.selectedPair   = None
    self.assignPeakList = None
    self.refPeakList    = None
    self.satPeakList    = None
    self.displayPeakList = None
    self.waiting        = 0
  
    BasePopup.__init__(self, parent, title="Data Analysis : Heteronuclear NOE", **kw)

  def body(self, guiFrame):

    self.geometry('700x700')
   
    guiFrame.expandGrid(0,0)
    
    options = ['Peak Lists & Settings','Peak Intensity Comparison']
    tabbedFrame = TabbedFrame(guiFrame, options=options, callback=self.changeTab)
    tabbedFrame.grid(row=0, column=0, sticky='nsew')
    self.tabbedFrame = tabbedFrame
    frameA, frameB = tabbedFrame.frames

    row = 0
    frameA.grid_columnconfigure(1, weight=1)
    frameA.grid_columnconfigure(3, weight=1)
    frameA.grid_columnconfigure(5, weight=1)
    frameA.grid_rowconfigure(5, weight=1)

    tipText = 'Number of reference peaks (no saturation)'
    self.peaksALabel = Label(frameA, text='Number of Ref Peaks: ', tipText=tipText)
    self.peaksALabel.grid(row=1,column=0,columnspan=2,sticky='w')

    tipText = 'Number of NOE saturation peaks'
    self.peaksBLabel = Label(frameA, text='Number of Sat Peaks: ', tipText=tipText)
    self.peaksBLabel.grid(row=1,column=2,columnspan=2,sticky='w')

    tipText = 'Number of peaks in assigned list'
    self.peaksCLabel = Label(frameA, text='Number of Assign Peaks: ', tipText=tipText)
    self.peaksCLabel.grid(row=1,column=4,columnspan=2,sticky='w')
    
    tipText = 'Selects which peak list is considered the NOE intensity reference (no saturation)'
    specALabel = Label(frameA, text='Ref Peak List: ')
    specALabel.grid(row=0,column=0,sticky='w')
    self.specAPulldown = PulldownList(frameA, callback=self.setRefPeakList, tipText=tipText)
    self.specAPulldown.grid(row=0,column=1,sticky='w')

    tipText = 'Selects which peak list is considered as NOE saturated.'
    specBLabel = Label(frameA, text='Sat Peak List: ')
    specBLabel.grid(row=0,column=2,sticky='w')
    self.specBPulldown = PulldownList(frameA, callback=self.setSatPeakList, tipText=tipText)
    self.specBPulldown.grid(row=0,column=3,sticky='w')

    tipText = 'Selects a peak list with assignments to use as a positional reference'
    specCLabel = Label(frameA, text='Assignment Peak List: ')
    specCLabel.grid(row=0,column=4,sticky='w')
    self.specCPulldown = PulldownList(frameA, callback=self.setAssignPeakList, tipText=tipText)
    self.specCPulldown.grid(row=0,column=5,sticky='w')

    frame0a = Frame(frameA)
    frame0a.grid(row=2,column=0,columnspan=6,sticky='nsew')
    frame0a.grid_columnconfigure(9, weight=1)
    
    tipText = '1H ppm tolerance for matching assigned peaks to reference & NOE saturation peaks'
    tolHLabel   = Label(frame0a, text='Tolerances: 1H')
    tolHLabel.grid(row=0,column=0,sticky='w')
    self.tolHEntry = FloatEntry(frame0a,text='0.02', width=6, tipText=tipText)
    self.tolHEntry .grid(row=0,column=1,sticky='w')  

    tipText = '15N ppm tolerance for matching assigned peaks to reference & NOE saturation peaks'
    tolNLabel   = Label(frame0a, text=' 15N')
    tolNLabel .grid(row=0,column=2,sticky='w')   
    self.tolNEntry = FloatEntry(frame0a,text='0.1', width=6, tipText=tipText)
    self.tolNEntry .grid(row=0,column=3,sticky='w')   

    tipText = 'Whether to peak new peaks in reference & NOE saturated lists (at assignment locations)'
    label = Label(frame0a, text=' Pick new peaks?', grid=(0,4)) 
    self.pickPeaksSelect = CheckButton(frame0a, tipText=tipText,
                                       grid=(0,5), selected=True)

    tipText = 'Whether to assign peaks in the peaks in the reference & NOE saturation lists, if not already assigned'
    label = Label(frame0a, text=' Assign peaks?')
    label.grid(row=0,column=6,sticky='w')   
    self.assignSelect = CheckButton(frame0a, tipText=tipText)
    self.assignSelect.set(1)
    self.assignSelect.grid(row=0,column=7,sticky='w')    

    tipText = 'Whether to consider peak height or volume in the heteronuclear NOE calculation'
    intensLabel = Label(frame0a, text=' Intensity Type:')
    intensLabel .grid(row=0,column=8,sticky='w')   
    self.intensPulldown = PulldownList(frame0a, texts=['height','volume'],
                                       callback=self.setIntensityType,
                                       tipText=tipText)
    self.intensPulldown.grid(row=0,column=9,sticky='w')    

    divider = LabelDivider(frameA, text='Peaks', grid=(3,0),
                           gridSpan=(1,6))

    tipTexts = ['Show the selected intensity reference peaks in the below table',
                'Show the selected NOE saturation peaks in the below table',
                'Show the selected assigned peak list in the below table',
                'Show the displayed peaks in a separate peak table, where assignments etc. may be adjusted']
    texts    = ['Show Ref Peaks','Show Sat Peaks',
                'Show Assign Peaks', 'Separate Peak Table']
    commands = [self.viewRefPeakList, self.viewSatPeakList,
                self.viewAssignPeakList, self.viewSeparatePeakTable]
    self.viewPeaksButtons = ButtonList(frameA, expands=True, tipTexts=tipTexts,
                                       texts=texts, commands=commands)
    self.viewPeaksButtons.grid(row=4,column=0,columnspan=6,sticky='nsew')

    self.peakTable = PeakTableFrame(frameA, self.guiParent, grid=(5,0),
                                    gridSpan=(1,6))
    self.peakTable.bottomButtons1.grid_forget()
    self.peakTable.bottomButtons2.grid_forget()
    #self.peakTable.topFrame.grid_forget()
    self.peakTable.topFrame.grid(row=2, column=0, sticky='ew')
    # Next tab

    frameB.expandGrid(0,0)
    
    tipTexts = ['Row number',
                'Assignment annotation for NOE saturation peak',
                'Assignment annotation for reference peak (no saturation)',
                '1H chemical shift of NOE saturation peak',
                '1H chemical shift of reference peak',
                '15N chemical shift of NOE saturation peak',
                '15N chemical shift of reference peak',
                'The separation between compared peaks: square root of the sum of ppm differences squared',
                'The intensity if the NOE saturation peak',
                'The intensity of the reference peak (no saturation)',
                'Ratio of peak intensities: saturated over reference',
                'Residue(s) for reference peak']
    colHeadings      = ['#','Sat Peak','Ref Peak','1H shift A',
                        '1H shift B','15N shift A','15N shift B',
                        'Closeness\nScore','Intensity A','Intensity B',
                        'Intensity\nRatio','Residue']
    self.scrolledMatrix = ScrolledMatrix(frameB, multiSelect=True, 
                                         headingList=colHeadings,
                                         callback=self.selectCell,
                                         tipTexts=tipTexts,
                                         grid=(0,0),
                                         deleteFunc=self.removePair)

    tipTexts = ['Force a manual update of the table; pair-up NOE saturation and reference peaks according to assigned peak positions',
                'Remove the selected rows of peak pairs',
                'Show peaks corresponding to the selected row in a table',
                'Save the Heteronuclear NOE values in the CCPN project as a data list']
    texts    = ['Refresh Table','Remove Pairs',
                'Show Peak Pair','Create Hetero NOE List']
    commands = [self.matchPeaks,self.removePair,
                self.showPeakPair,self.makeNoeList]
    self.pairButtons = ButtonList(frameB, tipTexts=tipTexts, grid=(1,0),
                                  texts=texts, commands=commands)


    bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, helpUrl=self.help_url)
    bottomButtons.grid(row=0, column=0, sticky='e')
    
    self.updatePulldowns()
    self.updateAfter()

    self.administerNotifiers(self.registerNotify)

  def administerNotifiers(self, notifyFunc):

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

    for func in ('__init__', 'delete','setAnnotation','setFigOfMerit'):
      notifyFunc(self.updatePeaks, 'ccp.nmr.Nmr.Peak', func)
    for func in ('setAnnotation','setPosition','setNumAliasing'):
      notifyFunc(self.updatePeakChild, 'ccp.nmr.Nmr.PeakDim', func)
    for func in ('__init__', 'delete', 'setValue'):
      notifyFunc(self.updatePeakChild, 'ccp.nmr.Nmr.PeakIntensity', func)

  def changeTab(self, index):
  
    if index == 1:
      self.matchPeaks()

  def open(self):
  
    self.updatePulldowns()
    self.updateAfter()
    BasePopup.open(self)
    
    
  def destroy(self):
  
    self.administerNotifiers(self.unregisterNotify)

    BasePopup.destroy(self)
 
  def updatePulldowns(self, *obj):

    index0 = 0
    index1 = 0
    index2 = 0
    names, peakLists = self.getPeakLists()
    
    if names:

      if self.refPeakList not in peakLists:
        self.refPeakList = peakLists[0]

      if  self.satPeakList not in peakLists:
        self.satPeakList = peakLists[0]

      if self.assignPeakList not in peakLists:
        self.assignPeakList = peakLists[0]

      index0 = peakLists.index(self.refPeakList)
      index1 = peakLists.index(self.satPeakList)
      index2 = peakLists.index(self.assignPeakList)
    
    self.specAPulldown.setup(names, peakLists, index0)
    self.specBPulldown.setup(names, peakLists, index1)
    self.specCPulldown.setup(names, peakLists, index2)

  def updatePeakChild(self,peakChild):
  
    if self.waiting:
      return
    
    self.updatePeaks(peakChild.peak)
  
  def updatePeaks(self, peak):
  
    if self.waiting:
      return
    
    if peak.peakList in (self.refPeakList,self.satPeakList,self.assignPeakList):
      if peak.isDeleted and (peak.peakList in (self.refPeakList,self.satPeakList) ):
        for peaks in self.peakPairs:
          if peak in peaks:
            self.peakPairs.remove(peaks)
            if self.selectedPair is peaks:
              self.selectedPair = None
            self.updateAfter()
            return
            
      self.updateAfter()
 
  def setIntensityType(self, intensityType):
    
    self.intensityType = intensityType
    self.updateAfter()
  
  def viewRefPeakList(self):
  
    if self.refPeakList:
      self.updatePeakTable(self.refPeakList)
   
  def viewSatPeakList(self):
  
    if self.satPeakList:
      self.updatePeakTable(self.satPeakList)
  
  def viewAssignPeakList(self):
  
    if self.assignPeakList:
      self.updatePeakTable(self.assignPeakList)
  
  def viewSeparatePeakTable(self):
  
    if self.displayPeakList:
      self.guiParent.editPeakList(peakList=self.displayPeakList)
  
  def setRefPeakList(self, refPeakList):
  
    if self.displayPeakList is self.refPeakList:
      self.updatePeakTable(refPeakList)

    self.refPeakList = refPeakList
    self.updateViewButtons()
    self.updateAfter()
  
  def setSatPeakList(self, satPeakList):
  
    if self.displayPeakList is self.satPeakList:
      self.updatePeakTable(satPeakList)
      
    self.satPeakList = satPeakList
    self.updateViewButtons()
    self.updateAfter()
  
  def setAssignPeakList(self, assignPeakList):
  
    if self.displayPeakList is self.assignPeakList:
      self.updatePeakTable(assignPeakList)
      
    self.assignPeakList = assignPeakList
    self.updateViewButtons()
    self.updateAfter()
  
  def getPeakListName(self, peakList):
  
    if peakList:
      spectrum = peakList.dataSource
      experiment = spectrum.experiment
      name = '%s:%s:%d' % (experiment.name, spectrum.name, peakList.serial)
    else:
      name = '<None>'
  
    return name
  
  def getPeakLists(self):
  
    names = []
    peakLists = []
    
    for experiment in self.nmrProject.sortedExperiments():
      for dataSource in experiment.sortedDataSources():
        if dataSource.numDim == 2:
          dimsN = findSpectrumDimsByIsotope(dataSource,'15N')
          dimsH = findSpectrumDimsByIsotope(dataSource,'1H')
          if len(dimsN) == 1 and len(dimsH) == 1:
            for peakList in dataSource.sortedPeakLists():
              name = self.getPeakListName(peakList)
              names.append( name )
              peakLists.append(peakList)
    
    return names, peakLists
  
  def showPeakPair(self):
  
    if self.selectedPair:
      self.guiParent.viewPeaks(self.selectedPair)
          
  def selectCell(self, object, row, col):
  
    self.selectedPair = object

    if self.selectedPair:
      self.pairButtons.buttons[1].enable()
      self.pairButtons.buttons[2].enable()
    else:
      self.pairButtons.buttons[1].disable()
      self.pairButtons.buttons[2].disable()
  
  def removePair(self, *event):
  
    pairs = self.scrolledMatrix.currentObjects
    
    if pairs:
      for pair in pairs:
        self.peakPairs.remove(pair)
        
      self.selectedPair = None
      self.updateAfter()
  
  def matchPeaks(self):
  
    # assign relative to reference
    
    if self.assignPeakList and self.assignPeakList.peaks and self.refPeakList and self.satPeakList:
 
      tolH = float( self.tolHEntry.get() )
      tolN = float( self.tolNEntry.get() )
      pickNewPeaks = self.pickPeaksSelect.get()
      doAssign     = self.assignSelect.get()
 
      dimH  = findSpectrumDimsByIsotope(self.assignPeakList.dataSource,'1H' )[0]
      dimHA = findSpectrumDimsByIsotope(self.refPeakList.dataSource,'1H' )[0]
      dimHB = findSpectrumDimsByIsotope(self.satPeakList.dataSource,'1H' )[0]
      dimN  = 1-dimH
      dimNA = 1-dimHA
      dimNB = 1-dimHB
 
      tolerancesA = [0,0]
      tolerancesA[dimHA] = tolH
      tolerancesA[dimNA] = tolN

      tolerancesB = [0,0]
      tolerancesB[dimHB] = tolH
      tolerancesB[dimNB] = tolN
 
      self.peakPairs = matchHnoePeaks(self.assignPeakList,self.refPeakList,
                                      self.satPeakList,tolerancesA,tolerancesB,
                                      pickNewPeaks,doAssign)
 
      self.updateAfter()
 
  def makeNoeList(self):

    if self.refPeakList is self.satPeakList:
      showWarning('Same Peak List',
                  'Ref Peak List and Sat Peak List cannot be the same',
                  parent=self)
      return

    if self.peakPairs:
      s1 = self.refPeakList.dataSource
      s2 = self.satPeakList.dataSource
      noiseRef = getSpectrumNoise(s1)
      noiseSat = getSpectrumNoise(s2)
      
      es = '%s-%s' % (s1.experiment.name,s2.experiment.name)
      if len(es) > 50:
        es = 'Expt(%d)-Expt(%d)' % (s1.experiment.serial,s2.experiment.serial)

      noeList = self.nmrProject.newNoeList(unit='None',name='Hetero NOE list for %s' % es)
      noeList.setExperiments([s1.experiment,])
      if s1.experiment is not s2.experiment:
        noeList.addExperiment( s2.experiment )
      # TBD: sf, noeValueType, refValue, refDescription
    
      resonancePairsSeen = set()
      for (peakA,peakB) in self.peakPairs: # peakA is sat
        intensA    = getPeakIntensity(peakA,self.intensityType)
        intensB    = getPeakIntensity(peakB,self.intensityType)
        value      = float(intensA)/intensB
        error      = abs(value) * sqrt((noiseSat/intensA)**2 + (noiseRef/intensB)**2)
        resonances = tuple(self.getPeakResonances(peakA))
        frozenResonances = frozenset(resonances)
        if len(resonances) < 2:
          pl = peakA.peakList
          sp = pl.dataSource
          msg = 'Skipping %s:%s:%d peak %d it has too few resonances assigned'
          data = (sp.experiment.name, sp.name, pl.serial, peakA.serial)
          showWarning('Warning',msg % data, parent=self)
        
        elif len(resonances) > 2:
          pl = peakA.peakList
          sp = pl.dataSource
          resonanceText = ' '.join([makeResonanceGuiName(r) for r in resonances])
          msg = 'Skipping %s:%s:%d peak %d it has too many resonances assigned (%s)'
          data = (sp.experiment.name, sp.name, pl.serial, peakA.serial, resonanceText)
          showWarning('Warning', msg % data, parent=self)
        
        elif frozenResonances not in resonancePairsSeen:
          resonancePairsSeen.add(frozenResonances)
          noeList.newNoe(value=value,resonances=resonances,peaks=[peakA,peakB],error=error)
          
        else:
          resonanceText = ' '.join([makeResonanceGuiName(r) for r in resonances])
          msg = 'Skipping duplicate entry for resonances %s' % resonanceText
          showWarning('Warning', msg, parent=self)

      self.parent.editMeasurements(measurementList=noeList)

  def getPeakResonances(self,peak):
  
    resonances = []
    for peakDim in peak.sortedPeakDims():
      for contrib in peakDim.sortedPeakDimContribs():
        resonances.append(contrib.resonance)
    
    return resonances

  def updateAfter(self, *opt):

    if self.waiting:
      return
    else:
      self.waiting = True
      self.after_idle(self.update)
 
  def updateViewButtons(self):
  
    if self.refPeakList:
      self.viewPeaksButtons.buttons[0].enable()
    else:
      self.viewPeaksButtons.buttons[0].disable()
  
    if self.satPeakList:
      self.viewPeaksButtons.buttons[1].enable()
    else:
      self.viewPeaksButtons.buttons[1].disable()
  
    if self.assignPeakList:
      self.viewPeaksButtons.buttons[2].enable()
    else:
      self.viewPeaksButtons.buttons[2].disable()
  
  def updatePeakTable(self, peakList):
    
    if peakList is not self.displayPeakList:
      self.displayPeakList = peakList
      self.peakTable.update(peaks=peakList.sortedPeaks())

  
  def update(self):

    if self.refPeakList:
      self.peaksALabel.set( 'Number of Ref Peaks: %d' % len(self.refPeakList.peaks) )
    else:
      self.peaksALabel.set( 'Number of Ref Peaks: %d' % 0 )
    if self.satPeakList:
      self.peaksBLabel.set( 'Number of Sat Peaks: %d' % len(self.satPeakList.peaks) )
    else:
      self.peaksBLabel.set( 'Number of Sat Peaks: %d' % 0 )
    if self.assignPeakList:
      self.peaksCLabel.set( 'Number of Assign Peaks: %d' % len(self.assignPeakList.peaks) )
    else:
      self.peaksCLabel.set( 'Number of Assign Peaks: %d' % 0 )

    if self.refPeakList and self.satPeakList and self.assignPeakList:
      if self.refPeakList is self.satPeakList:
        self.pairButtons.buttons[0].disable()
      else:
        self.pairButtons.buttons[0].enable()
    else:
      self.pairButtons.buttons[0].disable()
 
    if self.selectedPair:
      self.pairButtons.buttons[1].enable()
      self.pairButtons.buttons[2].enable()
    else:
      self.pairButtons.buttons[1].disable()
      self.pairButtons.buttons[2].disable()

    if self.peakPairs:
      self.pairButtons.buttons[3].enable()
      dsA = self.peakPairs[0][0].peakList.dataSource
      dsB = self.peakPairs[0][1].peakList.dataSource
      dimHA = findSpectrumDimsByIsotope(dsA,'1H')[0]
      dimHB = findSpectrumDimsByIsotope(dsB,'1H')[0]
      dimNA = findSpectrumDimsByIsotope(dsA,'15N')[0]
      dimNB = findSpectrumDimsByIsotope(dsB,'15N')[0]
    else:
      self.pairButtons.buttons[3].disable()
    
    objectList  = []
    textMatrix  = []

    i = 0
    for (peakA,peakB) in self.peakPairs:
      i += 1

      peakDimsA = peakA.sortedPeakDims()
      peakDimsB = peakB.sortedPeakDims()

      ppm0 = peakDimsA[dimHA].value
      ppm1 = peakDimsB[dimHB].value
      ppm2 = peakDimsA[dimNA].value
      ppm3 = peakDimsB[dimNB].value
      d0 = abs(ppm0-ppm1)
      d1 = abs(ppm2-ppm3)
      intensA = getPeakIntensity(peakA,self.intensityType)
      intensB = getPeakIntensity(peakB,self.intensityType)
      datum = []
      datum.append( i )
      datum.append( getPeakAnnotation(peakA, doPeakDims=False) )
      datum.append( getPeakAnnotation(peakB, doPeakDims=False) )
      datum.append( ppm0 )
      datum.append( ppm1 )
      datum.append( ppm2 )
      datum.append( ppm3 )
      datum.append( sqrt((d0*d0)+(d1*d1)) )
      datum.append( intensA )
      datum.append( intensB )
      if intensB:
        datum.append( float(intensA)/intensB )
      else:
        datum.append( None )
      seqCodes = ','.join(['%s' % seqCode for seqCode in getPeakSeqCodes(peakB)])
      datum.append(seqCodes)
      
      objectList.append( (peakA,peakB) )
      textMatrix.append( datum )
      
    if not objectList:
      textMatrix.append([])

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

    self.waiting = False
Beispiel #2
0
class ViewResidueFrame(Frame):

    showAssign = True
    chemCompVar = None
    residue = None

    def __init__(self,
                 parent,
                 residue=None,
                 resizeCallback=None,
                 project=None,
                 tipText=None,
                 shiftList=None,
                 *args,
                 **kw):

        self.shiftList = shiftList

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

        self.grid_columnconfigure(2, weight=1)

        row = 0
        self.label = Label(self, text='', grid=(row, 0))

        self.assignSelect = CheckButton(
            self,
            callback=self.setDisplayAssign,
            grid=(row, 1),
            tipText='Whether to show chemical shifts of assigned atoms')

        label0 = Label(self, text='Show Assignments', grid=(row, 2))

        row += 1
        self.grid_rowconfigure(row, weight=1)
        self.varFrame = ViewChemCompVarFrame(self,
                                             chemCompVar=self.chemCompVar,
                                             project=project,
                                             tipText=tipText,
                                             grid=(row, 0),
                                             gridSpan=(1, 3))

        self.assignSelect.set(True)

    def setDisplayAssign(self, trueOrFalse):

        self.showAssign = trueOrFalse

        self.update(self.residue)

    def setResidue(self, residue):

        self.residue = residue
        shiftList = self.shiftList

        if residue:
            self.varFrame.update(self.residue.chemCompVar)

            cAtomDict = self.varFrame.cAtomDict
            for atom in self.residue.atoms:
                chemAtom = atom.chemAtom
                cAtom = cAtomDict.get(chemAtom)

                if cAtom and self.showAssign:
                    shifts = getAtomSetShifts(atom.atomSet, shiftList)
                    label = '/'.join(
                        ['%3.3f' % (shift.value) for shift in shifts])
                    cAtom.setAnnotation(chemAtom.name + ' ' + label)

            self.varFrame.drawStructure()
            chain = self.residue.chain
            self.label.set('Residue: %d%s ( %s %s )' %
                           (self.residue.seqCode, getResidueCode(self.residue),
                            chain.molSystem.code, chain.code))

        else:
            self.varFrame.update(None)
            self.label.set('Residue: <None>')

    def update(self, residue=None, shiftList=None):

        self.shiftList = shiftList
        self.setResidue(residue)

    def printStructure(self):

        self.varFrame.printStructure()
Beispiel #3
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
Beispiel #4
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                   
Beispiel #5
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
Beispiel #6
0
class ViewChemicalShiftsPopup(BasePopup):
    """
  **A Table of Chemical Shifts for Export**
  
  This section is designed to make a layout of a table for chemical shifts  on a
  per-residue basis which may them be exported as either PostScript, for
  printing and graphical manipulation, or as plain text for import into other
  software or computer scripts. 

  The user chooses the molecular chain (which sequence) and the shift list to
  use at the top of the popup, together with a few other options that control
  how things are rendered. Then buttons are toggled to select which kinds of
  atom will be displayed in aligned columns; other kinds will simply be listed
  to the right of the columns. Thus for example if the shift list does not
  contain any carbonyl resonances in a protein chain then the user may toggle
  the empty "C" column off.

  Once the desired layout is achieved the user then uses the [Export PostScript]
  or [Export Text] buttons to write the data into a file of the appropriate
  type. The user will be presented wit ha file browser to specify the location
  and the name of the file to be saved. It should be noted that although the
  graphical display in the popup itself is somewhat limited, e.g. the gaps and
  spacing doesn't always look perfect, the PostScript version that is exported
  is significantly neater.

  **Caveats & Tips**

  If you need a chemical shift list represented in a particular format, specific
  for a particular external NMR program then you should use the FormatConverter
  software.

  Chemical shifts may also be exported from any table in Analysis that contains
  such data by clicking the right mouse button over the table and selecting the
  export option. 

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

        self.shiftList = None
        self.font = 'Helvetica 10'
        self.boldFont = 'Helvetica 10 bold'
        self.symbolFont = 'Symbol 8'
        self.smallFont = 'Helvetica 8'
        self.chain = None
        self.textOut = ''
        self.textMatrix = []

        BasePopup.__init__(self,
                           parent=parent,
                           title='Chart : Chemical Shifts Table')

    def body(self, guiFrame):

        row = 0
        frame = Frame(guiFrame, grid=(row, 0))
        frame.expandGrid(None, 6)

        label = Label(frame, text='Chain:', grid=(0, 0))
        tipText = 'Selects which molecular chain to show residues and chemical shift values for'
        self.chainPulldown = PulldownList(frame,
                                          callback=self.changeChain,
                                          grid=(0, 1),
                                          tipText=tipText)

        label = Label(frame, text='  Shift List:', grid=(0, 2))
        tipText = 'Selects which shift list is used to derive the displayed chemical shift values'
        self.shiftListPulldown = PulldownList(frame,
                                              callback=self.changeShiftList,
                                              grid=(0, 3),
                                              tipText=tipText)

        label = Label(frame, text=' List all shifts:', grid=(0, 4))
        tipText = 'Sets whether to display all the chemical shifts for residues or just for the nominated atom types in columns'
        self.otherShiftsSelect = CheckButton(frame,
                                             callback=self.draw,
                                             grid=(0, 5),
                                             tipText=tipText)

        utilButtons = UtilityButtonList(frame,
                                        helpUrl=self.help_url,
                                        grid=(0, 7))

        row += 1
        frame = Frame(guiFrame, grid=(row, 0))
        frame.expandGrid(None, 6)

        label = Label(frame, text=' 1-letter codes:', grid=(0, 0))
        tipText = 'Whether to use 1-letter residue codes in the table, or otherwise Ccp/three-letter codes'
        self.oneLetterSelect = CheckButton(frame,
                                           callback=self.draw,
                                           grid=(0, 1),
                                           selected=False,
                                           tipText=tipText)

        precisions = [0.1, 0.01, 0.001]
        texts = [str(t) for t in precisions]
        label = Label(frame, text='  1H precision:', grid=(0, 2))
        tipText = 'Specifies how many decimal places to use when displaying 1H chemical shift values'
        self.protonPrecisionSelect = PulldownList(frame,
                                                  texts=texts,
                                                  objects=precisions,
                                                  callback=self.draw,
                                                  index=1,
                                                  grid=(0, 3),
                                                  tipText=tipText)

        label = Label(frame, text='  Other precision:')
        label.grid(row=0, column=4, sticky='w')
        tipText = 'Specifies how many decimal places to use when displaying chemical shift values for isotopes other than 1H'
        self.otherPrecisionSelect = PulldownList(frame,
                                                 texts=texts,
                                                 objects=precisions,
                                                 callback=self.draw,
                                                 index=1,
                                                 grid=(0, 5),
                                                 tipText=tipText)

        row += 1
        frame = Frame(guiFrame, grid=(row, 0))
        frame.expandGrid(None, 1)

        label = Label(frame, text='Column\nAtoms:', grid=(0, 0))
        tipText = 'Selects which kinds of atoms are displayed in aligned columns, or otherwise displayed at the end of the residue row (if "List all shifts" is set)'
        self.optSelector = PartitionedSelector(frame,
                                               self.toggleOpt,
                                               tipText=tipText,
                                               maxRowObjects=10,
                                               grid=(0, 1),
                                               sticky='ew')
        options = ['H', 'N', 'C', 'CA', 'CB', 'CG']
        self.optSelector.update(objects=options,
                                labels=options,
                                selected=['H', 'N', 'CA'])

        row += 1
        guiFrame.expandGrid(row, 0)
        self.canvasFrame = ScrolledCanvas(guiFrame,
                                          relief='groove',
                                          width=650,
                                          borderwidth=2,
                                          resizeCallback=None,
                                          grid=(row, 0),
                                          padx=1,
                                          pady=1)
        self.canvas = self.canvasFrame.canvas
        #self.canvas.bind('<Button-1>', self.toggleResidue)

        row += 1
        tipTexts = [
            'Output information from the table as PostScript file, for printing etc.',
            'Output information from the table as a whitespace separated plain text file'
        ]
        commands = [self.makePostScript, self.exportText]
        texts = ['Export PostScript', 'Export Text']
        buttonList = ButtonList(guiFrame,
                                commands=commands,
                                texts=texts,
                                grid=(row, 0),
                                tipTexts=tipTexts)

        chains = self.getChains()
        if len(chains) > 1:
            self.chain = chains[1]
        else:
            self.chain = None

        self.updateShiftLists()
        self.updateChains()
        self.otherShiftsSelect.set(True)
        self.update()

        for func in ('__init__', 'delete'):
            self.registerNotify(self.updateChains,
                                'ccp.molecule.MolSystem.Chain', func)
        for func in ('__init__', 'delete'):
            self.registerNotify(self.updateShiftLists, 'ccp.nmr.Nmr.ShiftList',
                                func)

    def changeShiftList(self, shiftList):

        if shiftList is not self.shiftList:
            self.shiftList = shiftList
            self.update()

    def updateShiftLists(self, *opt):

        names = []
        index = 0

        shiftLists = getShiftLists(self.nmrProject)

        shiftList = self.shiftList

        if shiftLists:
            names = [
                '%s [%d]' % (sl.name or '<No name>', sl.serial)
                for sl in shiftLists
            ]
            if shiftList not in shiftLists:
                shiftList = shiftLists[0]

            index = shiftLists.index(shiftList)

        if self.shiftList is not shiftList:
            self.shiftList = shiftList

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

    def getChains(self):

        chains = [
            None,
        ]
        for molSystem in self.project.sortedMolSystems():
            for chain in molSystem.sortedChains():
                if len(chain.residues) > 1:
                    chains.append(chain)

        return chains

    def changeChain(self, chain):

        if chain is not self.chain:
            self.chain = chain
            self.update()

    def updateChains(self, *opt):

        names = []
        index = -1

        chains = self.getChains()
        chain = self.chain

        if len(chains) > 1:
            names = [
                'None',
            ] + ['%s:%s' % (ch.molSystem.code, ch.code) for ch in chains[1:]]
            if chain not in chains:
                chain = chains[1]

            index = chains.index(chain)

        else:
            chain = None

        self.chainPulldown.setup(names, chains, index)

    def destroy(self):

        for func in ('__init__', 'delete'):
            self.unregisterNotify(self.updateChains,
                                  'ccp.molecule.MolSystem.Chain', func)
        for func in ('__init__', 'delete'):
            self.unregisterNotify(self.updateShiftLists,
                                  'ccp.nmr.Nmr.ShiftList', func)

        BasePopup.destroy(self)

    def exportText(self, *event):

        from memops.gui.FileSelect import FileType
        from memops.gui.FileSelectPopup import FileSelectPopup

        if self.textOut:
            fileTypes = [
                FileType('Text', ['*.txt']),
                FileType('CSV', ['*.csv']),
                FileType('All', ['*'])
            ]
            fileSelectPopup = FileSelectPopup(self,
                                              file_types=fileTypes,
                                              title='Save table as text',
                                              dismiss_text='Cancel',
                                              selected_file_must_exist=False)

            fileName = fileSelectPopup.getFile()

            if fileName:
                file = open(fileName, 'w')
                if fileName.endswith('.csv'):
                    for textRow in self.textMatrix:
                        file.write(','.join(textRow) + '\n')
                else:
                    file.write(self.textOut)

    def toggleOpt(self, selected):

        self.draw()

    def makePostScript(self):

        self.canvasFrame.printCanvas()

    def update(self):

        colors = []
        selected = set()
        atomNames = set()

        if self.chain:
            for residue in self.chain.sortedResidues():
                for atom in residue.atoms:
                    chemAtom = atom.chemAtom

                    if colorDict.get(chemAtom.elementSymbol) is None:
                        continue

                    if chemAtom.waterExchangeable:
                        continue

                    atomNames.add(atom.name[:2])

                molType = residue.molResidue.molType
                if molType == 'protein':
                    selected.add('H')
                    selected.add('N')
                    selected.add('CA')
                    selected.add('C')

                elif molType == 'DNA':
                    selected.add("C1'")

                elif molType == 'RNA':
                    selected.add("C1'")

                elif molType == 'carbohydrate':
                    selected.add("C1")

        else:
            for spinSystem in self.shiftList.nmrProject.resonanceGroups:
                if not spinSystem.residue:
                    for resonance in spinSystem.resonances:
                        for name in resonance.assignNames:
                            atomNames.add(name)

        options = list(atomNames)

        molType = 'protein'
        if self.chain:
            molType = self.chain.molecule.molType
        options = greekSortAtomNames(options, molType=molType)

        if 'H' in options:
            options.remove('H')
            options = [
                'H',
            ] + options
        colors = [colorDict.get(n[0]) for n in options]

        if options and not selected:
            selected = [
                options[0],
            ]

        self.optSelector.update(objects=options,
                                labels=options,
                                colors=colors,
                                selected=list(selected))

        self.draw()

    def draw(self, *opt):

        if not self.shiftList:
            return

        nmrProject = self.shiftList.nmrProject
        shiftList = self.shiftList
        font = self.font
        bfont = self.boldFont
        symbolFont = self.symbolFont
        sFont = self.smallFont
        bbox = self.canvas.bbox
        doOthers = self.otherShiftsSelect.get()

        spc = 4
        gap = 14
        x = gap
        y = gap
        ct = self.canvas.create_text
        cl = self.canvas.create_line
        cc = self.canvas.coords

        self.canvas.delete('all')

        ssDict = {}

        formatDict = {
            0.1: '%.1f',
            0.01: '%.2f',
            0.001: '%.3f',
        }

        protonFormat = formatDict[self.protonPrecisionSelect.getObject()]
        otherFormat = formatDict[self.otherPrecisionSelect.getObject()]

        uSpinSystems = []
        chains = set()
        molSystems = set()

        for spinSystem in nmrProject.resonanceGroups:

            residue = spinSystem.residue
            if residue:
                ssDict[residue] = ssDict.get(residue, []) + [
                    spinSystem,
                ]
            else:
                uSpinSystems.append((spinSystem.serial, spinSystem))

        uSpinSystems.sort()

        commonAtoms = self.optSelector.getSelected()
        N = len(commonAtoms)

        chain = self.chain

        if chain:
            spinSystems = []
            for residue in chain.sortedResidues():
                spinSystems0 = ssDict.get(residue, [])

                for spinSystem in spinSystems0:
                    if spinSystem and spinSystem.resonances:
                        spinSystems.append([residue, spinSystem])
        else:
            spinSystems = uSpinSystems

        strings = []

        doOneLetter = self.oneLetterSelect.get()

        if spinSystems:

            x = gap
            y += gap

            numItems = []
            codeItems = []
            commonItems = []
            otherItems = []

            numWidth = 0
            codeWidth = 0
            commonWidths = [0] * N
            commonCounts = [0] * N

            for residue, spinSystem in spinSystems:

                if type(residue) is type(1):
                    seqNum = '{%d}' % residue

                    if doOneLetter:
                        ccpCode = '-'
                    else:
                        ccpCode = spinSystem.ccpCode or ''

                else:
                    if doOneLetter:
                        ccpCode = residue.chemCompVar.chemComp.code1Letter

                    else:
                        ccpCode = getResidueCode(residue)

                    seqNum = str(residue.seqCode)

                subStrings = []
                subStrings.append(seqNum)
                subStrings.append(ccpCode)

                item = ct(x, y, text=seqNum, font=font, anchor='se')
                box = bbox(item)
                iWidth = box[2] - box[0]
                numWidth = max(numWidth, iWidth)
                numItems.append(item)

                item = ct(x, y, text=ccpCode, font=font, anchor='sw')
                box = bbox(item)
                iWidth = box[2] - box[0]
                codeWidth = max(codeWidth, iWidth)
                codeItems.append(item)

                commonShifts, commonElements, otherShifts = self.getShiftData(
                    spinSystem, shiftList, commonAtoms)

                items = []
                for i in range(N):
                    values = commonShifts[i]
                    element = commonElements[i]

                    if element == 'H':
                        shiftFormat = protonFormat
                    else:
                        shiftFormat = otherFormat

                    subItems = []
                    for value in values:
                        text = shiftFormat % value

                        if text:
                            item = ct(x, y, text=text, font=font, anchor='se')
                            box = bbox(item)
                            iWidth = box[2] - box[0]
                            commonWidths[i] = max(commonWidths[i], iWidth)
                            commonCounts[i] += 1
                            subItems.append(item)

                    subStrings.append(
                        ','.join([shiftFormat % v for v in values]) or '-')

                    items.append(subItems)

                commonItems.append(items)

                if doOthers:
                    items0 = []
                    i = 0
                    I = len(otherShifts)
                    for atomLabel, element, value in otherShifts:

                        label = atomLabel
                        if label[0] == '?':
                            label = label[3:-1]

                        if element == 'H':
                            shiftFormat = protonFormat
                        else:
                            shiftFormat = otherFormat

                        subStrings.append('%6s:%-4s' %
                                          (shiftFormat % value, label))
                        i += 1

                        atoms = atomLabel.split('|')

                        items = []
                        j = 0
                        for atom in atoms:
                            text = element
                            if j > 0:
                                text = '/' + text

                            item = ct(x, y, text=text, font=font, anchor='sw')
                            box = bbox(item)
                            iWidth = box[2] - box[0] - 3
                            items.append((iWidth, item, 0))

                            p = len(element)
                            if len(atom) > p:
                                letter = atom[p]
                                if letter not in ('0123456789'):
                                    item = ct(x,
                                              y,
                                              text=letter.lower(),
                                              font=symbolFont,
                                              anchor='sw')
                                    box = bbox(item)
                                    iWidth = box[2] - box[0] - 2
                                    items.append((iWidth, item, -4))
                                    p += 1

                            text = atom[p:]
                            if text:
                                item = ct(x,
                                          y,
                                          text=text,
                                          font=sFont,
                                          anchor='sw')
                                box = bbox(item)
                                iWidth = box[2] - box[0] - 2
                                items.append((iWidth, item, -4))
                            j += 1

                        text = ' ' + shiftFormat % value
                        if i != I:
                            text += ','

                        item = ct(x, y, text=text, font=font, anchor='sw')
                        box = bbox(item)
                        iWidth = box[2] - box[0] - 4
                        items.append((iWidth, item, 0))

                        items0.append(items)

                    otherItems.append(items0)

                strings.append(subStrings)

            y0 = y
            x = x0 = gap + numWidth + codeWidth + spc + spc
            for i in range(N):

                if not commonCounts[i]:
                    continue

                x += commonWidths[i] + spc + spc

                element = commonElements[i]

                iWidth = 0
                text = commonAtoms[i][len(element):].lower()
                if text:
                    item = ct(x, y, text=text, font=symbolFont, anchor='se')
                    box = bbox(item)
                    iWidth = box[2] - box[0] - 2

                ct(x - iWidth, y, text=element, font=font, anchor='se')

            y += gap

            for i in range(len(numItems)):
                x = gap + numWidth + spc

                cc(numItems[i], x, y)

                x += spc

                cc(codeItems[i], x, y)

                x += codeWidth

                x1 = x + spc

                yM = y
                for j in range(N):
                    if not commonCounts[j]:
                        continue

                    x += commonWidths[j] + spc + spc

                    items = commonItems[i][j]

                    yB = y - gap
                    for item in items:
                        yB += gap
                        cc(item, x, yB)
                        yM = max(yB, yM)

                x += gap

                if doOthers:
                    x += spc
                    x3 = x

                    for items in otherItems[i]:
                        if x > 550:
                            x = x3
                            y += gap

                        for iWidth, item, dy in items:
                            cc(item, x, y + dy)
                            x += iWidth

                y = max(y, yM)
                y += gap

            x = x0
            for i in range(N):
                if not commonCounts[i]:
                    continue

                x += commonWidths[i] + spc + spc

                cl(x + 8, y0, x + 8, y - gap, width=0.3, fill='#808080')

            cl(x1, y0, x1, y - gap, width=0.3, fill='#808080')
            cl(0, 0, 550, 0, width=0.3, fill='#FFFFFF')

            y += gap

        textWidths = {}
        for subStrings in strings:
            for i, text in enumerate(subStrings):
                if text and len(text) > textWidths.get(i, 0):
                    textWidths[i] = len(text)
                else:
                    textWidths[i] = 0

        formats = {}
        for i in textWidths.keys():
            formats[i] = ' %%%ds' % max(6, textWidths[i])

        textOut = '!'
        textRow = ['', '']
        textMatrix = [textRow]
        textOut += ' ' * (max(6, textWidths.get(0, 6)) +
                          max(6, textWidths.get(1, 6)) + 1)

        i = 2
        for atom in commonAtoms:
            if i in formats:
                textOut += formats[i] % atom
                textRow.append((formats[i] % atom).strip())
                i += 1
        textOut += '\n'

        for subStrings in strings:
            textRow = []
            textMatrix.append(textRow)
            i = 0
            for text in subStrings:
                textOut += formats[i] % text
                textRow.append((formats[i] % text).strip())
                i += 1

            textOut += '\n'

        self.textOut = textOut
        self.textMatrix = textMatrix

    def getShiftData(self,
                     spinSystem,
                     shiftList,
                     commonAtoms=('H', 'N', 'CA', 'CB')):

        commonShifts = []
        commonResonances = {}
        commonElements = []

        for atomName in commonAtoms:
            elements = set()
            resonances = []

            for resonance in spinSystem.resonances:
                resonanceSet = resonance.resonanceSet

                if resonanceSet:
                    for atomSet in resonanceSet.atomSets:
                        for atom in atomSet.atoms:
                            if atomName == atom.name[:2]:
                                resonances.append(resonance)
                                break

                        else:
                            continue
                        break

                else:
                    for assignName in resonance.assignNames:
                        if atomName == assignName[:2]:
                            resonances.append(resonance)
                            break

            shiftValues = []
            for resonance in resonances:
                isotope = resonance.isotope
                if isotope:
                    elements.add(isotope.chemElement.symbol)
                commonResonances[resonance] = True
                shift = resonance.findFirstShift(parentList=shiftList)
                if shift:
                    shiftValues.append(shift.value)

            if not elements:
                element = atomName[0]
            else:
                element = elements.pop()

            commonElements.append(element)
            commonShifts.append(shiftValues)

        otherShifts = []
        for resonance in spinSystem.resonances:
            if not commonResonances.get(resonance):
                shift = resonance.findFirstShift(parentList=shiftList)

                if shift:
                    isotope = resonance.isotope

                    if isotope:
                        element = isotope.chemElement.symbol
                    else:
                        element = '??'

                    if resonance.assignNames or resonance.resonanceSet:
                        name = getResonanceName(resonance)
                    else:
                        name = '??[%d]' % resonance.serial

                    otherShifts.append((name, element, shift.value))

        molType = 'protein'
        if spinSystem.residue:
            molType = spinSystem.residue.molResidue.molType

        otherShifts = greekSortAtomNames(otherShifts, molType)

        return commonShifts, commonElements, otherShifts
Beispiel #7
0
class MidgePopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.guiParent = parent
        self.project = parent.getProject()
        self.waiting = 0
        self.specFreq = 800.13
        self.maxIter = 15
        self.mixTime = 60
        self.corrTime = 11.5
        self.leakRate = 2.0
        self.ratioHD = 0.9
        self.peakListDict = {}
        self.peakListDict3d = {}
        self.noesyPeakList = None
        self.noesy3dPeakList = None
        self.carbonLabel = 0
        self.nitrogenLabel = 1
        self.noesyPeakList1 = None
        self.noesyPeakList2 = None
        self.noesyPeakList3 = None
        self.noesyPeakList3d = None

        self.resonances = None
        self.noesyPeaks = None
        self.distanceConstraintList = None
        self.antiDistConstraintList = None
        self.adcAtomTypes = None
        self.structure = None

        BasePopup.__init__(self,
                           parent,
                           title="Relaxation Matrix Optimisation",
                           **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)

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

        row = 0
        labelFrame0 = LabelFrame(guiFrame, text='Input data')
        labelFrame0.grid(row=row, column=0, sticky=Tkinter.NSEW)
        labelFrame0.grid_columnconfigure(3, weight=1)

        label = Label(labelFrame0, text='Assigned NOESY spectrum')
        label.grid(row=0, column=0, sticky=Tkinter.NW)
        self.noesyPulldown = PulldownMenu(labelFrame0,
                                          entries=self.getNoesys(),
                                          callback=self.setNoesy,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.noesyPulldown.grid(row=0, column=1, sticky=Tkinter.NW)

        label = Label(labelFrame0, text='H/D ratio: ')
        label.grid(row=0, column=2, sticky=Tkinter.NW)
        self.ratioHDEntry = FloatEntry(labelFrame0, text=self.ratioHD, width=6)
        self.ratioHDEntry.grid(row=0, column=3, sticky=Tkinter.NW)

        label = Label(labelFrame0, text='NOESY spectrum 1:')
        label.grid(row=1, column=0, sticky=Tkinter.NW)
        self.tmix1Pulldown = PulldownMenu(labelFrame0,
                                          entries=self.getNoesys(),
                                          callback=self.setNoesy1,
                                          selected_index=-0,
                                          do_initial_callback=0)
        self.tmix1Pulldown.grid(row=1, column=1, sticky=Tkinter.NW)
        label = Label(labelFrame0, text='Tmix (ms): ')
        label.grid(row=1, column=2, sticky=Tkinter.NW)
        self.tmix1Entry = FloatEntry(labelFrame0, text=60, width=6)
        self.tmix1Entry.grid(row=1, column=3, sticky=Tkinter.NW)

        label = Label(labelFrame0, text='NOESY spectrum 2:')
        label.grid(row=2, column=0, sticky=Tkinter.NW)
        self.tmix2Pulldown = PulldownMenu(labelFrame0,
                                          entries=self.getNoesys(),
                                          callback=self.setNoesy2,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.tmix2Pulldown.grid(row=2, column=1, sticky=Tkinter.NW)
        label = Label(labelFrame0, text='Tmix (ms): ')
        label.grid(row=2, column=2, sticky=Tkinter.NW)
        self.tmix2Entry = FloatEntry(labelFrame0, text=120, width=6)
        self.tmix2Entry.grid(row=2, column=3, sticky=Tkinter.NW)

        label = Label(labelFrame0, text='NOESY spectrum 3:')
        label.grid(row=3, column=0, sticky=Tkinter.NW)
        self.tmix3Pulldown = PulldownMenu(labelFrame0,
                                          entries=self.getNoesys(),
                                          callback=self.setNoesy3,
                                          selected_index=0,
                                          do_initial_callback=0)
        self.tmix3Pulldown.grid(row=3, column=1, sticky=Tkinter.NW)
        label = Label(labelFrame0, text='Tmix (ms): ')
        label.grid(row=3, column=2, sticky=Tkinter.NW)
        self.tmix3Entry = FloatEntry(labelFrame0, text=200, width=6)
        self.tmix3Entry.grid(row=3, column=3, sticky=Tkinter.NW)

        label = Label(labelFrame0, text='3D NOESY:')
        label.grid(row=4, column=0, sticky=Tkinter.NW)
        self.noesy3dPulldown = PulldownMenu(labelFrame0,
                                            entries=self.getNoesys3d(),
                                            callback=self.setNoesy3d,
                                            selected_index=0,
                                            do_initial_callback=0)
        self.noesy3dPulldown.grid(row=4, column=1, sticky=Tkinter.NW)

        label10 = Label(labelFrame0, text='Num peaks:')
        label10.grid(row=5, column=0, sticky=Tkinter.NW)
        self.numPeaksLabel = Label(labelFrame0, text='0')
        self.numPeaksLabel.grid(row=5, column=1, sticky=Tkinter.NW)

        label11 = Label(labelFrame0, text='Num resonances:')
        label11.grid(row=5, column=2, sticky=Tkinter.NW)
        self.numResonancesLabel = Label(labelFrame0, text='0')
        self.numResonancesLabel.grid(row=5, column=3, sticky=Tkinter.NW)

        row += 1
        labelFrame1 = LabelFrame(guiFrame, text='Parameters')
        labelFrame1.grid(row=row, column=0, sticky=Tkinter.NSEW)
        labelFrame1.grid_columnconfigure(3, weight=1)

        label = Label(labelFrame1, text='15N labelled sample:')
        label.grid(row=0, column=0, sticky=Tkinter.NW)
        self.nitrogenSelect = CheckButton(labelFrame1,
                                          callback=self.setNitrogenLabel)
        self.nitrogenSelect.grid(row=0, column=1, sticky=Tkinter.W)
        self.nitrogenSelect.set(1)

        label = Label(labelFrame1, text='13C labelled sample:')
        label.grid(row=0, column=2, sticky=Tkinter.NW)
        self.carbonSelect = CheckButton(labelFrame1,
                                        callback=self.setCarbonLabel)
        self.carbonSelect.grid(row=0, column=3, sticky=Tkinter.W)
        self.carbonSelect.set(0)

        labelFrame1.grid_rowconfigure(1, weight=1)
        data = [
            self.specFreq, self.maxIter, self.mixTime, self.corrTime,
            self.leakRate
        ]
        colHeadings = [
            'Spectrometer\nfrequency', 'Max\niterations', 'Mixing\ntime (ms)',
            'Correl.\ntime (ns)', 'Leak\nrate'
        ]
        editWidgets = [
            self.specFreqEntry,
            self.maxIterEntry,
            self.mixTimeEntry,
            self.corrTimeEntry,
            self.leakRateEntry,
        ]
        editGetCallbacks = [
            self.getSpecFreq,
            self.getMaxIter,
            self.getMixTime,
            self.getCorrTime,
            self.getLeakRate,
        ]
        editSetCallbacks = [
            self.setSpecFreq,
            self.setMaxIter,
            self.setMixTime,
            self.setCorrTime,
            self.setLeakRate,
        ]
        self.midgeParamsMatrix = ScrolledMatrix(
            labelFrame1,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            editWidgets=editWidgets,
            maxRows=1,
            initialCols=5,
            headingList=colHeadings,
            callback=None,
            objectList=[
                'None',
            ],
            textMatrix=[
                data,
            ])
        self.midgeParamsMatrix.grid(row=1,
                                    column=0,
                                    columnspan=4,
                                    sticky=Tkinter.NSEW)

        label10 = Label(labelFrame1, text='Benchmark structure')
        label10.grid(row=2, column=0, sticky=Tkinter.NW)
        self.structurePulldown = PulldownMenu(labelFrame1,
                                              entries=self.getStructures(),
                                              callback=self.setStructure,
                                              selected_index=0,
                                              do_initial_callback=0)
        self.structurePulldown.grid(row=2, column=1, sticky=Tkinter.NW)

        label11 = Label(labelFrame1, text='ADC atom types:')
        label11.grid(row=2, column=2, sticky=Tkinter.NW)
        self.adcAtomsPulldown = PulldownMenu(labelFrame1,
                                             entries=self.getAdcAtomTypes(),
                                             callback=self.setAdcAtomTypes,
                                             selected_index=0,
                                             do_initial_callback=0)
        self.adcAtomsPulldown.grid(row=2, column=3, sticky=Tkinter.NW)

        row += 1
        labelFrame2 = LabelFrame(guiFrame, text='Output')
        labelFrame2.grid(row=row, column=0, sticky=Tkinter.NSEW)
        labelFrame2.grid_columnconfigure(3, weight=1)

        label20 = Label(labelFrame2, text='Distance constraints:')
        label20.grid(row=0, column=0, sticky=Tkinter.NW)
        self.distConstrLabel = Label(labelFrame2, text='0')
        self.distConstrLabel.grid(row=0, column=1, sticky=Tkinter.NW)

        label21 = Label(labelFrame2, text='Anti-distance constraints:')
        label21.grid(row=0, column=2, sticky=Tkinter.NW)
        self.antiConstrLabel = Label(labelFrame2, text='0')
        self.antiConstrLabel.grid(row=0, column=3, sticky=Tkinter.NW)

        texts = [
            'Calculate distances', 'Show distance\nconstraints',
            'Show anti-distance\nconstraints'
        ]
        commands = [
            self.calculateDistances, self.showConstraints,
            self.showAntiConstraints
        ]
        self.midgeButtons = ButtonList(labelFrame2,
                                       expands=1,
                                       texts=texts,
                                       commands=commands)
        self.midgeButtons.grid(row=1,
                               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,
                                columnspan=4,
                                sticky=Tkinter.EW)

        self.getPeaks()
        self.getResonances()
        self.update()

        self.geometry('600x400')

    def setCarbonLabel(self, boolean):

        self.carbonLabel = boolean

    def setNitrogenLabel(self, boolean):

        self.nitrogenLabel = boolean

    def update(self):

        if self.resonances and (
            (self.noesyPeaks and self.noesyPeakList1 and self.noesyPeakList2
             and self.noesyPeakList3) or self.noesyPeakList3d):
            self.midgeButtons.buttons[0].enable()
        else:
            self.midgeButtons.buttons[0].disable()

        if self.distanceConstraintList:
            self.distConstrLabel.set(
                str(len(self.distanceConstraintList.constraints)))
            self.midgeButtons.buttons[1].enable()
        else:
            self.distConstrLabel.set('')
            self.midgeButtons.buttons[1].disable()

        if self.antiDistConstraintList:
            self.antiConstrLabel.set(
                str(len(self.antiDistConstraintList.constraints)))
            self.midgeButtons.buttons[2].enable()
        else:
            self.antiConstrLabel.set('')
            self.midgeButtons.buttons[2].disable()

        if self.resonances:
            self.numResonancesLabel.set(str(len(self.resonances)))
        else:
            self.numResonancesLabel.set('')

        if self.noesyPeaks:
            self.numPeaksLabel.set(str(len(self.noesyPeaks)))
        else:
            self.numPeaksLabel.set('')

    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 ['<None>', 'HN', 'HN HA', 'HN HA HB']

    def setAdcAtomTypes(self, index, name=None):

        if name is None:
            name = self.adcAtomsPulldown.getSelected()

        if name == '<None>':
            name = None

        self.adcAtomTypes = name

    def getResonances(self):

        resonanceDict = {}
        if self.noesyPeaks:
            for peak in self.noesyPeaks:
                for peakDim in peak.peakDims:
                    for contrib in peakDim.peakDimContribs:
                        resonanceDict[contrib.resonance] = 1
                        # TBD: Set resonance.name for typing

        self.resonances = resonanceDict.keys()

    def getPeaks(self):

        if self.noesyPeakList:
            self.noesyPeaks = self.noesyPeakList.sortedPeaks()

    def calculateDistances(self):

        resonances = list(self.resonances)

        resDict = {}
        for resonance in resonances:
            resDict[resonance.serial] = resonance

        ratioHD = self.ratioHDEntry.get() or self.ratioHD

        tmix1 = self.tmix1Entry.get() or 60
        tmix2 = self.tmix2Entry.get() or 120
        tmix3 = self.tmix3Entry.get() or 200

        data = [(tmix1, self.noesyPeakList1), (tmix2, self.noesyPeakList2),
                (tmix3, self.noesyPeakList3)]
        data.sort()

        mixingTimes = [x[0] for x in data]
        peakLists = [x[1] for x in data]

        # get a clean, symmetric and normalised NOE matrix
        noeMatrix = getNoeMatrixFromPeaks(self.noesyPeaks,
                                          resonances,
                                          peakLists,
                                          mixingTimes,
                                          ratioHD=ratioHD,
                                          analysis=self.guiParent)

        # optimiseRelaxation will remove unconstrained resonances
        self.distanceConstraintList, resonances = optimiseRelaxation(
            resonances,
            noeMatrix,
            self.mixTime,
            self.specFreq,
            self.corrTime,
            self.leakRate,
            self.carbonLabel,
            self.nitrogenLabel,
            maxIter=self.maxIter)

        #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 and self.noesyPeakList:
            constraintHead = self.distanceConstraintList.nmrConstraintStore

            if self.adcAtomTypes:
                adcDict = {
                    'HN': ['H'],
                    'HN HA': ['H', 'HA', 'HA1', 'HA2'],
                    'HN HA HB': ['H', 'HA', 'HA1', 'HA2', 'HB', 'HB2', 'HB3']
                }

                allowedAtomTypes = adcDict[self.adcAtomTypes]

                print "Making ADCs"
                self.antiDistConstraintList = makeNoeAdcs(
                    resonances[:],
                    self.noesyPeakList.dataSource,
                    constraintHead,
                    allowedAtomTypes=allowedAtomTypes)
                print "Done ADCs"

            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:
                    item = constraint.findFirstItem()
                    resonances = list(item.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.setOrigData(distance)

        self.update()

    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 getNoesys3d(self):

        peakLists = getThroughSpacePeakLists(self.project)

        names = [
            '<None>',
        ]
        for peakList in peakLists:
            spectrum = peakList.dataSource
            if spectrum.numDim != 3:
                continue

            name = '%s:%s:%s' % (spectrum.experiment.name, spectrum.name,
                                 peakList.serial)
            names.append(name)
            self.peakListDict3d[name] = peakList
            if not self.noesyPeakList:
                self.noesyPeakList = peakList

        return names

    def getNoesys(self):

        peakLists = getThroughSpacePeakLists(self.project)

        names = [
            '<None>',
        ]
        for peakList in peakLists:
            spectrum = peakList.dataSource
            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()

        if name == '<None>':
            self.noesyPeakList = None

        else:
            self.noesyPeakList = self.peakListDict[name]

        self.getPeaks()
        self.getResonances()
        self.update()

    def setNoesy1(self, index, name=None):

        if not name:
            name = self.tmix1Pulldown.getSelected()

        if name != '<None>':
            self.noesyPeakList1 = self.peakListDict[name]
        else:
            self.noesyPeakList1 = None

        self.update()

    def setNoesy2(self, index, name=None):

        if not name:
            name = self.tmix2Pulldown.getSelected()

        if name != '<None>':
            self.noesyPeakList2 = self.peakListDict[name]
        else:
            self.noesyPeakList2 = None

        self.update()

    def setNoesy3(self, index, name=None):

        if not name:
            name = self.tmix3Pulldown.getSelected()

        if name != '<None>':
            self.noesyPeakList3 = self.peakListDict[name]
        else:
            self.noesyPeakList3 = None

        self.update()

    def setNoesy3d(self, index, name=None):

        if not name:
            name = self.noesy3dPulldown.getSelected()

        if name != '<None>':
            self.noesyPeakList3d = self.peakListDict3d[name]
            self.noesyPeaks = self.noesyPeakList3d.sortedPeaks()

        else:
            self.noesyPeakList3d = None
            self.noesyPeaks = []

        self.getResonances()
        self.update()

    def updateMidgeParams(self):

        data = [
            self.specFreq, self.maxIter, self.mixTime, self.corrTime,
            self.leakRate
        ]

        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 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 destroy(self):

        BasePopup.destroy(self)
Beispiel #8
0
class EditSymmetryPopup(BasePopup):
    def __init__(self, parent, project):

        self.parent = parent
        self.project = project
        self.singleMolecule = True
        self.molSystem = None
        self.molecules = []
        self.symmetrySet = None
        self.symmetryOp = None
        self.waiting = False

        BasePopup.__init__(self, parent=parent, title='Symmetry Operations')

    def body(self, guiFrame):

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

        frame = LabelFrame(guiFrame, text='Options')
        frame.grid(row=0, column=0, sticky='ew')
        frame.grid_columnconfigure(5, weight=1)

        label = Label(frame, text='MolSystem:')
        label.grid(row=0, column=0, sticky='w')
        self.molSystemPulldown = PulldownMenu(frame,
                                              callback=self.selectMolSystem)
        self.molSystemPulldown.grid(row=0, column=1, sticky='w')

        self.molLabel = Label(frame, text='Molecule:')
        self.molLabel.grid(row=0, column=2, sticky='w')
        self.moleculePulldown = PulldownMenu(frame,
                                             callback=self.selectMolecule)
        self.moleculePulldown.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='Same Molecule Symmetry:')
        label.grid(row=0, column=4, sticky='w')
        self.molSelect = CheckButton(frame, callback=self.toggleSingleMolecule)
        self.molSelect.grid(row=0, column=5, sticky='w')
        self.molSelect.set(self.singleMolecule)

        frame = LabelFrame(guiFrame, text='Symmetry Operations')
        frame.grid(row=1, column=0, sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        self.symmCodePulldown = PulldownMenu(self,
                                             callback=self.setSymmCode,
                                             do_initial_callback=False)
        self.segLengthEntry = IntEntry(self,
                                       returnCallback=self.setSegLength,
                                       width=6)
        self.setChainMulti = MultiWidget(self,
                                         CheckButton,
                                         callback=self.setChains,
                                         minRows=0,
                                         useImages=False)
        self.setSegmentMulti = MultiWidget(self,
                                           IntEntry,
                                           callback=self.setSegments,
                                           minRows=0,
                                           useImages=False)

        editWidgets = [
            None, self.symmCodePulldown, self.segLengthEntry,
            self.setChainMulti, self.setSegmentMulti
        ]
        editGetCallbacks = [
            None, self.getSymmCode, self.getSegLength, self.getChains,
            self.getSegments
        ]
        editSetCallbacks = [
            None, self.setSymmCode, self.setSegLength, self.setChains,
            self.setSegments
        ]

        headings = [
            '#', 'Symmetry\nType', 'Segment\nLength', 'Chains',
            'Segment\nPositions'
        ]
        self.symmetryMatrix = ScrolledMatrix(frame,
                                             headingList=headings,
                                             callback=self.selectSymmetry,
                                             editWidgets=editWidgets,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks)
        self.symmetryMatrix.grid(row=0, column=0, sticky='nsew')

        texts = ['Add Symmetry Op', 'Remove Symmetrey Op']
        commands = [self.addSymmOp, self.removeSymmOp]
        buttonList = createDismissHelpButtonList(guiFrame,
                                                 texts=texts,
                                                 commands=commands,
                                                 expands=True)
        buttonList.grid(row=2, column=0, sticky='ew')

        self.updateMolSystems()
        self.updateMolecules()
        self.updateSymmetriesAfter()

        self.notify(self.registerNotify)

    def open(self):

        self.updateMolSystems()
        self.updateMolecules()
        self.updateSymmetriesAfter()

        BasePopup.open(self)

    def notify(self, notifyFunc):

        for func in ('__init__', 'delete', 'setSymmetryCode',
                     'setSegmentLength'):
            notifyFunc(self.updateSymmetriesAfter, 'molsim.Symmetry.Symmetry',
                       func)

        for func in ('__init__', 'delete', 'setfirstSeqId'):
            notifyFunc(self.updateSymmetriesAfter, 'molsim.Symmetry.Segment',
                       func)

    def getSymmCode(self, symmetryOp):
        """Get allowed symmetry operators from the model"""

        symmetryOpCodes = symmetryOp.parent.metaclass.container.getElement(
            'SymmetryOpCode').enumeration
        index = 0

        if symmetryOp.symmetryCode in symmetryOpCodes:
            index = symmetryOpCodes.index(symmetryOp.symmetryCode)

        self.symmCodePulldown.setup(symmetryOpCodes, index)

    def getSegLength(self, symmetryOp):

        if symmetryOp and symmetryOp.segmentLength:
            self.segLengthEntry.set(symmetryOp.segmentLength)

    def getChains(self, symmetryOp):

        chains = []
        for chain in self.molSystem.chains:
            if chain.residues:
                if chain.molecule in self.molecules: chains.append(chain.code)
        chains.sort()

        values = []
        for chain in chains:
            if symmetryOp.findFirstSegment(chainCode=chain):
                values.append(True)
            else:
                values.append(False)

        self.setChainMulti.set(values=values, options=chains)

    def getSegments(self, symmetryOp):

        values = []
        names = []

        if symmetryOp:
            for segment in symmetryOp.sortedSegments():
                names.append(segment.chainCode)
                values.append(segment.firstSeqId)

        n = len(values)
        self.setSegmentMulti.maxRows = n
        self.setSegmentMulti.minRows = n
        self.setSegmentMulti.set(values=values, options=names)

    def setSymmCode(self, index, name=None):
        """Set the symmetry code as NCS,C2,C3,C4,C5,C6"""

        if self.symmetryOp:
            symmCode = self.symmCodePulldown.getSelected()
            self.symmetryOp.symmetryCode = symmCode

    def setSegLength(self, event):

        value = self.segLengthEntry.get() or 1
        self.symmetryOp.segmentLength = value

    def setChains(self, obj):

        if self.symmetryOp and obj:
            codes = self.setChainMulti.options
            segment = self.symmetryOp.findFirstSegment()
            values = self.setChainMulti.get()

            if segment: seqId0 = segment.firstSeqId
            else: seqId0 = 1

            for i in range(len(values)):
                segment = self.symmetryOp.findFirstSegment(chainCode=codes[i])

                if segment and not values[i]: segment.delete()
                elif values[i] and not segment:
                    chain = self.molSystem.findFirstChain(code=codes[i])
                    residue = chain.findFirstResidue(seqid=seqId0)

                    if residue: seqId = seqId0
                    else:
                        residue = chain.sortedResidues()[0]
                        seqId = residue.seqId

                    residue2 = chain.findFirstResidue(
                        seqid=seqId + self.symmetryOp.segmentLength)
                    if not residue2:
                        residue2 = chain.sortedResidues()[-1]
                        self.symmetryOp.segmentLength = (residue2.seqId -
                                                         seqId) + 1

                    segment = self.symmetryOp.newSegment(chainCode=codes[i],
                                                         firstSeqId=seqId)

        self.symmetryMatrix.keyPressEscape()

    def setSegments(self, obj):

        if self.symmetryOp and obj:
            segments = self.symmetryOp.sortedSegments()
            values = self.setSegmentMulti.get()

            for i in range(len(values)):
                seqCode = values[i]
                chain = self.molSystem.findFirstChain(
                    code=segments[i].chainCode)
                residue = chain.findFirstResidue(seqCode=seqCode)

                if residue: seqId = residue.seqId
                if segments[i].firstSeqId != seqId:
                    segments[i].delete()
                    segments[i] = self.symmetryOp.newSegment(
                        chainCode=chain.code, firstSeqId=seqId)

        self.symmetryMatrix.keyPressEscape()

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

        self.symmetryOp = obj

    def addSymmOp(self):

        if self.molSystem:
            if not self.symmetrySet:
                self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet(
                )

            if not self.symmetrySet:
                objGen = self.project.newMolSystemSymmetrySet
                self.symmetrySet = objGen(symmetrySetId=1,
                                          molSystem=self.molSystem)

            segLen = len(self.molSystem.findFirstChain().residues)
            symmetry = self.symmetrySet.newSymmetry(segmentLength=segLen)

    def removeSymmOp(self):

        if self.symmetryOp: self.symmetryOp.delete()

    def toggleSingleMolecule(self, boolean):

        self.singleMolecule = not boolean
        self.updateMolSystems()
        self.updateMolecules()

    def setMolecules(self, molecules):

        self.molecules = molecules
        if self.symmetrySet:
            for symmetryOp in self.symmetrySet.symmetries:
                for segment in symmetryOp.segments:
                    chain = self.molSystem.findFirstChain(
                        code=segment.chainCode)
                if chain and (chain.molecule not in molecules):
                    segment.delete()

    def selectMolecule(self, index, name):

        self.setMolecules(self.getMolecules()[index])
        self.updateSymmetries()

    def getMolecules(self):

        counts = {}
        moleculesList = []

        for chain in self.molSystem.chains:
            molecule = chain.molecule
            counts[molecule] = counts.get(molecule, 0) + 1

        molecules = counts.keys()
        if self.singleMolecule:
            for molecule in counts:
                if counts[molecule] > 1: moleculesList.append([
                        molecule,
                ])

        elif molecules:
            molecules = counts.keys()
            n = len(molecules)
            moleculesList.append([
                molecules[0],
            ])

            if n > 1:
                moleculesList.append([
                    molecules[1],
                ])
                moleculesList.append([molecules[0], molecules[1]])

            if n > 2:
                moleculesList.append([
                    molecules[2],
                ])
                moleculesList.append([molecules[1], molecules[2]])
                moleculesList.append(
                    [molecules[0], molecules[1], molecules[2]])

            if n > 3:
                moleculesList.append([
                    molecules[3],
                ])
                moleculesList.append([molecules[0], molecules[3]])
                moleculesList.append([molecules[1], molecules[3]])
                moleculesList.append([molecules[2], molecules[3]])
                moleculesList.append(
                    [molecules[0], molecules[1], molecules[3]])
                moleculesList.append(
                    [molecules[0], molecules[2], molecules[3]])
                moleculesList.append(
                    [molecules[1], molecules[2], molecules[3]])
                moleculesList.append(
                    [molecules[0], molecules[1], molecules[2], molecules[3]])

        return moleculesList

    def updateMolecules(self):

        names = []
        index = -1
        moleculesList = self.getMolecules()
        if moleculesList:
            if self.molecules not in moleculesList:
                self.setMolecules(moleculesList[0])
                self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet(
                )

            index = moleculesList.index(self.molecules)

            names = []
            for molecules in moleculesList:
                names.append(','.join([mol.name for mol in molecules]))

        else:
            self.molecules = []

        self.moleculePulldown.setup(names, index)

    def selectMolSystem(self, index, name):

        self.molSystem = self.getMolSystems()[index]
        self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet()
        self.updateSymmetries()

    def getMolSystems(self):

        molSystems = []
        for molSystem in self.project.sortedMolSystems():
            n = len(molSystem.chains)

            if self.singleMolecule and (n > 1): molSystems.append(molSystem)
            elif n > 0: molSystems.append(molSystem)

        return molSystems

    def updateMolSystems(self):

        names = []
        index = -1
        molSystems = self.getMolSystems()

        if molSystems:
            if self.molSystem not in molSystems: self.molSystem = molSystems[0]

            index = molSystems.index(self.molSystem)
            names = [ms.code for ms in molSystems]
        else:
            self.molSystem = None

        self.molSystemPulldown.setup(names, index)

    def updateSymmetriesAfter(self, obj=None):

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

    def updateSymmetries(self):

        textMatrix = []
        objectList = []
        if self.symmetrySet:
            for symmetryOp in self.symmetrySet.symmetries:
                chains = []
                segments = []
                length = symmetryOp.segmentLength

                for segment in symmetryOp.sortedSegments():
                    code = segment.chainCode
                    chain = self.molSystem.findFirstChain(code=code)

                    if chain:
                        chains.append(code)
                        seqId = segment.firstSeqId
                        residue1 = chain.findFirstResidue(seqId=seqId)
                        residue2 = chain.findFirstResidue(seqId=seqId +
                                                          length - 1)
                        segments.append(
                            '%s:%d-%d' %
                            (code, residue1.seqCode, residue2.seqCode))

                datum = [
                    symmetryOp.serial, symmetryOp.symmetryCode, length,
                    '\n'.join(chains), '\n'.join(segments)
                ]
                objectList.append(symmetryOp)
                textMatrix.append(datum)

        self.symmetryMatrix.update(objectList=objectList,
                                   textMatrix=textMatrix)
        self.waiting = False

    def destroy(self):

        self.notify(self.unregisterNotify)
        BasePopup.destroy(self)
Beispiel #9
0
class EditPeakDrawParamsPopup(BasePopup):
  """
  **Control How Peak Symbols and Annotations Are Drawn**
  
  This popup window controls the display of picked peak positions within
  spectrum windows and also how their annotations are displayed in
  many of the tables throughout the rest of Analysis.

  **Peak Annotations**

  The "Annotation Style" tab, as the name suggests, controls which bits of
  information go to form the assignment annotation that is used to label peaks
  in spectra and when listing their identities in tables. The user can toggle
  various options on or off to dictate what should be included. With no options
  selected at all peaks will show only resonance number information like
  "[123],[45]", irrespective of any atomic assignments. Switching the atom
  assignments on will substitute the atom and residue name for  the resonance
  names. The spin system toggle is used to control the display of spin system
  numbers like the curly bracketed numbers of "{89}[123],[45]" or a residue name
  if the spin system is assigned, although the atom assignment option will also
  give any residue name. The chain and molecular system toggles are used when
  there are several sequences in the assignment that need to be distinguished, so
  that you can identify "A25LsyH,N" separately to "B25LysH,N" or even
  "MS2:A25LysH,N". The details toggle allows the user to contribute to peak
  annotations; such details are set in the relevant column of the peak tables
  (e.g. `Selected Peaks`_)or the "Peak::Set details" option of the right-click
  window menu. The last "Minimal Annotations" option is special because it gives
  a quick replacement for spectrum annotations that overrides all other settings,
  for example "25LysH,N" becomes "25K", which is useful to reduce clutter when
  printing out an HSQC.

  It should be noted that, with the exception of the "Minimal Annotations"
  option, any changes to the annotation options for existing peak assignments
  will not be visible until [Update Full Annotations] is pressed, which can take
  a while to update if the number of peaks in the project is large. Any new
  assignments will observe the current settings.

  **Draw Size**
  
  The second tab controls how the peak cross symbols, which indicate the pick
  position, are drawn in the spectrum display. Here, the user has four choices:
  the default is to use a fixed number of screen pixels, so that all symbols are
  the same size, irrespective of zoom level; uniform size in ppm (with the 
  appropriate values for each isotope set in the lower table that appears)
  allows the peak symbol maintain a constant size relative to the contours, and
  thus differ in on-screen size according to the contour zoom level; and two
  choices for a "scaled" size where the peak symbol is larger or smaller
  depending on the intensity of the peak, either relative to its peak list or an
  absolute globally applied value.

  **Figure of Merit**

  The last "Merit Symbols" tab allows the user to add textual markers to a peak
  depending on the figure-of-merit value, which is an indication of reliability
  (although the precise context is at the discretion of the user). The merit
  value for a peak is set via the peak tables or the "Peak::Set merit" option of
  the right-click window menu. Aside from display purposes the merit value is
  used at a few points throughout Analysis to optionally exclude peaks. Typically
  a peak with a merit value of 0.0 may be ignored during certain analyses, e.g.
  for making NOE derived distance restraints.

  **Caveats & Tips**

  When assigning peaks via the `Assignment Panel`_ the resonance annotation will
  always display spin system information, given that this grouping is critical
  to assignment, but the chain and atom assignment will reflect the peak
  display, and thus these details may be missing if unset in this Draw
  Parameters popup.


  .. _`Assignment Panel`: EditAssignmentPopup.html
  .. _`Selected Peaks`: SelectedPeaksPopup.html
  """
  def __init__(self, parent, *args, **kw):
 
    BasePopup.__init__(self, parent=parent, title='Peak : Draw Parameters', **kw)

  def body(self, guiParent):
 
    self.geometry('380x250')

    analysisProject = self.analysisProject

    self.smallFont    = '-schumacher-clean-medium-r-normal--14-140-75-75-c-70-iso646.1991-irv'
    guiParent.grid_columnconfigure(0, weight=1)
    guiParent.grid_rowconfigure(0, weight=1)
    
    row = 0
    
    tipTexts = ['Options specifying how peak annotations are drawn in spectrum windows and in tables etc.',
                'Options to specify how large the peak crosses/symbols are drawn in spectrum windows',
                'Enables the user to specify special symbols to annotate peaks according to quality']
    options=['Annotation Style','Draw Size','Merit Symbols']
    tabbedFrame = TabbedFrame(guiParent, options=options,
                              grid=(row,0), tipTexts=tipTexts)
    
    frame1, frame2, frame3 = tabbedFrame.frames
    frame1.expandGrid(7,1)
    frame2.expandGrid(2,0)
    frame3.expandGrid(3,1)
    
    self.drawFrame = frame2
    
 
    # Annotations

    tipText = 'Whether to show unassigned spin system numbers like "{123}" in peak annotations; does not affect the display of full residue assignments'
    self.spinSystAnnoSelect = CheckButton(frame1, callback=self.setSpinSystAnno, grid=(0,0),
                                          selected=analysisProject.doSpinSystemAnnotations,
                                          tipText=tipText)
    spinSystAnnoLabel = Label(frame1, text='Spin System Info', grid=(0,1))

    tipText = 'Whether to show assigned atom names in peak annotations rather than resonance numbers, e.g. "21LeuH,N" or "21Leu[55],[56]"'
    self.resonanceAnnoSelect = CheckButton(frame1, callback=self.setResonanceAnno, grid=(1,0),
                                           selected=analysisProject.doAssignmentAnnotations,
                                           tipText=tipText)
    resonanceAnnoLabel = Label(frame1, text='Atom Assignment', grid=(1,1))

    tipText = 'Whether to show the molecular chain code letter in peak annotations, e.g. "21LeuH,N" or "A21LeuH,N"'
    self.chainAnnoSelect = CheckButton(frame1, callback=self.setChainAnno, grid=(2,0),
                                       selected=analysisProject.doChainAnnotations,
                                       tipText=tipText)
    chainAnnoLabel = Label(frame1, text='Chain Assignment', grid=(2,1))

    tipText = 'Whether to show the molecular system code name in peak annotations, e.g. "MS1:21LeuH,N" or "21LeuH,N"'
    self.molSysAnnoSelect = CheckButton(frame1, callback=self.setMolSysAnno, grid=(3,0),
                                       selected=analysisProject.doMolSysAnnotations,
                                       tipText=tipText)
    molSysAnnoLabel = Label(frame1, text='Molecular System', grid=(3,1))

    tipText = 'Whether to show a symbol indicating the quality of a peak; these symbols must be set in the "Merit Symbols" tab'
    self.meritAnnoSelect = CheckButton(frame1, callback=self.setMeritAnno, grid=(4,0),
                                       selected=analysisProject.doMeritAnnotations,
                                       tipText=tipText)
    meritAnnoLabel = Label(frame1, text='Merit Symbol', grid=(4,1))

    tipText = 'Whether to show the details text for a peak in spectrum windows (set in the peak tables)'
    self.detailAnnoSelect = CheckButton(frame1, callback=self.setDetailAnno, grid=(5,0),
                                        selected=analysisProject.doDetailAnnotations,
                                        tipText=tipText)
    detailAnnoLabel = Label(frame1, text='Details', grid=(5,1))

    tipText = 'Whether to ignore above settings, and use a short peak annotation using only residue numbers and one-letter codes, e.g. "21L"'
    self.simpleAnnoSelect = CheckButton(frame1, callback=self.setSimpleAnnotations,
                                        grid=(6,0), tipText=tipText,
                                        selected=analysisProject.doMinimalAnnotations)
    simpleAnnoLabel = Label(frame1, text='Minimal Annotations (overriding option)', grid=(6,1))

    tipText = 'Manually cause an update of all peak annotations; may take some time but recommended to see the immediate effect of changes'
    self.updateFullAnnoButton = Button(frame1, text='Update Full Annotations',
                                       command=self.updateAnnotations, grid=(7,0),
                                       gridSpan=(1,2), sticky='nsew', tipText=tipText)

    # Size
    
    tipText = 'The width of the displayed peak cross/symbol in screen pixels; the number of pixels from the centre point'
    self.pixel_entry = LabeledEntry(frame2, label='Number of pixels',
                                    entry=analysisProject.peakPixelSize,
                                    returnCallback=self.updatePixelSize,
                                    entry_width=8, tipText=tipText)

    tipText = 'Specifies which peak height corresponds to the specific per-isotope ppm size; actual peak symbol sizes are scaled, according to relative height (and volume)'
    self.intensity_entry = LabeledEntry(frame2, label='Height scale',
                                        entry=analysisProject.peakIntensityScale,
                                        returnCallback=self.updateIntensityScale,
                                        entry_width=8, tipText=tipText)
                                        
    tipText = 'Specifies which peak volume corresponds to the specific per-isotope ppm size; actual peak symbol sizes are scaled, according to relative volume (and height)'
    self.volume_entry = LabeledEntry(frame2, label='Volume scale',
                                     entry=analysisProject.peakVolumeScale,
                                     returnCallback=self.updateVolumeScale,
                                     entry_width=8, tipText=tipText)

    tipTexts = ['The kind of nuclear isotope, as found on the axis if a spectrum window',
                'The ppm width of the peak cross/symbol along the specific kind of isotope axis']
    headings = ['Isotope', 'Peak Size (ppm)']
    self.peakSizeEntry = FloatEntry(self, returnCallback=self.setPeakSize, width=10)
    editWidgets = [None, self.peakSizeEntry]
    editGetCallbacks = [None, self.getPeakSize]
    editSetCallbacks = [None, self.setPeakSize]
    self.peak_size_table = ScrolledMatrix(frame2, headingList=headings,
                                          initialRows=5, editWidgets=editWidgets,
                                          editGetCallbacks=editGetCallbacks,
                                          editSetCallbacks=editSetCallbacks,
                                          tipTexts=tipTexts)

    self.selected_method = None
    self.method_widgets = {}
    self.method_widgets[peak_draw_methods[0]] = [self.pixel_entry]
    self.method_widgets[peak_draw_methods[1]] = [self.peak_size_table]
    self.method_widgets[peak_draw_methods[2]] = [self.intensity_entry, self.volume_entry, self.peak_size_table]
    self.method_widgets[peak_draw_methods[3]] = [self.peak_size_table]
    self.method_widgets[peak_draw_methods[4]] = []
    self.method_widgets[peak_draw_methods[5]] = []

    selected_index = peak_draw_methods.index(analysisProject.peakDrawMethod)
    tipText = 'Selects which mode to use for determining peak cross/symbol sizes; a fixed pixel/ppm value or scaled by intensity for all peaks or just one peak list'
    self.method_menu = PulldownList(frame2, texts=peak_draw_methods, gridSpan=(1,2), 
                                    grid=(0,0), tipText=tipText,
                                    callback=self.setMethod, index=selected_index)
    
    # Merit symbol
    
    label = Label(frame3, text='Good merit (>0.66)', grid=(0,0))
    tipText = 'Although typically blank, sets a symbol to display for good quality peaks (merit value > 0.66), if the relevant option is selected in the "Annotation Style" tab'
    self.meritGoodEntry = Entry(frame3, text=analysisProject.meritAnnotationGood,
                                width=8, grid=(0,1), sticky='ew', tipText=tipText,
                                returnCallback=self.setMeritAnnotation)

    label = Label(frame3, text='Medium merit', grid=(1,0))
    tipText = 'Sets a symbol to display for mediocre quality peaks (merit value between 0.34 & 0.66), if the relevant option is selected in the "Annotation Style" tab'
    self.meritUglyEntry = Entry(frame3, text=analysisProject.meritAnnotationMediocre,
                                width=8, grid=(1,1), sticky='ew', tipText=tipText,
                                returnCallback=self.setMeritAnnotation)

    label = Label(frame3, text='Poor merit (<0.34)', grid=(2,0))
    tipText = 'Sets a symbol to display for poor quality peaks (merit value < 0.34), if the relevant option is selected in the "Annotation Style" tab'
    self.meritBadEntry  = Entry(frame3, text=analysisProject.meritAnnotationBad,
                                width=8, grid=(2,1), sticky='ew', tipText=tipText,
                                returnCallback=self.setMeritAnnotation)

    tipText = 'Commit the changes to the merit symbols; this will not automatically update the display - see the "Annotation Style" tab'
    setButton = Button(frame3, text='Set symbols', command=self.setMeritAnnotation,
                       grid=(3,0), gridSpan=(1,2), tipText=tipText, sticky='nsew')

    buttons = UtilityButtonList(tabbedFrame.sideFrame, grid=(0,0), 
                                helpUrl=self.help_url, sticky='e')

    self.updatePeakSizeTable()
    self.updateMethod()

    for func in ('__init__', 'delete', ''):                                           
      self.registerNotify(self.updatePeakSizeTable, 'ccpnmr.Analysis.AxisType', func)

    self.registerNotify(self.changedDoSpinSystemAnnotations, 'ccpnmr.Analysis.AnalysisProject', 'setDoSpinSystemAnnotations')
    self.registerNotify(self.changedDoAssignmentAnnotations, 'ccpnmr.Analysis.AnalysisProject', 'setDoAssignmentAnnotations')
    self.registerNotify(self.changedDoChainAnnotations, 'ccpnmr.Analysis.AnalysisProject', 'setDoChainAnnotations')
    self.registerNotify(self.changedPeakDrawMethod, 'ccpnmr.Analysis.AnalysisProject', 'setPeakDrawMethod')
    self.registerNotify(self.changedPeakPixelSize, 'ccpnmr.Analysis.AnalysisProject', 'setPeakPixelSize')

  def open(self):
  
    self.updatePeakSizeTable()
    self.updateMethod()
    BasePopup.open(self)
    

  def close(self):
  
    self.setMeritAnnotation()
    BasePopup.close(self)

  def destroy(self):
 
    for func in ('__init__', 'delete', ''):                                           
      self.unregisterNotify(self.updatePeakSizeTable, 'ccpnmr.Analysis.AxisType', func)

    self.unregisterNotify(self.changedDoSpinSystemAnnotations, 'ccpnmr.Analysis.AnalysisProject', 'setDoSpinSystemAnnotations')
    self.unregisterNotify(self.changedDoAssignmentAnnotations, 'ccpnmr.Analysis.AnalysisProject', 'setDoAssignmentAnnotations')
    self.unregisterNotify(self.changedDoChainAnnotations, 'ccpnmr.Analysis.AnalysisProject', 'setDoChainAnnotations')
    self.unregisterNotify(self.changedPeakDrawMethod, 'ccpnmr.Analysis.AnalysisProject', 'setPeakDrawMethod')
    self.unregisterNotify(self.changedPeakPixelSize, 'ccpnmr.Analysis.AnalysisProject', 'setPeakPixelSize')

    BasePopup.destroy(self)

  def setMeritAnnotation(self, *opt):
    
    analysisProject = self.analysisProject
    analysisProject.meritAnnotationGood     = self.meritGoodEntry.get() or None
    analysisProject.meritAnnotationMediocre = self.meritUglyEntry.get() or None
    analysisProject.meritAnnotationBad      = self.meritBadEntry.get() or None
   
  def updateAnnotations(self):
  
    self.setMeritAnnotation()
    refreshPeakAnnotations(self.project)
  
  def setSimpleAnnotations(self, trueOrFalse):
  
    self.analysisProject.doMinimalAnnotations = trueOrFalse

  def setSpinSystAnno(self, trueOrFalse):
  
    self.analysisProject.doSpinSystemAnnotations = trueOrFalse

  def setResonanceAnno(self, trueOrFalse):
  
    self.analysisProject.doAssignmentAnnotations = trueOrFalse
    
  def setMolSysAnno(self, trueOrFalse):
  
    self.analysisProject.doMolSysAnnotations = trueOrFalse
    
  def setChainAnno(self, trueOrFalse):
  
    self.analysisProject.doChainAnnotations = trueOrFalse
    
  def setMeritAnno(self, trueOrFalse):

    self.analysisProject.doMeritAnnotations = trueOrFalse

  def setDetailAnno(self, trueOrFalse):   

    self.analysisProject.doDetailAnnotations = trueOrFalse
    
  def changedDoSpinSystemAnnotations(self, analysisProject):

    self.spinSystAnnoSelect.set(analysisProject.doSpinSystemAnnotations)

  def changedDoAssignmentAnnotations(self, analysisProject):

    self.resonanceAnnoSelect.set(analysisProject.doAssignmentAnnotations)

  def changedDoChainAnnotations(self, analysisProject):

    self.chainAnnoSelect.set(analysisProject.doChainAnnotations)

  def changedPeakDrawMethod(self, analysisProject):
 
    self.updateMethod()

  def changedPeakPixelSize(self, analysisProject):
 
    self.pixel_entry.setEntry(analysisProject.peakPixelSize)

  def setMethod(self, text):
  
    self.analysisProject.peakDrawMethod = text

  def updateMethod(self):

    selected = self.analysisProject.peakDrawMethod
    if selected == self.selected_method:
      return

    self.unsetMethod()

    widgets = self.method_widgets[selected]

    row = 1
    for widget in widgets:
      if isinstance(widget, ScrolledMatrix):
        widget.grid(row=row, column=0, sticky='nsew')
        self.drawFrame.grid_rowconfigure(row, weight=1)
      else:
        widget.grid(row=row, column=0, sticky='new')
        self.drawFrame.grid_rowconfigure(row, weight=0)
  
      row += 1

    self.selected_method = selected

  def unsetMethod(self):

    selected = self.selected_method
    if selected is None:
      return

    widgets = self.method_widgets[selected]

    for widget in widgets:
      widget.grid_forget()

    self.selected_method = None

  def updatePeakSizeTable(self, *extra):
 
    axisTypes = self.parent.getAxisTypes()
 
    textMatrix = []
    n = 0
    for axisType in axisTypes:
      if (len(axisType.isotopeCodes) == 1):
        n = n + 1
        text = []
        text.append(', '.join(axisType.isotopeCodes))
        text.append(axisType.peakSize)
        textMatrix.append(text)
 
    self.peak_size_table.update(objectList=axisTypes, textMatrix=textMatrix)

  def getPeakSize(self, axisType):
 
    self.peakSizeEntry.set(axisType.peakSize)
 
  def setPeakSize(self, *extra):
 
    axisType = self.getAxisType()
    try:
      axisType.peakSize = self.peakSizeEntry.get()
    except Implementation.ApiError, e:
      showError('Setting peak size', e.error_msg, parent=self)