Пример #1
0
class PopupTemplate(BasePopup):

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

    self.project = project
    self.parent  = parent
    self.objects = self.getObjects()
    self.object  = None
    
    BasePopup.__init__(self, parent=parent, title='Popup Template', **kw)
                       
    self.updateObjects()

  def body(self, mainFrame):

    mainFrame.grid_columnconfigure(1, weight=1, minsize=100)
    mainFrame.config(borderwidth=5, relief='solid')

    row = 0
    label = Label(mainFrame, text="Frame (with sub-widgets):")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    frame = Frame(mainFrame, relief='raised', border=2, background='#8080D0')
    # Frame expands East-West
    frame.grid(row=row, column=1, sticky=Tkinter.EW)
    # Last column expands => Widgets pusted to the West
    frame.grid_columnconfigure(3, weight=1)
    
    # Label is within the sub frame
    label = Label(frame, text='label ')
    label.grid(row=0, column=0, sticky=Tkinter.W)
    
    entry = Entry(frame, text='Entry', returnCallback=self.showWarning)
    entry.grid(row=0, column=1, sticky=Tkinter.W)
    
    self.check = CheckButton(frame, text='Checkbutton', selected=True, callback=self.updateObjects)
    self.check.grid(row=0, column=2, sticky=Tkinter.W)
    
    # stick a button to the East wall
    button = Button(frame, text='Button', command=self.pressButton)
    button.grid(row=0, column=3, sticky=Tkinter.E)
  
    row += 1
    label = Label(mainFrame, text="Text:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.textWindow = Text(mainFrame, text='Initial Text\n', width=60, height=5)
    self.textWindow.grid(row=row, column=1, sticky=Tkinter.NSEW)
    
    row += 1
    label = Label(mainFrame, text="CheckButtons:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    entries = ['Alpha','Beta','Gamma','Delta']
    selected = entries[2:]
    self.checkButtons = CheckButtons(mainFrame, entries, selected=selected,select_callback=self.changedCheckButtons)
    self.checkButtons.grid(row=row, column=1, sticky=Tkinter.W)
  
    row += 1
    label = Label(mainFrame, text="PartitionedSelector:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    labels   = ['Bool','Int','Float','String']
    objects  = [type(0),type(1),type(1.0),type('a')]
    selected = [type('a')]
    self.partitionedSelector= PartitionedSelector(mainFrame, labels=labels,
                                                  objects=objects,
                                                  colors = ['red','yellow','green','#000080'],
                                                  callback=self.toggleSelector,selected=selected)
    self.partitionedSelector.grid(row=row, column=1, sticky=Tkinter.EW)

    row += 1
    label = Label(mainFrame, text="PulldownMenu")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    entries = ['Frodo','Pipin','Merry','Sam','Bill','Gandalf','Strider','Gimli','Legolas']
    self.pulldownMenu = PulldownMenu(mainFrame, callback=self.selectPulldown,
                                     entries=entries, selected_index=2,
                                     do_initial_callback=False)
    self.pulldownMenu.grid(row=row, column=1, sticky=Tkinter.W)

    row += 1
    label = Label(mainFrame, text="RadioButtons in a\nScrolledFrame.frame:")
    label.grid(row=row, column=0, sticky=Tkinter.EW)
    
    frame = ScrolledFrame(mainFrame, yscroll = False, doExtraConfig = True, width=100)
    frame.grid(row=row, column=1, sticky=Tkinter.EW)
    frame.grid_columnconfigure(0, weight=1)

    self.radioButtons = RadioButtons(frame.frame, entries=entries,
                                     select_callback=self.checkRadioButtons,
                                     selected_index=1, relief='groove')
    self.radioButtons.grid(row=0, column=0, sticky=Tkinter.W)
    
    row += 1
    label = Label(mainFrame, text="LabelFrame with\nToggleLabels inside:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    labelFrame = LabelFrame(mainFrame, text='Frame Title')
    labelFrame.grid(row=row, column=1, sticky=Tkinter.NSEW)
    labelFrame.grid_rowconfigure(0, weight=1)
    labelFrame.grid_columnconfigure(3, weight=1)
    
        
    self.toggleLabel1 = ToggleLabel(labelFrame, text='ScrolledMatrix', callback=self.toggleFrame1)
    self.toggleLabel1.grid(row=0, column=0, sticky=Tkinter.W)
    self.toggleLabel1.arrowOn()

    self.toggleLabel2 = ToggleLabel(labelFrame, text='ScrolledGraph', callback=self.toggleFrame2)
    self.toggleLabel2.grid(row=0, column=1, sticky=Tkinter.W)

    self.toggleLabel3 = ToggleLabel(labelFrame, text='ScrolledCanvas', callback=self.toggleFrame3)
    self.toggleLabel3.grid(row=0, column=2, sticky=Tkinter.W)
    
    row += 1
    mainFrame.grid_rowconfigure(row, weight=1)

    label = Label(mainFrame, text="changing/shrinking frames:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    self.toggleRow = row
    self.toggleFrame = Frame(mainFrame)
    self.toggleFrame.grid(row=row, column=1, sticky=Tkinter.NSEW)
    self.toggleFrame.grid_rowconfigure(0, weight=1)
    self.toggleFrame.grid_columnconfigure(0, weight=1)
    
    # option 1
    
    self.intEntry = IntEntry(self, returnCallback = self.setNumber, width=8)
    
    self.multiWidget = MultiWidget(self, Entry, options=None, 
                                  values=None, callback=self.setKeywords,
                                  minRows=3, maxRows=5)

    editWidgets      = [None, None, self.intEntry,  self.multiWidget]
    editGetCallbacks = [None, None, self.getNumber, self.getKeywords]
    editSetCallbacks = [None, None, self.setNumber, self.setKeywords]
    
    headingList = ['Name','Color','Number','Keywords']
    self.scrolledMatrix = ScrolledMatrix(self.toggleFrame, headingList=headingList,
                                         editSetCallbacks=editSetCallbacks,
                                         editGetCallbacks=editGetCallbacks,
                                         editWidgets=editWidgets,
                                         callback=self.selectObject,
                                         multiSelect=False) 
                                         
    self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW)

    # option 2
    self.scrolledGraph = ScrolledGraph(self.toggleFrame, width=400,
                                       height=300, symbolSize=5,
                                       symbols=['square','circle'],
                                       dataColors=['#000080','#800000'],
                                       lineWidths=[0,1] )

    self.scrolledGraph.setZoom(1.3)

    dataSet1 = [[0,0],[1,1],[2,4],[3,9],[4,16],[5,25]]
    dataSet2 = [[0,0],[1,3],[2,6],[3,9],[4,12],[5,15]]
    self.scrolledGraph.update(dataSets=[dataSet1,dataSet2],
                              xLabel = 'X axis label',
                              yLabel = 'Y axis label',
                              title  = 'Main Title')
    self.scrolledGraph.draw()

    # option 3
    self.scrolledCanvas = ScrolledCanvas(self.toggleFrame,relief = 'groove', borderwidth = 2, resizeCallback=None)
    canvas = self.scrolledCanvas.canvas
    font   = 'Helvetica 10'
    box    = canvas.create_rectangle(10,10,150,200, outline='grey', fill='grey90')
    line   = canvas.create_line(0,0,200,200,fill='#800000', width=2)
    text   = canvas.create_text(120,50, text='Text', font=font, fill='black')
    circle = canvas.create_oval(30,30,50,50,outline='#008000',fill='#404040',width=3)
     
    row += 1
    label = Label(mainFrame, text="FloatEntry:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.floatEntry = FloatEntry(mainFrame, text=3.14159265, returnCallback=self.floatEntryReturn)
    self.floatEntry.grid(row=row, column=1, sticky=Tkinter.W)
    
     
    row += 1
    label = Label(mainFrame, text="Scale:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.scale = Scale(mainFrame, from_=10, to=90, value=50, orient=Tkinter.HORIZONTAL)
    self.scale.grid(row=row, column=1, sticky=Tkinter.W)

    row += 1
    label = Label(mainFrame, text="Value Ramp:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.valueRamp = ValueRamp(mainFrame, self.valueRampCallback, speed = 1.5, delay = 50)
    self.valueRamp.grid(row=row, column=1, sticky=Tkinter.W)
  

    row += 1
    label = Label(mainFrame, text="ButtonList:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    texts    = ['Select File','Close','Quit']
    commands = [self.selectFile, self.close, self.quit]
    bottomButtons = ButtonList(mainFrame, texts=texts, commands=commands, expands=True) 
    bottomButtons.grid(row=row, column=1, sticky=Tkinter.EW)
  
    self.protocol('WM_DELETE_WINDOW', self.quit)

  def floatEntryReturn(self, event):
  
    value = self.floatEntry.get()
    self.textWindow.setText('%s\n' % value)

  def selectObject(self, object, row, col):
  
    self.object = object

  def getKeywords(self, object):
  
    if object :
      values = object.keywords
      self.multiWidget.set(values)
  
  def setKeywords(self, event):
  
    values = self.multiWidget.get()
    self.object.keywords = values
    self.updateObjects()

  def getNumber(self, object):

    if object :
      self.intEntry.set(object.quantity)

  def setNumber(self, event):

    value = self.intEntry.get()
    self.object.quantity = value
    self.updateObjects()

  def toggleFrame1(self, isHidden):
 
    if isHidden:
      self.scrolledMatrix.grid_forget()
      self.toggleFrame.grid_forget()
    else:
      self.scrolledGraph.grid_forget()
      self.scrolledCanvas.grid_forget()
      self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW)
      self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW)
      self.toggleLabel2.arrowOff()
      self.toggleLabel3.arrowOff()


  def toggleFrame2(self, isHidden):
 
    if isHidden:
      self.scrolledGraph.grid_forget()
      self.toggleFrame.grid_forget()
    else:
      self.scrolledMatrix.grid_forget()
      self.scrolledCanvas.grid_forget()
      self.scrolledGraph.grid(row=0, column=0, sticky=Tkinter.NSEW)
      self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW)
      self.toggleLabel1.arrowOff()
      self.toggleLabel3.arrowOff()

  def toggleFrame3(self, isHidden):
 
    if isHidden:
      self.scrolledCanvas.grid_forget()
      self.toggleFrame.grid_forget()
    else:
      self.scrolledMatrix.grid_forget()
      self.scrolledGraph.grid_forget()
      self.scrolledCanvas.grid(row=0, column=0, sticky=Tkinter.NSEW)
      self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW)
      self.toggleLabel1.arrowOff()
      self.toggleLabel2.arrowOff()

 
  def valueRampCallback(self, value):
  
    self.textWindow.setText('%s\n' % value)

  def checkRadioButtons(self, value):
  
    self.textWindow.setText('%s\n' % value)

  def selectPulldown(self, index, name):
  
    self.textWindow.setText('%d, %s\n' % (index, name))

  def toggleSelector(self, value):
  
    self.textWindow.setText('%s\n' % value)

  def changedCheckButtons(self, values):
  
    self.textWindow.setText(','.join(values) + '\n')

  def getObjects(self):
  
    objects = []
    
    objects.append( Fruit('Lemon',   '#FFFF00',1,keywords=['Bitter','Tangy'] ) )
    objects.append( Fruit('Orange',  '#FF8000',4 ) )
    objects.append( Fruit('Banana',  '#FFF000',5 ) )
    objects.append( Fruit('Pinapple','#FFD000',9 ) )
    objects.append( Fruit('Kiwi',    '#008000',12) )
    objects.append( Fruit('Lime',    '#00FF00',2 ) )
    objects.append( Fruit('Apple',   '#800000',5,keywords=['Crunchy'] ) )
    objects.append( Fruit('Pear',    '#408000',6 ) )
    objects.append( Fruit('Peach',   '#FFE0C0',2,keywords=['Sweet','Furry'] ) )
    objects.append( Fruit('Plumb',   '#800080',7 ) )
    
    return objects

  def updateObjects(self, event=None):

    textMatrix = []
    objectList = []
    colorMatrix = []
    
    for object in self.objects:
      datum = []
      datum.append( object.name )
      datum.append( None )
      datum.append( object.quantity )
      datum.append( ','.join(object.keywords) )
    
      colors = [None, object.color, None, None]
    
      textMatrix.append(datum)
      objectList.append(object)
      colorMatrix.append(colors)

    if self.check.get():
      self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList)
    else:
      self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList, colorMatrix=colorMatrix)

  def selectFile(self):

    fileSelectPopup = FileSelectPopup(self, title = 'Choose file', dismiss_text = 'Cancel',
                                      selected_file_must_exist = True)

    fileName = fileSelectPopup.getFile()

    self.textWindow.setText('File Selected: %s\n' % fileName)

  def showWarning(self, eventObject):
  
    self.textWindow.setText('Text Entry Return Pressed\n')
    showWarning('Warning Title','Warning Message')
    return

  def pressButton(self):
  
    self.textWindow.setText('Button Pressed\n')
    if showYesNo('Title','Prompt: Clear text window?'):
       self.textWindow.clear()
       
    return

  def quit(self):
  
    BasePopup.destroy(self)  
Пример #2
0
class ConfirmSeqSpinSystemsPopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.guiParent = parent
        self.spinSystems = []
        self.spectrum = None
        self.spectra = []
        self.waiting = 0
        self.shiftList = None
        self.spinSystem = None
        self.link = '-1'

        BasePopup.__init__(self,
                           parent=parent,
                           title="Confirm Sequential Spin System",
                           **kw)

    def body(self, guiFrame):

        guiFrame.grid_columnconfigure(0, weight=1)

        row = 0

        frame = Frame(guiFrame)
        frame.grid(row=row, column=0, sticky='nsew')
        frame.grid_columnconfigure(3, weight=1)

        label = Label(frame, text='Shift List:')
        label.grid(row=0, column=0, sticky='w')

        self.shiftListPulldown = PulldownMenu(frame,
                                              callback=self.setShiftList)
        self.shiftListPulldown.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='Sequential Link Type:')
        label.grid(row=0, column=2, sticky='w')

        entries = ['-1', '-1,+1', '+1']
        self.linkPulldown = PulldownMenu(frame,
                                         callback=self.setLink,
                                         entries=entries,
                                         do_initial_callback=False,
                                         selected_index=entries.index(
                                             self.link))
        self.linkPulldown.grid(row=0, column=3, sticky='w')

        row += 1
        frame = LabelFrame(guiFrame, text='Link Atoms:')
        frame.grid(row=row, column=0, sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        labels = ['C', 'CA', 'CB', 'CG', 'CD', 'H', 'HA', 'HB', 'HG', 'HD']
        selected = ['CA', 'CB']
        self.atomSelector = PartitionedSelector(frame,
                                                objects=labels,
                                                labels=labels,
                                                selected=selected,
                                                toggledBg='#808080',
                                                callback=self.changeAtoms,
                                                maxRowObjects=10)
        self.atomSelector.grid(row=0, column=0, sticky='ew')

        row += 1
        guiFrame.grid_rowconfigure(row, weight=1)

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

        headingList = [
            '#', 'Predicted\nResidue', 'Prob.', 'Links', 'CA', 'CA -1', 'CB',
            'CB -1'
        ]
        self.spinSystemMatrix = ScrolledMatrix(frame,
                                               headingList=headingList,
                                               callback=self.selectSpinSystem,
                                               multiSelect=1)
        self.spinSystemMatrix.grid(row=0, column=0, sticky='nsew')

        row += 1
        texts = ['Link Selected', 'Link All', 'Commit Assignment']
        commands = [
            self.linkSelectedSpinSystems, self.linkAllSpinSystems,
            self.commitAssignments
        ]
        buttonList = UtilityButtonList(guiFrame,
                                       texts=texts,
                                       commands=commands,
                                       helpUrl=self.help_url)
        buttonList.grid(row=row, column=0, sticky='ew')

        self.buttons = buttonList.buttons

        for func in ('__init__', 'delete'):
            for clazz in ('ccp.nmr.Nmr.ShiftList', ):
                self.registerNotify(self.updateShiftLists, clazz, func)

        for func in ('__init__', 'delete', 'setNmrChains', 'setResidue',
                     'setResonances', 'addResonance', 'removeResonance'):
            self.registerNotify(self.updateSpinSystemsAfter,
                                'ccp.nmr.Nmr.ResonanceGroup', func)

        self.updateShiftLists()

    def setLink(self, index, name):

        self.link = name
        self.updateSpinSystemsAfter()

    def updateButtons(self):

        if len(self.spinSystemMatrix.currentObjects) > 1:
            self.buttons[0].enable()
        else:
            self.buttons[0].disable()

        if self.spinSystemMatrix.objectList:
            self.buttons[1].enable()
        else:
            self.buttons[1].disable()

        if self.spinSystem:
            self.buttons[2].enable()
        else:
            self.buttons[2].disable()

    def changeAtoms(self, *opt):

        self.updateSpinSystemsAfter()

    def getShiftListNames(self, shiftLists):

        shiftListNames = []
        for shiftList in shiftLists:
            if not hasattr(shiftList, 'name'):
                shiftList.name = "ShiftList " + str(shiftList.serial)
            elif not shiftList.name:
                shiftList.name = "ShiftList " + str(shiftList.serial)
            shiftListNames.append(shiftList.name)

        return shiftListNames

    def updateShiftLists(self, *opt):

        shiftLists = list(
            self.nmrProject.findAllMeasurementLists(className='ShiftList'))
        shiftListNames = self.getShiftListNames(shiftLists)
        shiftList = None
        index = -1

        if shiftListNames:

            if self.shiftList in shiftLists:
                shiftList = self.shiftList
            else:
                shiftList = shiftLists[0]

            index = shiftLists.index(shiftList)

        self.shiftList = shiftList
        self.shiftListPulldown.setup(shiftListNames, index)

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

        shiftLists = list(
            self.nmrProject.findAllMeasurementLists(className='ShiftList'))
        if shiftLists:
            self.shiftList = shiftLists[index]
        else:
            self.shiftList = None

        self.updateSpinSystemsAfter()

    def linkSelectedSpinSystems(self):

        spinSystems = self.spinSystemMatrix.currentObjects
        self.linkSpinSystems(spinSystems)

    def linkAllSpinSystems(self):

        spinSystems = self.spinSystemMatrix.objectList
        self.linkSpinSystems(spinSystems)

    def linkSpinSystems(self, spinSystems):

        data = []

        for spinSystem in spinSystems:
            residue, p = self.getProbableResidue(spinSystem)
            key = '%s%s%4.4d' % (residue.chain.molSystem.code,
                                 residue.chain.code, residue.seqCode)
            data.append([key, residue.seqCode, residue, spinSystem])

        data.sort()
        seqCodes = [x[1] for x in data]
        residues = [x[2] for x in data]
        spinSystems = [x[3] for x in data]

        N = len(data)
        for i in range(N):

            if i > 0:
                delta = seqCodes[i] - seqCodes[i - 1]
                if delta == 1 and (residues[i].chain is residues[i - 1].chain):
                    ss = findConnectedSpinSystem(spinSystems[i], delta=-1)
                    if ss:
                        mergeSpinSystems(
                            ss,
                            spinSystems[i -
                                        1])  # copy resonances across & delete

                    makeSeqSpinSystemLink(spinSystems[i - 1],
                                          spinSystems[i],
                                          delta=1)

            if i < N - 1:
                delta = seqCodes[i + 1] - seqCodes[i]
                if delta == 1 and (residues[i].chain is residues[i + 1].chain):
                    ss = findConnectedSpinSystem(spinSystems[i], delta=1)
                    if ss:
                        mergeSpinSystems(
                            ss,
                            spinSystems[i +
                                        1])  # copy resonances across & delete

                    makeSeqSpinSystemLink(spinSystems[i],
                                          spinSystems[i + 1],
                                          delta=1)

        self.updateSpinSystemsAfter()

    def commitAssignments(self):

        merge = showYesNo('Query', 'Merge with any existing spin systems?',
                          self)

        for spinSystem in self.spinSystemMatrix.currentObjects:
            if not spinSystem.residue:
                residue, p = self.getProbableResidue(spinSystem)
                assignSpinSystemResidue(spinSystem, residue, warnMerge=merge)

    def getProbableResidue(self, spinSystem):

        residue = None
        probability = 0.0

        if spinSystem.residue:
            return spinSystem.residue, 1.0

        data = []
        for residueProb in spinSystem.residueProbs:
            data.append((residueProb.weight, residueProb.possibility))
        data.sort()

        if data:
            residue, probability = data[-1]

        return residue, probability

    def getTentativeSpinSystems(self):

        spinSystemsList = []

        if self.project:

            for spinSystem in self.nmrProject.sortedResonanceGroups():
                if spinSystem.residueProbs and not spinSystem.residue:
                    #if spinSystem.residue:
                    residue, p = self.getProbableResidue(spinSystem)
                    key = '%s%s%4.4d' % (residue.chain.molSystem.code,
                                         residue.chain.code, residue.seqCode)
                    spinSystemsList.append((key, spinSystem))

        spinSystemsList.sort()

        return [x[1] for x in spinSystemsList]

    def updateSpinSystemsAfter(self, spinSystem=None):

        if self.waiting:
            return
        else:
            if spinSystem:
                if not spinSystem.residueProbs:
                    return
                if spinSystem.residue:
                    return

            self.waiting = True
            self.after_idle(self.updateSpinSystems)

    def getHeadings(self):

        headingList = ['#', 'Predicted\nResidue', 'Prob.', 'Links']

        atoms = self.atomSelector.getSelected()

        for atom in atoms:

            headingList.append(atom)

            if self.link == '-1':
                headingList.append('%s -1' % atom)
                headingList.append('D %s -1' % atom)

            elif self.link == '+1':
                headingList.append('%s +1' % atom)
                headingList.append('D %s +1' % atom)

            else:
                headingList.append('%s -1' % atom)
                headingList.append('D %s -1' % atom)
                headingList.append('%s +1' % atom)
                headingList.append('D %s +1' % atom)

        return headingList

    def addShiftData(self, spinSystem, datum):

        prevSS, nextSS = self.getConnectedSpinSystems(spinSystem)
        atoms = self.atomSelector.getSelected()
        dict = {}

        residue, p = self.getProbableResidue(spinSystem)
        prevRes = residue.chain.findFirstResidue(seqCode=residue.seqCode - 1)
        nextRes = residue.chain.findFirstResidue(seqCode=residue.seqCode + 1)
        prevSS0 = None
        nextSS0 = None
        for ss in self.getTentativeSpinSystems():
            if self.getProbableResidue(ss)[0] is prevRes:
                prevSS0 = ss
            if self.getProbableResidue(ss)[0] is nextRes:
                nextSS0 = ss
            if nextSS0 and prevSS0:
                break

        for atom in atoms:

            resonances = []
            resonancesPrev = []
            resonancesNext = []
            resonancesPrev0 = []
            resonancesNext0 = []
            for resonance0 in spinSystem.sortedResonances():
                for name in resonance0.assignNames:
                    if name[:2] == atom:
                        resonances.append(resonance0)
                        break

            text = ''
            if resonances:
                text = self.getResonanceText(resonances)
            datum.append(text)

            if prevSS and ('-1' in self.link):
                for resonance0 in prevSS.sortedResonances():
                    for name in resonance0.assignNames:
                        if name[:2] == atom:
                            resonancesPrev.append(resonance0)
                            break

            deltasPrev = []
            if prevSS0 and resonancesPrev:
                for resonance1 in prevSS0.sortedResonances():
                    for name1 in resonance1.assignNames:
                        if name1[:2] == atom:
                            shift1 = resonance1.findFirstShift(
                                parentList=self.shiftList)
                            deltas = []
                            for resonance2 in resonancesPrev:
                                shift2 = resonance2.findFirstShift(
                                    parentList=self.shiftList)
                                if shift1 and shift2:
                                    deltas.append(
                                        abs(shift1.value - shift2.value))

                            if deltas:
                                deltas.sort()
                                deltasPrev.append('%.2f' % deltas[0])
                            break

            if nextSS and ('+1' in self.link):
                for resonance0 in nextSS.sortedResonances():
                    for name in resonance0.assignNames:
                        if name[:2] == atom:
                            resonancesNext.append(resonance0)
                            break

            deltasNext = []
            if nextSS0 and resonancesNext:
                for resonance1 in nextSS0.sortedResonances():
                    for name1 in resonance1.assignNames:
                        if name1[:2] == atom:
                            shift1 = resonance1.findFirstShift(
                                parentList=self.shiftList)
                            deltas = []
                            for resonance2 in resonancesNext:
                                shift2 = resonance2.findFirstShift(
                                    parentList=self.shiftList)
                                if shift1 and shift2:
                                    deltas.append(
                                        abs(shift1.value - shift2.value))

                            if deltas:
                                deltas.sort()
                                deltasNext.append('%.2f' % deltas[0])
                            break

            if self.link == '-1':
                ppms = ''
                diff = ''
                if resonancesPrev:
                    ppms = self.getResonanceText(resonancesPrev)
                    diff = ','.join(deltasPrev)
                datum.append(ppms)
                datum.append(diff)

            elif self.link == '+1':
                ppms = ''
                diff = ''
                if resonancesNext:
                    ppms = self.getResonanceText(resonancesNext)
                    diff = ','.join(deltasNext)
                datum.append(ppms)
                datum.append(diff)

            else:
                ppms = ''
                diff = ''
                if resonancesPrev:
                    ppms = self.getResonanceText(resonancesPrev)
                    diff = ','.join(deltasPrev)
                datum.append(ppms)
                datum.append(diff)

                ppms = ''
                diff = ''
                if resonancesNext:
                    ppms = self.getResonanceText(resonancesNext)
                    diff = ','.join(deltasNext)
                datum.append(ppms)
                datum.append(diff)

    def updateSpinSystems(self):

        textMatrix = []
        objectList = []
        colorMatrix = []
        headingList = self.getHeadings()

        for spinSystem in self.getTentativeSpinSystems():

            residueText = None
            residue, probability = self.getProbableResidue(spinSystem)
            if residue:
                residueText = '%d%s' % (residue.seqCode,
                                        getResidueCode(residue))

            links = []
            color = '#D04040'

            if findConnectedSpinSystem(spinSystem, delta=-1):
                links.append('-1')

            if findConnectedSpinSystem(spinSystem, delta=1):
                links.append('+1')

            if len(links) == 2:
                color = '#40B040'
            elif len(links) == 1:
                color = '#B0B040'

            datum = []
            datum.append(spinSystem.serial)
            datum.append(residueText)
            datum.append(probability)
            datum.append(' '.join(links))

            self.addShiftData(spinSystem, datum)

            colors = [None] * len(headingList)
            colors[3] = color

            objectList.append(spinSystem)
            textMatrix.append(datum)
            colorMatrix.append(colors)

        if self.spinSystem not in objectList:
            self.spinSystem = None

        self.spinSystemMatrix.update(headingList=headingList,
                                     objectList=objectList,
                                     textMatrix=textMatrix,
                                     colorMatrix=colorMatrix)
        self.updateButtons()
        self.waiting = False

    def getResonanceText(self, resonances):

        shifts = []

        for resonance in resonances:
            shift = resonance.findFirstShift(parentList=self.shiftList)
            if shift:
                shifts.append('%.2f' % shift.value)

        return ','.join(shifts)

    def getConnectedSpinSystems(self, spinSystem):

        if self.link == '-1':
            prevSS = findConnectedSpinSystem(spinSystem, delta=-1)
            nextSS = None
        elif self.link == '+1':
            prevSS = None
            nextSS = findConnectedSpinSystem(spinSystem, delta=1)
        else:
            prevSS = findConnectedSpinSystem(spinSystem, delta=-1)
            nextSS = findConnectedSpinSystem(spinSystem, delta=1)

        return prevSS, nextSS

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

        self.spinSystem = object
        self.updateButtons()

    def destroy(self):

        for func in ('__init__', 'delete'):
            for clazz in ('ccp.nmr.Nmr.ShiftList', ):
                self.unregisterNotify(self.updateShiftLists, clazz, func)

        for func in ('__init__', 'delete', 'setNmrChains', 'setResidue',
                     'setResonances', 'addResonance', 'removeResonance'):
            self.unregisterNotify(self.updateSpinSystemsAfter,
                                  'ccp.nmr.Nmr.ResonanceGroup', func)

        BasePopup.destroy(self)
Пример #3
0
class BrowseReferenceShiftsPopup(BasePopup):
  """
  **Graphs and Charts of Database Chemical Shift Data**
  
  This popup window presents the user with the distributions of known chemical
  shift values, for various kinds of atom, as they appear in the BioMagResBank
  or re-referenced RefDB databases. This information is useful when attempting
  to determine the type of a residue from its NMR spectra, for example when
  performing protein sequence assignment.

  The popup is divided into two tabs for two different kinds of graphical
  display. The first "1D graphs" tab shows the distributions of chemical shift
  value for either hydrogens or other "heavy" atoms within a given kind of
  residue. The buttons that carry atom names above the main graph can be toggled
  two switch the display for different kinds of atom on or off.

  The second "Amino Acid CA CB" tab is a special display to assist in the 
  assignment of protein sequences when using triple-resonance experiments
  like HNCA/CB. Data for all of the common amino acids is displayed, but
  only for the alpha and beta carbons.

  **Caveats & Tips**

  Two dimensional correlations, e.g. between a 1H resonance and a covalently
  bound 13C will be added to Analysis in the future.

  DNA and RNA chemical shift distributions is not present in the RefDB data, but
  are present in the BMRB data; to view the BMRB data change the pulldown menu
  at the top-right.

  Some of the atom types have a second, minor chemical shift distribution, far
  from the main peak, that is erroneous (this data is still present in the
  source databases). An example of this is for the NE atom of the amino acid
  arginine at around 115 ppm, which in this instance is probably caused by peaks
  being assigned in HSQC spectra in the normal backbone amide ppm range when the
  NE peak is really an aliased harmonic and should be a spectrum width away,
  nearer 85 ppm.

  Distributions that are notably jagged, due to lack of data for a given atom
  type should naturally not be relied upon to any great degree.

  """

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

    self.guiParent = parent
    self.sourceName = 'RefDB'
    self.chemAtomNmrRefs = {}
    
    BasePopup.__init__(self, parent=parent, title="Resonance : Reference Chemical Shifts", **kw)

  def body(self, guiFrame):
    
    self.geometry("775x500")
    guiFrame.expandGrid(0,0)
    
    options = ['1D Graphs','Amino Acid CA CB']
    tipTexts = ['Simple graphs of how chemical shift values are distributed for a given atom type',
                'Density plots of alpha a & beta carbon shift distributions for common amnio acids']
    tabbedFrame = TabbedFrame(guiFrame, options=options, grid=(0,0), tipTexts=tipTexts)
    frameA, frameB = tabbedFrame.frames
    
    # # # # # # #  1D GRAPHS  # # # # # # # 
    
 
    row = 0
     
    MolType = self.project.metaclass.metaObjFromQualName('ccp.molecule.ChemComp.MolType')
    molTypes = MolType.enumeration
    molTypes.remove('other')
    molTypes.remove('carbohydrate')
   
    self.molType = 'protein'
    
    ccpCodes = self.getCcpCodes(self.molType) or [None,]
    self.ccpCode = 'Ala'
    
    self.atomType = ATOM_TYPES[0]
    
    self.atomNamesDict = {}
    self.chemAtomNmrRefs = self.getCcpCodeData(self.ccpCode, atomType=self.atomType)
    
    
    tipText = 'Which of the common bio-polymer types to show data for'
    self.molTypeLabel     = Label(frameA, text = 'Molecule Type:', grid=(row,0))
    self.molTypePulldown  = PulldownList(frameA, callback=self.changeMolType,
                                         texts=molTypes, grid=(row,1), tipText=tipText)

    tipText = 'Which residue code to show chemical shift distributions for'
    self.ccpCodeLabel     = Label(frameA, text = 'Residue Code:', grid=(row,2))
    self.ccpCodePulldown  = PulldownList(frameA, callback=self.changeCcpCode, texts=ccpCodes,
                                         index=ccpCodes.index(self.ccpCode), 
                                         grid=(row,3), tipText=tipText)

    tipText = 'Whether to show distributions for hydrogen atoms or other atoms'
    self.atomTypeLabel    = Label(frameA, text = 'Atom Type:', grid=(row,4))
    self.atomTypePulldown = PulldownList(frameA, callback=self.changeAtomType,
                                         texts=ATOM_TYPES, tipText=tipText,
                                         grid=(row,5))

    row += 1

    tipText = 'The selection of atom name to display distributions for'
    self.atomSelector = PartitionedSelector(frameA, self.toggleAtom,
                                            tipText=tipText, maxRowObjects=20)
    self.atomSelector.grid(row=row, column=0, columnspan=6, sticky='ew')

    row += 1

    frameA.expandGrid(row,5)
    self.scrolledGraph = ScrolledGraph(frameA, symbolSize=2, reverseX=True, width=650,
                                       height=300, title='Chemical shift distribution',
                                       xLabel='Chemical shift', yLabel='proportion',
                                       motionCallback=self.updateCrosshairs)
    self.scrolledGraph.grid(row=row, column=0, columnspan=6, sticky='nsew')
    
    # # # # # # #  PROTEIN CA CB   # # # # # # # 
    
    frameB.expandGrid(0,0)
    matrix, ppms = self.getCaCbMatrix()
    title = 'Amino Acid CA & CB Chemical Shifts'
    self.cacbMatrix = ScrolledDensityMatrix(frameB, matrix=matrix, boxSize=14,
                                            title=title,
                                            xLabels=ppms, yLabels=AMINO_ACIDS,
                                            borderColor='grey', zoom=1.0,
                                            labelAxes=True, barPlot=False,
                                            doLegend=False, grid=(0,0))
    
    sdm = self.cacbMatrix
    font = sdm.boldFont
    
    x0, y0 = (470,370)
    sdm.canvas.create_rectangle(x0+170,y0-6,x0+182,y0+6,fill='#4040A0',
                                outline=sdm.borderColor, width=1)
    sdm.canvas.create_text(x0+200, y0, text='CA', font=font)
    sdm.canvas.create_rectangle(x0+220,y0-6,x0+232,y0+6,fill='#A04040',
                                outline=sdm.borderColor, width=1)
    sdm.canvas.create_text(x0+250, y0, text='CB', font=font)
    sdm.canvas.create_text(x0, y0, text='13C PPM +/- 0.5', font=font)
    
    # # # # # # #  M A I N   # # # # # # # 
    
    tipText = 'Whether to use chemical shift data from the BMRB (unfiltered) or RefDB sets'
    label = Label(tabbedFrame.sideFrame, text='Source Database:', grid=(0,0), sticky='e')
    index = SOURCE_NAMES.index(self.sourceName)
    self.sourcePulldown = PulldownList(tabbedFrame.sideFrame, self.changeSource,
                                       texts=SOURCE_NAMES, index=index, 
                                       grid=(0,1), sticky='e', tipText=tipText)

    self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame, expands=True,
                                           helpUrl=self.help_url, sticky='e',
                                           grid=(0,2))
                                               
    self.waiting = False
    self.updateAfter()

    for func in ('__init__', 'delete'):
      self.registerNotify(self.updateAfter, 'ccp.nmr.NmrReference.NmrReferenceStore', func)

  def open(self):
  
    self.updateAfter()
    BasePopup.open(self)
  
  def changeSource(self, sourceName):
  
    if sourceName is not self.sourceName:
      self.sourceName = sourceName
      self.updateCcpCodes()
      self.updateAfter()
    
  def getAtomColor(self, i,N):
    
    h = i/float(N)
    s = 1
    v = 0.8
    [r,g,b] = hsbToRgb(h,s,v)
   
    return hexRepr(r,g,b)

  def toggleAtom(self, atomName):
  
    if self.atomNamesDict.get(atomName):
      self.atomNamesDict[atomName] = False
    else:
      self.atomNamesDict[atomName] = True

    self.updateAfter()

  def getCcpCodes(self, molType):
  
    sourceName = self.sourceName

    ccpCodes = []
    for nmrRef in self.project.findAllNmrReferenceStores(molType=molType):
      chemCompNmrRef = nmrRef.findFirstChemCompNmrRef(sourceName=sourceName)
      
      if chemCompNmrRef:
        ccpCodes.append(nmrRef.ccpCode)
    
    ccpCodes.sort()
      
    return ccpCodes
  
  def getCcpCodeData(self, ccpCode, molType=None, atomType=None):

    if not molType:
      molType = self.molType

    dataDict = {}
    project = self.project
    sourceName = self.sourceName
    
    nmrRefStore = project.findFirstNmrReferenceStore(molType=molType,ccpCode=ccpCode)
     
    chemCompNmrRef = nmrRefStore.findFirstChemCompNmrRef(sourceName=sourceName)
    if chemCompNmrRef:
    
      chemCompVarNmrRef = chemCompNmrRef.findFirstChemCompVarNmrRef(linking='any',descriptor='any')
      if chemCompVarNmrRef:
        for chemAtomNmrRef in chemCompVarNmrRef.chemAtomNmrRefs:
          atomName = chemAtomNmrRef.name
          element  = chemAtomNmrRef.findFirstChemAtom().elementSymbol
  
          if not atomType:
            dataDict[atomName] = chemAtomNmrRef
  
          elif (atomType == 'Hydrogen' and element == 'H') or \
               (atomType == 'Heavy' and element != 'H'):
            dataDict[atomName] = chemAtomNmrRef
 
    return dataDict  
 
  def changeMolType(self, molType):
  
    self.molType = molType
    self.updateCcpCodes()
  
  def changeCcpCode(self, ccpCode):
  
    self.ccpCode = ccpCode
    self.updateAtomNames()
       
  def changeAtomType(self, atomType):
  
    self.atomType = atomType
    self.updateAtomNames()
       
  def updateAfter(self, *opt):
  
    if self.waiting:
      return
    else:
      self.waiting = True
      self.after_idle(self.update)

  def updateCcpCodes(self):
    
    ccpCodes = self.getCcpCodes(self.molType)
    if ccpCodes:
      self.ccpCodePulldown.setup(ccpCodes, ccpCodes, 0)
      self.changeCcpCode(ccpCodes[0])
    else:
      self.ccpCodePulldown.setup([], [], 0)
      self.changeCcpCode(None)
      
  
  def updateAtomNames(self):
  
    if self.ccpCode:
      self.chemAtomNmrRefs = self.getCcpCodeData(self.ccpCode, atomType=self.atomType)
      atomNames = self.chemAtomNmrRefs.keys()
      atomNames = greekSortAtomNames(atomNames, self.molType)
      N = len(atomNames)

      for atomName in atomNames:
        if self.atomNamesDict.get(atomName) is None:
          self.atomNamesDict[atomName] = True

      colors = []
      for i in range(N):
        colors.append( self.getAtomColor(i,N) )

 
    else:
      colors = []
      atomNames = []
      N = 0
 
    self.atomSelector.update(objects=atomNames,labels=atomNames,colors=colors)
        
    for i in range(N):
      if self.atomNamesDict[atomNames[i]]:
        self.atomSelector.setButtonState(i, True)
      else:
        self.atomSelector.setButtonState(i, False)

    self.updateAfter()
  
  def destroy(self):

    for func in ('__init__', 'delete'):
      self.unregisterNotify(self.updateAfter, 'ccp.nmr.NmrReference.NmrReferenceStore', func)

    BasePopup.destroy(self)
    
  def update(self):

    matrix, ppms = self.getCaCbMatrix()
    self.cacbMatrix.xLabels = ppms
    self.cacbMatrix.update(matrix)
       
    self.updateAtomNames()
    dataSets = []
    colorList = []
    atomsString = ''
    
    if self.ccpCode:
      c = 0
      atomNames = self.chemAtomNmrRefs.keys()
      N = len(atomNames)
      for atomName in greekSortAtomNames(atomNames, self.molType):
        if self.atomNamesDict[atomName]:
          atomsString += '%s ' % atomName
          chemAtomNmrRef = self.chemAtomNmrRefs[atomName]
          distribution   = chemAtomNmrRef.distribution
          refPoint       = chemAtomNmrRef.refPoint
          refValue       = chemAtomNmrRef.refValue
          valuePerPoint  = chemAtomNmrRef.valuePerPoint

          data = []
          for i in range(len(distribution)):
            x = refValue + valuePerPoint*( i-refPoint)
            y = distribution[i]
            data.append( (x,y) )
 
          dataSets.append(data)
          colorList.append(self.getAtomColor(c,N))
        c += 1
 
      self.scrolledGraph.title = '%s %s Chemical shift distribution' % (self.ccpCode,atomsString)
    else:
      dataSets = [[(0,0)],]
      self.scrolledGraph.title = 'Chemical shift distribution'
    
    self.scrolledGraph.zoom  = 1.0
    
    self.scrolledGraph.update(dataSets=dataSets, dataColors=colorList)  
    
    self.waiting = False
    
  def getCaCbMatrix(self):  
    
    ppms = range(73,14,-1)
    blankCol = [0.0]*len(ppms)
    matrix = [[0.0]*len(AMINO_ACIDS) for x in ppms]
    
    for i, ccpCode in enumerate(AMINO_ACIDS):
      atomRefDict = self.getCcpCodeData(ccpCode, molType='protein')
      valueDict = {}
      
      for atomName in ('CA','CB'):
        valueDict[atomName] = blankCol[:]
        
        chemAtomNmrRef = atomRefDict.get(atomName)
        if not chemAtomNmrRef:
          continue
          
        distribution   = chemAtomNmrRef.distribution
        refPoint       = chemAtomNmrRef.refPoint
        refValue       = chemAtomNmrRef.refValue
        valuePerPoint  = chemAtomNmrRef.valuePerPoint
        
        
        for j, ppm in enumerate(ppms):
          ppmMin = ppm-0.5
          ppmMax = ppm+0.5
 
          v = 0.0
          n = 0.0
          for k in range(len(distribution)):
            y = refValue + valuePerPoint*(k-refPoint)
 
            if ppmMin < y <= ppmMax:
              v += distribution[k]
              n += 1.0
            elif y > ppmMax:
              break
 
          if n:
            valueDict[atomName][j] = v/n
      
      for j, ppm in enumerate(ppms):
        matrix[j][i] = valueDict['CA'][j] - valueDict['CB'][j]

    return matrix, ppms

  def updateCrosshairs(self, event):

    # code below is a bit dangerous

    position = self.scrolledGraph.getPlotCoords(event)[0]

    typeLocation = []
    isHydrogen = (self.atomType == 'Hydrogen')
    for panelType in self.analysisProject.panelTypes:
      axisType = panelType.axisType
      if isHydrogen:
        if axisType.name in ('1H', '2H'):
          typeLocation.append((panelType, position))
      else:
        if axisType.name not in ('1H', '2H'):
          typeLocation.append((panelType, position))

    self.scrolledGraph.mouseEnter(event)
    self.parent.drawWindowCrosshairs(typeLocation)

  def drawCrosshairs(self, typeLocation):
    """ Draw crosshairs at specified locations.
        typeLocation = tuple of (PanelType, position)
    """

    isHydrogen = (self.atomType == ATOM_TYPES[0])

    positions = []
    for (panelType, position) in typeLocation:
      axisType = panelType.axisType
      if axisType.measurementType != 'Shift':
        continue
        
      if position is None:
        continue

      if isHydrogen:
        if axisType.name in ('1H', '2H'):
          positions.append(position)
      else:
        if axisType.name not in ('1H', '2H'):
          positions.append(position)

    self.scrolledGraph.drawVerticalLines(positions)
Пример #4
0
class CalcCouplingPopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.waiting = False
        self.peakList = None
        self.peakLists = []
        self.windowPane = None
        self.cluster = None
        self.clusters = {}
        self.multiplet = None
        self.guiParent = parent

        BasePopup.__init__(self,
                           parent=parent,
                           title='Measure Couplings',
                           **kw)

        self.updateWindows()
        self.updateAfter()

    def body(self, guiFrame):

        guiFrame.grid_columnconfigure(0, weight=1)

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

        label = Label(frame, text='Window:')
        label.grid(row=0, column=0, sticky='nw')
        self.windowPulldown = PulldownList(frame, callback=self.changeWindow)
        self.windowPulldown.grid(row=0, column=1, sticky='nw')

        label = Label(frame, text='Multiplet Pattern:')
        label.grid(row=1, column=0, columnspan=2, sticky='nw')
        self.multipletButtons = PartitionedSelector(frame,
                                                    callback=self.setMultiplet,
                                                    radio=True)
        self.multipletButtons.grid(row=2, column=0, columnspan=2, sticky='ew')

        row += 1
        frame = LabelFrame(guiFrame, text='Active Peak Lists')
        frame.grid(row=row, column=0, sticky='ew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        headingList = [
            'Experiment', 'Spectrum', 'List', 'Coupled Dims', 'Experiment Type'
        ]
        self.peakListMatrix = ScrolledMatrix(frame,
                                             headingList=headingList,
                                             callback=None,
                                             multiSelect=False)
        self.peakListMatrix.grid(row=0, column=0, sticky='nsew')

        row += 1
        guiFrame.grid_rowconfigure(row, weight=1)
        frame = LabelFrame(guiFrame, text='Multiplet Peak Clusters')
        frame.grid(row=row, column=0, sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        headingList = [
            '#', 'Main\nAssignment', 'Num\nPeaks', 'Coupling\nAssignment',
            'Value', 'Value'
        ]
        self.clusterMatrix = ScrolledMatrix(frame,
                                            headingList=headingList,
                                            callback=self.selectCluster,
                                            multiSelect=True)
        self.clusterMatrix.grid(row=0, column=0, sticky='nsew')

        row += 1
        texts = [
            'Cluster Selected\nPeaks', 'Assign\nCouplings', 'List\nPeaks',
            'Find\nPeaks', 'Delete\nClusters'
        ]
        commands = [
            self.clusterSelectedPeaks, self.assignCouplings, self.showPeaks,
            self.findPeaks, self.deleteClusters
        ]
        self.bottomButtons = UtilityButtonList(guiFrame,
                                               texts=texts,
                                               expands=True,
                                               commands=commands,
                                               helpUrl=self.help_url)
        self.bottomButtons.grid(row=row, column=0, sticky='ew')

        self.administerNotifiers(self.registerNotify)

    def administerNotifiers(self, notifyFunc):

        for clazz in ('ccp.nmr.Nmr.DataSource', 'ccp.nmr.Nmr.Experiment'):
            notifyFunc(self.updatePeakListsAfter, clazz, 'setName')

        for func in ('__init__', 'delete', 'setName'):
            notifyFunc(self.updateWindows, 'ccpnmr.Analysis.SpectrumWindow',
                       func)

        for func in ('__init__', 'delete'):
            notifyFunc(self.updatePeakListsAfter, 'ccp.nmr.Nmr.PeakList', func)

        for func in ('__init__', 'delete', 'addPeak', 'setPeaks', 'removePeak',
                     'setAnnotation'):
            notifyFunc(self.updateAfter, 'ccp.nmr.Nmr.PeakCluster', func)

    def deleteClusters(self):

        clusters = self.clusterMatrix.currentObjects
        for cluster in clusters:
            deleteCluster(cluster)

    def findPeaks(self):

        if self.windowPane and self.cluster:
            peaks = list(self.cluster.peaks)
            if not peaks:
                return

            spectrum = peaks[0].peakList.dataSource
            analysisSpectrum = spectrum.analysisSpectrum
            view = self.windowPane.findFirstSpectrumWindowView(
                analysisSpectrum=analysisSpectrum)
            windowFrame = self.windowPane.getWindowFrame()

            position = {}
            n = float(len(peaks))

            for axisMapping in view.axisMappings:
                dim = axisMapping.analysisDataDim.dataDim.dim
                xyz = axisMapping.label

                mean = 0.0
                for peak in peaks:
                    peakDim = peak.findFirstPeakDim(dim=dim)
                    mean += peakDim.realValue

                mean /= n
                position[xyz] = mean

            windowFrame.gotoPosition(position)

    def updatePeakListsAfter(self, object):

        if object.className == 'Experiment':
            for spectrum in object.dataSources:
                for peakList in spectrum.peakLists:
                    if peakList in self.peakLists:
                        self.updatePeakLists()

        elif object.className == 'DataSource':
            for peakList in object.peakLists:
                if peakList in self.peakLists:
                    self.updatePeakLists()

        else:
            if object in self.peakLists:
                self.updatePeakLists(object)

    def open(self):

        BasePopup.open(self)

        self.updateWindows()
        self.updateAfter()

    def showPeaks(self):

        peaks = {}
        for peakCluster in self.clusterMatrix.currentObjects:
            for peak in peakCluster.peaks:
                peaks[peak] = True

        if peaks:
            self.parent.viewPeaks(peaks.keys())

    def getWindows(self):

        windowPanes = []

        for window in self.analysisProject.sortedSpectrumWindows():
            for windowPane in window.sortedSpectrumWindowPanes():
                for view in windowPane.spectrumWindowViews:
                    if view.isPosVisible or view.isNegVisible:
                        spectrum = view.analysisSpectrum.dataSource

                        if self.getCoupledExpDims(spectrum.experiment):
                            windowPanes.append(windowPane)
                            break

        return windowPanes

    def getCoupledExpDims(self, experiment):
        """ Descrn: List the dimensions (ExpDims) of an experiment which carry couplings.
        Inputs: Nmr.Experiment
        Output: List of Nmr.ExpDims
    """
        COUPLING_TYPES = ('JCoupling', 'Rdc', 'DipolarCoupling')

        expDims = []
        refExperiment = experiment.refExperiment

        if refExperiment:
            for expDim in experiment.expDims:
                refExpDim = expDim.refExpDim

                if not refExpDim:  # Could be sampled dim
                    continue

                for refExpDimRef in refExpDim.refExpDimRefs:
                    if refExpDimRef.coupledIsotopeCodes:
                        expDims.append(expDim)
                        break

        if not expDims:
            for expDim in experiment.expDims:
                for expDimRef in expDim.expDimRefs:
                    if expDimRef.measurementType in COUPLING_TYPES:
                        expDims.append(expDim)
                        break

        return expDims

    def changeWindow(self, windowPane):

        if windowPane is not self.windowPane:
            self.windowPane = windowPane
            self.updatePeakLists()

    def updateWindows(self, *object):

        panes = self.getWindows()
        index = 0
        names = []
        pane = self.windowPane

        if panes:
            names = [getWindowPaneName(wp) for wp in panes]

            if pane not in panes:
                pane = panes[0]

            index = panes.index(pane)

        if pane is not self.windowPane:
            self.windowPane = pane
            self.updatePeakLists()

        self.windowPulldown.setup(names, panes, index)

    def getPeakLists(self):

        peakLists = []

        if self.windowPane:
            for view in self.windowPane.spectrumWindowViews:
                try:
                    spectrum = view.analysisSpectrum.dataSource
                except:
                    continue

                if spectrum.peakLists:
                    peakList = spectrum.activePeakList

                    if not peakList:
                        peakList = spectrum.findFirstPeakList()

                    peakLists.append(peakList)

        return peakLists

    def updatePeakLists(self, peakList=None):

        objectList = self.getPeakLists()
        textMatrix = []
        spectra = {}

        for peakList0 in objectList:
            spectrum = peakList0.dataSource
            experiment = spectrum.experiment
            spectra[spectrum] = True
            refExperiment = experiment.refExperiment
            coupledDims = []
            if refExperiment:
                experimentType = refExperiment.name

                for expDim in experiment.expDims:
                    refExpDim = expDim.refExpDim
                    isotopes = {}

                    for refExpDimRef in refExpDim.refExpDimRefs:
                        for isotope in refExpDimRef.coupledIsotopeCodes:
                            isotopes[isotope] = True

                    if isotopes:
                        isoString = ','.join(isotopes)
                        coupledDims.append('%d (%s)' % (expDim.dim, isoString))

            else:
                experimentType = None

            if not coupledDims:
                coupledDims = None
            else:
                coupledDims = ' '.join(coupledDims)

            datum = [
                experiment.name, spectrum.name, peakList0.serial, coupledDims,
                experimentType
            ]
            textMatrix.append(datum)

        self.peakLists = objectList
        self.peakListMatrix.update(objectList=objectList,
                                   textMatrix=textMatrix)

        self.multiplet = None
        for spectrum in spectra.keys():
            multiplet = self.getSpectrumMultiplet(spectrum)

            if multiplet:
                self.multiplet = MULTIPLET_PEAK_DICT.get(multiplet)
                break

        self.updateMultipletButtons()
        self.updateAfter()

    def setMultiplet(self, pattern):

        for peakList in self.peakLists:
            spectrum = peakList.dataSource

            for name in MULTIPLET_PEAK_DICT.keys():
                if MULTIPLET_PEAK_DICT[name] == pattern:
                    setSpectrumMultipletPattern(spectrum, name)
                    break

        self.multiplet = pattern

    def setSpectrumMultiplet(self, spectrum, pattern):

        prevPattern = getSpectrumMultipletPattern(spectrum)

        if prevPattern and (prevPattern != pattern):
            if showOkCancel('Query',
                            'Really change multiplet pattern?',
                            parent=self):

                setSpectrumMultipletPattern(spectrum, pattern)

    def getSpectrumMultiplet(self, spectrum):

        name = getSpectrumMultipletPattern(spectrum)

        if not name:
            name = self.predictSpectrumMultiplet(spectrum)
            setSpectrumMultipletPattern(spectrum, name)

        return name

    def predictSpectrumMultiplet(self, spectrum):

        name = None

        refExperiment = spectrum.experiment.refExperiment
        if refExperiment:
            name = EXPT_MULTIPLETS.get(refExperiment.name)

        return name

    def updateMultipletButtons(self):

        import re

        labels = []
        objects = []
        colors = []
        selected = None

        if self.windowPane:
            coupledAxes = []
            spectra = {}
            for peakList in self.peakLists:
                spectra[peakList.dataSource] = True
                multiplet = self.getSpectrumMultiplet(peakList.dataSource)
                selected = MULTIPLET_PEAK_DICT[multiplet]

            for spectrum in spectra.keys():
                mapping = getDataDimAxisMapping(spectrum, self.windowPane)

                for axisLabel in ('x', 'y'):
                    dataDim = mapping[axisLabel]

                    for expDimRef in dataDim.expDim.expDimRefs:
                        if expDimRef.refExpDimRef and expDimRef.refExpDimRef.coupledIsotopes:
                            if axisLabel not in coupledAxes:
                                coupledAxes.append(axisLabel)
                                break

        else:
            coupledAxes = ['x', 'y']

        for name in MULTIPLET_PEAK_DICT.keys():

            pattern = MULTIPLET_PEAK_DICT[name]

            if type(pattern[0]) in (type(()), type([])):
                if 'y' not in coupledAxes:
                    continue

                if len(pattern[0]) > 1:  # x & y
                    if 'x' not in coupledAxes:
                        continue

                else:  # y only
                    if 'x' in coupledAxes:
                        continue

            else:  # x only
                if 'x' not in coupledAxes:
                    continue

                if 'y' in coupledAxes:
                    continue

            label = re.sub('\|', '\n', name)

            objects.append(pattern)
            labels.append(label)
            colors.append('#8080FF')

        self.multipletButtons.update(objects=objects,
                                     colors=colors,
                                     labels=labels)

        self.multipletButtons.setSelected([
            selected,
        ])

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

        self.peakList = object

        self.updateButtons()

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

        self.cluster = object

        self.updateButtons()

    def assignCouplings(self):

        for cluster in self.clusterMatrix.currentObjects:
            assignPrimaryClusterCoupling(cluster)

    def assignAllCouplings(self):

        for cluster in self.clusters.keys():
            assignPrimaryClusterCoupling(cluster)

    def clusterSelectedPeaks(self):

        peaks0 = self.parent.currentPeaks
        peaks = []
        for peak in peaks0:
            if peak.peakList in self.peakLists:
                peaks.append(peak)

        if not peaks:
            showWarning('Cluster Failure',
                        'No peaks selected from active peak lists',
                        parent=self)
            return

        if not self.multiplet:
            showWarning('Cluster Failure',
                        'No multiplet pattern selected',
                        parent=self)
            return

        cluster = makeMultipletPeakCluster(peaks, self.multiplet,
                                           self.windowPane)

        if cluster:
            self.clusterMatrix.selectObject(cluster)

    def getActiveClusterCouplings(self):

        clusters = {}
        if self.peakLists:
            dims = {}

            for peakList in self.peakLists:
                experiment = peakList.dataSource.experiment

                for expDim in getCoupledExpDims(experiment):
                    dims[expDim.dim] = True

            dims = dims.keys()

            for cluster in getPeakListsPeakClusters(self.peakLists):
                values = []

                for dim in dims:
                    values.append(getClusterCoupling(cluster, dim))
                    # Allow Nones?

                clusters[cluster] = values

        self.clusters = clusters

        return clusters

    def updateButtons(self):

        pass

    def updateAfter(self, cluster=None):

        if self.waiting:
            return

        if cluster:
            for peak in cluster.peaks:
                if peak.peakList in self.peakLists:
                    self.waiting = True
                    self.after_idle(self.update)
                    break

        else:
            self.waiting = True
            self.after_idle(self.update)

    def update(self):

        clusters = self.getActiveClusterCouplings()

        textMatrix = []
        objectList = []

        headingList = [
            '#', 'Main\nAssignment', 'Num\nPeaks', 'Coupling\nAssignment'
        ]

        if clusters:
            cluster0 = clusters.keys()[0]
            i = 1

            for value in clusters[cluster0]:
                headingList.append('F%d Value\n(Hz)' % i)
                i += 1

        else:
            headingList.append('Value')

        for cluster in clusters.keys():

            couplingAssign = ','.join(getCouplingAnnotations(cluster))

            datum = [
                cluster.serial, cluster.annotation,
                len(cluster.peaks), couplingAssign
            ]

            values = clusters[cluster]
            for value in values:
                datum.append(value)

            textMatrix.append(datum)
            objectList.append(cluster)

        self.clusterMatrix.update(headingList=headingList,
                                  textMatrix=textMatrix,
                                  objectList=objectList)

        self.updateButtons()
        self.waiting = False

    def destroy(self):

        self.administerNotifiers(self.unregisterNotify)

        BasePopup.destroy(self)