示例#1
0
class ResultsTab(object):
    def __init__(self, parent, frame):

        self.guiParent = parent

        self.frame = frame

        self.project = parent.project

        self.nmrProject = parent.nmrProject

        self.selectedLinkA = None
        self.selectedLinkB = None
        self.selectedResidueA = None
        self.selectedResidueB = None
        self.selectedLink = None

        self.dataModel = self.guiParent.connector.results

        self.body()

    def body(self):

        frame = self.frame

        self.resultsResidueNumber = 1

        frame.expandGrid(5, 0)

        resultTopFrame = LabelFrame(frame, text='Which results to show')
        resultTopFrame.grid(row=0, column=0, sticky='ew')

        self.resultsResidueNumber = 3

        texts = [' < ']
        commands = [self.resultsPrevResidue]
        self.resultsPreviousButton = ButtonList(resultTopFrame,
                                                commands=commands,
                                                texts=texts)
        self.resultsPreviousButton.grid(row=0, column=1, sticky='nsew')

        tipText = 'The Number of the residue in the sequence to display results for'
        self.resultsResidueNumberEntry = IntEntry(
            resultTopFrame,
            grid=(0, 2),
            width=7,
            text=3,
            returnCallback=self.resultsUpdateAfterEntry,
            tipText=tipText)
        #self.resultsResidueNumberEntry.bind('<Leave>', self.resultsUpdateAfterEntry, '+')

        texts = [' > ']
        commands = [self.resultsNextResidue]
        self.resultsNextButton = ButtonList(resultTopFrame,
                                            commands=commands,
                                            texts=texts)
        self.resultsNextButton.grid(row=0, column=3, sticky='nsew')

        selectCcpCodes = ['residue'] + AMINO_ACIDS
        self.resultsSelectedCcpCode = 'residue'

        tipText = 'Instead of going through the sequence residue by residue, jump directly to next amino acid of a specific type.'
        resultsSelectCcpCodeLabel = Label(
            resultTopFrame,
            text='Directly jump to previous/next:',
            grid=(0, 4))
        self.resultsSelectCcpCodePulldown = PulldownList(
            resultTopFrame,
            callback=self.resultsChangeSelectedCcpCode,
            texts=selectCcpCodes,
            index=selectCcpCodes.index(self.resultsSelectedCcpCode),
            grid=(0, 5),
            tipText=tipText)

        self.selectedSolution = 1

        runLabel = Label(resultTopFrame, text='run:')
        runLabel.grid(row=0, column=6)

        texts = [' < ']
        commands = [self.resultsPrevSolution]
        self.resultsPreviousSolutionButton = ButtonList(resultTopFrame,
                                                        commands=commands,
                                                        texts=texts)
        self.resultsPreviousSolutionButton.grid(row=0, column=7, sticky='nsew')

        tipText = 'If you ran the algorithm more than once, you can select the solution given by the different runs.'
        self.resultsSolutionNumberEntry = IntEntry(
            resultTopFrame,
            grid=(0, 8),
            width=7,
            text=1,
            returnCallback=self.solutionUpdateAfterEntry,
            tipText=tipText)
        #self.resultsSolutionNumberEntry.bind('<Leave>', self.solutionUpdateAfterEntry, '+')

        texts = [' > ']
        commands = [self.resultsNextSolution]
        self.resultsNextSolutionButton = ButtonList(resultTopFrame,
                                                    commands=commands,
                                                    texts=texts)
        self.resultsNextSolutionButton.grid(row=0, column=9, sticky='nsew')

        self.energyLabel = Label(resultTopFrame, text='energy:')
        self.energyLabel.grid(row=0, column=10)

        texts = ['template for puzzling']
        commands = [self.adoptSolution]
        self.adoptButton = ButtonList(resultTopFrame,
                                      commands=commands,
                                      texts=texts)
        self.adoptButton.grid(row=0, column=11, sticky='nsew')

        # LabelFrame(frame, text='Spin Systems')
        resultsSecondFrame = Frame(frame)
        resultsSecondFrame.grid(row=2, column=0, sticky='nsew')

        resultsSecondFrame.grid_columnconfigure(0, weight=1)
        resultsSecondFrame.grid_columnconfigure(1, weight=1)
        resultsSecondFrame.grid_columnconfigure(2, weight=1)
        resultsSecondFrame.grid_columnconfigure(3, weight=1)
        resultsSecondFrame.grid_columnconfigure(4, weight=1)

        headingList = ['#', '%']

        tipTexts = [
            'Spinsystem number {} indicates serial of the spinsystem. If the spinsystem was already assigned to a residue, the residue number is shown aswell',
            'percentage of the solutions that connected this spinsystem to this residue'
        ]

        editWidgets = [None, None, None]

        self.displayResultsTables = []
        self.residueLabels = []

        for i in range(5):

            label = Label(resultsSecondFrame, text='residue')
            label.grid(row=0, column=i)

            #editGetCallbacks = [createCallbackFunction(i)]*3

            displayResultsTable = ScrolledMatrix(
                resultsSecondFrame,
                headingList=headingList,
                multiSelect=False,
                tipTexts=tipTexts,
                callback=self.selectSpinSystemForTable,
                passSelfToCallback=True)

            displayResultsTable.grid(row=2, column=i, sticky='nsew')
            displayResultsTable.sortDown = False

            self.residueLabels.append(label)
            self.displayResultsTables.append(displayResultsTable)

        # LabelFrame(frame, text='Sequence Fragment')
        resultsFirstFrame = Frame(resultsSecondFrame)
        resultsFirstFrame.grid(row=1, column=0, sticky='ew', columnspan=5)

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

        texts = [
            ' res 1 ', ' links ', ' res 2 ', ' links ', ' res 3 ', ' links ',
            ' res 4 ', ' links ', ' res 5 '
        ]
        commands = [
            lambda: self.selectRelativeResidue(1, True),
            lambda: self.selectLink(1, True),
            lambda: self.selectRelativeResidue(2, True),
            lambda: self.selectLink(2, True),
            lambda: self.selectRelativeResidue(3, True),
            lambda: self.selectLink(3, True),
            lambda: self.selectRelativeResidue(4, True),
            lambda: self.selectLink(4, True),
            lambda: self.selectRelativeResidue(5, True)
        ]
        self.sequenceButtons = ButtonList(resultsFirstFrame,
                                          commands=commands,
                                          texts=texts)
        self.sequenceButtons.grid(row=0, column=0, sticky='nsew')

        for n, button in enumerate(self.sequenceButtons.buttons):

            if n % 2:

                button.grid(column=n, sticky='ns')

                self.sequenceButtons.grid_columnconfigure(n, weight=0)

            else:

                self.sequenceButtons.grid_columnconfigure(n, uniform=2)

        spacer = Spacer(resultsFirstFrame)
        spacer.grid(row=1, column=0, sticky='nsew')

        texts = [
            ' res 1 ', ' links ', ' res 2 ', ' links ', ' res 3 ', ' links ',
            ' res 4 ', ' links ', ' res 5 '
        ]
        commands = commands = [
            lambda: self.selectRelativeResidue(1, False),
            lambda: self.selectLink(1, False),
            lambda: self.selectRelativeResidue(2, False),
            lambda: self.selectLink(2, False),
            lambda: self.selectRelativeResidue(3, False),
            lambda: self.selectLink(3, False),
            lambda: self.selectRelativeResidue(4, False),
            lambda: self.selectLink(4, False),
            lambda: self.selectRelativeResidue(5, False)
        ]
        self.sequenceButtonsB = ButtonList(resultsFirstFrame,
                                           commands=commands,
                                           texts=texts)
        self.sequenceButtonsB.grid(row=2, column=0, sticky='nsew')

        for n, button in enumerate(self.sequenceButtonsB.buttons):

            if n % 2:

                button.grid(column=n, sticky='ns')

                self.sequenceButtonsB.grid_columnconfigure(n, weight=0)

            else:

                self.sequenceButtonsB.grid_columnconfigure(n, uniform=2)

        frame.grid_rowconfigure(3, weight=2)

        resultsThirdFrame = Frame(frame)
        resultsThirdFrame.grid(row=3, column=0, sticky='nsew')

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

        tabbedFrameB = TabbedFrame(resultsThirdFrame,
                                   options=['Peaks', 'Spin System'],
                                   callback=self.toggleTab,
                                   grid=(0, 0))
        #self.tabbedFrameB = tabbedFrame

        PeakFrame, SpinSystemFrame = tabbedFrameB.frames

        SpinSystemFrame.grid_rowconfigure(0, weight=1)
        PeakFrame.grid_rowconfigure(1, weight=1)

        SpinSystemFrame.grid_columnconfigure(0, weight=1)
        PeakFrame.grid_columnconfigure(0, weight=1)

        headingList = [
            'residue', 'assigned to in project', 'user defined sequence',
            'selected annealing result', '%'
        ]

        tipTexts = [None, None, None, None, None]

        editWidgets = [None, None, None, None, None]

        editGetCallbacks = [None, None, None, None, None]

        editSetCallbacks = [None, None, None, None, None]

        self.spinSysTable = ScrolledMatrix(SpinSystemFrame,
                                           headingList=headingList,
                                           editWidgets=editWidgets,
                                           multiSelect=False,
                                           editGetCallbacks=editGetCallbacks,
                                           editSetCallbacks=editSetCallbacks,
                                           tipTexts=tipTexts)
        self.spinSysTable.grid(row=0, column=0, sticky='nsew')

        buttonFrameinPeakFrame = Frame(PeakFrame)
        buttonFrameinPeakFrame.grid(sticky='ew')

        self.findButton = Button(
            buttonFrameinPeakFrame,
            text=' Go to Peak ',
            borderwidth=1,
            padx=2,
            pady=1,
            command=self.findPeak,
            tipText='Locate the currently selected peak in the specified window'
        )

        self.findButton.grid(row=0, column=0, sticky='e')

        label = Label(buttonFrameinPeakFrame, text='in window:')

        label.grid(row=0, column=1, sticky='w')

        self.windowPulldown = PulldownList(
            buttonFrameinPeakFrame,
            callback=self.selectWindowPane,
            tipText='Choose the spectrum window for locating peaks or strips')

        self.windowPulldown.grid(row=0, column=2, sticky='w')

        self.assignSelectedPeaksButton = Button(
            buttonFrameinPeakFrame,
            text='Assign Resonances to Peak(s)',
            borderwidth=1,
            padx=2,
            pady=1,
            command=self.assignSelectedPeaks,
            tipText=
            'Assign resonances to peak dimensions, this of course only works when the peak is found in the spectrum.'
        )

        self.assignSelectedPeaksButton.grid(row=0, column=3, sticky='ew')

        self.assignSelectedSpinSystemsToResiduesButton = Button(
            buttonFrameinPeakFrame,
            text='Assign Spinsystems to Residues',
            borderwidth=1,
            padx=2,
            pady=1,
            command=self.assignSelectedSpinSystemsToResidues,
            tipText='Assign spinsystems to residues')

        self.assignSelectedSpinSystemsToResiduesButton.grid(row=0,
                                                            column=4,
                                                            sticky='ew')

        headingList = [
            '#', 'spectrum', 'Dim1', 'Dim2', 'Dim3', 'c.s. dim1', 'c.s. dim2',
            'c.s. dim3', 'colabelling'
        ]

        tipTexts = [
            'Peak number, only present when the peak was actually found in the spectrum.',
            'Name of the spectrum',
            'Name of atomSet measured in this dimension. Dimension number corresponds to Ref Exp Dim as indicated by going in the main menu to Experiment-->Experiments-->Experiment Type',
            'Name of atomSet measured in this dimension. Dimension number corresponds to Ref Exp Dim as indicated by going in the main menu to Experiment-->Experiments-->Experiment Type',
            'Name of atomSet measured in this dimension. Dimension number corresponds to Ref Exp Dim as indicated by going in the main menu to Experiment-->Experiments-->Experiment Type',
            'Chemical Shift', 'Chemical Shift', 'Chemical Shift',
            'Colabbeling fraction over all nuclei that are on the magnetization transfer pathway during the experiment that gave rise to the peak, including visited nuclei that were not measured in any of the peak dimensions'
        ]

        #editWidgets = [None, None, None, None, None, None, None, None, None]

        editGetCallbacks = [
            None, None, None, None, None, None, None, None, None
        ]

        #editGetCallbacks = [self.selectPeak, self.selectPeak, self.selectPeak, self.selectPeak, self.selectPeak, self.selectPeak, self.selectPeak, self.selectPeak, self.selectPeak]

        editSetCallbacks = [
            None, None, None, None, None, None, None, None, None
        ]

        self.displayPeakTable = ScrolledMatrix(PeakFrame,
                                               headingList=headingList,
                                               multiSelect=True,
                                               tipTexts=tipTexts)
        #editWidgets=editWidgets, multiSelect=True,
        # editGetCallbacks=editGetCallbacks,
        # editSetCallbacks=editSetCallbacks,
        # tipTexts=tipTexts)
        self.displayPeakTable.grid(row=1, column=0, sticky='nsew')

        self.windowPane = None
        self.updateWindows()

    def selectSpinSystemForTable(self, spinSystem, row, column, table):

        table_number = self.displayResultsTables.index(table)
        self.selectSpinSystem(table_number, spinSystem)

    @lockUntillResults
    def showResults(self):

        self.updateResultsTable()

    @lockUntillResults
    def selectLink(self, number, topRow):

        if topRow:

            self.selectedResidueA = None
            self.selectedResidueB = None
            self.selectedLinkA = number
            self.selectedLinkB = None

        else:

            self.selectedResidueA = None
            self.selectedResidueB = None
            self.selectedLinkA = None
            self.selectedLinkB = number

        self.updateButtons()
        self.updateLink()

    @lockUntillResults
    def selectRelativeResidue(self, number, topRow):

        if topRow:

            self.selectedResidueA = number
            self.selectedResidueB = None
            self.selectedLinkA = None
            self.selectedLinkB = None

        else:

            self.selectedResidueA = None
            self.selectedResidueB = number
            self.selectedLinkA = None
            self.selectedLinkB = None

        self.updateButtons()
        self.updateLink()

    def updateLink(self):
        '''
        Checks for any selected link (self.selectedLinkA or self.selectedLinkB) and calls
        updatePeakTable with the correct residue Object and spinsystem Objects.
        '''

        number = self.selectedLinkA or self.selectedLinkB or self.selectedResidueA or self.selectedResidueB

        if not number:

            self.emptyPeakTable()
            return

        dataModel = self.dataModel
        resNumber = self.resultsResidueNumber
        chain = dataModel.chain
        residues = chain.residues
        solutionNumber = self.selectedSolution - 1

        if self.selectedResidueA:

            res = residues[resNumber - 4 + number]
            spinSystem = res.solutions[solutionNumber]

            self.selectedLink = None
            if res and spinSystem:
                self.selectedLink = res.getIntraLink(spinSystem)

            #self.updatePeakTableIntra(res, spinSystem)
            self.updateSpinSystemTable(spinSystem)

        elif self.selectedResidueB:

            res = residues[resNumber - 4 + number]
            spinSystem = res.userDefinedSolution

            self.selectedLink = None
            if res and spinSystem:
                self.selectedLink = res.getIntraLink(spinSystem)

            #self.updatePeakTableIntra(res, spinSystem)
            self.updateSpinSystemTable(spinSystem)

        elif self.selectedLinkA:

            resA = residues[resNumber - 4 + number]
            resB = residues[resNumber - 3 + number]

            spinSystemA = resA.solutions[solutionNumber]
            spinSystemB = resB.solutions[solutionNumber]

            self.selectedLink = None
            if resA and spinSystemA and spinSystemB:
                self.selectedLink = resA.getLink(spinSystemA, spinSystemB)

            #self.updatePeakTable(resA, spinSystemA, spinSystemB)

        # and resA.userDefinedSolution and resB.userDefinedSolution:
        elif self.selectedLinkB:

            resA = residues[resNumber - 4 + number]
            resB = residues[resNumber - 3 + number]

            spinSystemA = resA.userDefinedSolution
            spinSystemB = resB.userDefinedSolution

            self.selectedLink = None
            if resA and spinSystemA and spinSystemB:
                self.selectedLink = resA.getLink(spinSystemA, spinSystemB)

            #self.updatePeakTable(resA, spinSystemA, spinSystemB)

        self.updatePeakTable()

    def emptyPeakTable(self):

        self.displayPeakTable.update(objectList=[],
                                     textMatrix=[],
                                     colorMatrix=[])

    def updatePeakTable(self):
        '''
        Updates the peak table to show the peaks that are found for a sequencial pair of
        spinsystems A and B. If there is not a linkobject found for spinsystems A and B the
        table is emptied. Also sets the selected peak to None.
        '''

        link = self.selectedLink

        if not link:
            self.emptyPeakTable()

        else:

            resA, resB = link.getResidues()
            spinSystemA, spinSystemB = link.getSpinSystems()
            data = []
            objectList = []
            peakLinks = link.getAllPeakLinks()

            if not peakLinks:
                self.emptyPeakTable()
                return

            maxDimenionality = max([
                len(peakLink.getSimulatedPeak().getContribs())
                for peakLink in peakLinks
            ])

            for peakLink in peakLinks:

                serial = None
                realPeak = peakLink.getPeak()
                simPeak = peakLink.getSimulatedPeak()
                atomTexts = [None] * maxDimenionality
                chemicalShifts = [None] * maxDimenionality

                for simulatedPeakContrib in simPeak.getContribs():

                    atomName = simulatedPeakContrib.getAtomName()

                    #ccpCode = simulatedPeakContrib.getCcpCode()

                    dimNumber = simulatedPeakContrib.getDimNumber()

                    if resA is simulatedPeakContrib.getResidue():

                        spinSystemDescription = spinSystemA.getDescription(
                            noSerialWhenSeqCodeIsPresent=True)

                    else:

                        spinSystemDescription = spinSystemB.getDescription(
                            noSerialWhenSeqCodeIsPresent=True)

                    atomTexts[dimNumber -
                              1] = '%s %s' % (spinSystemDescription, atomName)

                if realPeak:

                    serial = realPeak.getSerial()
                    for dim in realPeak.getDimensions():
                        chemicalShifts[dim.getDimNumber() -
                                       1] = dim.getChemicalShift()

                else:
                    shiftListSerial = simPeak.getSpectrum().getShiftListSerial(
                    )
                    for resonance, simulatedPeakContrib in zip(
                            peakLink.getResonances(), simPeak.getContribs()):

                        if resonance:

                            chemicalShifts[simulatedPeakContrib.getDimNumber()
                                           - 1] = resonance.getChemicalShift(
                                               shiftListSerial)

                        else:

                            chemicalShifts[simulatedPeakContrib.getDimNumber()
                                           - 1] = '?'

                data.append([serial, simPeak.getSpectrum().name] + atomTexts +
                            chemicalShifts + [simPeak.colabelling])
                objectList.append(peakLink)
            headingList = ['#', 'spectrum'] + [
                'dim%s' % a for a in range(1, maxDimenionality + 1)
            ] + ['c.s. dim%s' % a
                 for a in range(1, maxDimenionality + 1)] + ['colabbeling']
            self.displayPeakTable.update(objectList=objectList,
                                         textMatrix=data,
                                         headingList=headingList)

    def findPeak(self):

        if not self.windowPane:

            return

        selectedPeakLinks = self.displayPeakTable.currentObjects

        if not selectedPeakLinks:

            self.guiParent.updateInfoText('Please select a peak first.')
            return

        if len(selectedPeakLinks) > 1:

            self.guiParent.updateInfoText('Can only go to one peak at a time.')
            return

        selectedPeakLink = selectedPeakLinks[0]
        selectedPeak = selectedPeakLink.getPeak()

        if selectedPeak:

            ccpnPeak = selectedPeak.getCcpnPeak()
            createPeakMark(ccpnPeak, lineWidth=2.0)

            windowFrame = self.windowPane.getWindowFrame()
            windowFrame.gotoPeak(ccpnPeak)

        else:

            simPeak = selectedPeakLink.getSimulatedPeak()
            spectrum = simPeak.getSpectrum()
            ccpnSpectrum = spectrum.getCcpnSpectrum()
            view = getSpectrumWindowView(self.windowPane, ccpnSpectrum)

            if not view:

                self.guiParent.updateInfoText(
                    'This peak cannot be displayed in the window you chose.')

            axisMappingByRefExpDimNumber = {}

            for axisMapping in view.axisMappings:

                refExpDimNumber = axisMapping.analysisDataDim.dataDim.expDim.refExpDim.dim

                axisMappingByRefExpDimNumber[refExpDimNumber] = axisMapping

            positionToGoTo = {}
            markPosition = []
            axisTypes = []

            for resonance, contrib in zip(selectedPeakLink.getResonances(),
                                          simPeak.getContribs()):

                dimNumber = contrib.getDimNumber()

                axisMapping = axisMappingByRefExpDimNumber.get(dimNumber)

                label = axisMapping.label

                if resonance:

                    axisType = axisMapping.axisPanel.axisType
                    chemicalShift = resonance.getChemicalShift()

                    positionToGoTo[label] = chemicalShift
                    markPosition.append(chemicalShift)
                    axisTypes.append(axisType)

                # Not drawing a mark at this chemical shift, just hoovering to
                # the good region in the spectrum
                else:

                    ccpCode = contrib.getResidue().getCcpCode()
                    atomName = contrib.getAtomName()

                    medianChemicalShift = self.getMedianChemicalShift(
                        ccpCode, atomName)

                    if medianChemicalShift:

                        positionToGoTo[label] = medianChemicalShift

            if positionToGoTo:

                windowFrame = self.windowPane.getWindowFrame()
                windowFrame.gotoPosition(positionToGoTo)

            if markPosition:

                createNonPeakMark(markPosition, axisTypes)

    def assignSelectedPeaks(self):

        selectedPeakLinks = self.displayPeakTable.currentObjects

        for pl in selectedPeakLinks:

            peak = pl.getPeak()

            if peak:

                for resonance, dimension in zip(pl.getResonances(),
                                                peak.getDimensions()):

                    ccpnResonance = resonance.getCcpnResonance()
                    ccpnDimension = dimension.getCcpnDimension()

                    if ccpnResonance and ccpnDimension:

                        assignResToDim(ccpnDimension, ccpnResonance)

    def assignSelectedSpinSystemsToResidues(self):

        link = self.selectedLink

        if link:

            residues = link.getResidues()
            spinSystems = link.getSpinSystems()

            ccpnSpinSystems = []
            ccpnResidues = []

            for spinSys, res in zip(spinSystems, residues):

                if spinSys and res:

                    ccpnSpinSystems.append(spinSys.getCcpnResonanceGroup())
                    ccpnResidues.append(res.getCcpnResidue())

            assignSpinSystemstoResidues(ccpnSpinSystems,
                                        ccpnResidues,
                                        guiParent=self.guiParent)

            self.updateButtons()
            self.updateButtons()
            self.updateResultsTable()
            self.updatePeakTable()

    def getMedianChemicalShift(self, ccpCode, atomName):

        nmrRefStore = self.project.findFirstNmrReferenceStore(
            molType='protein', ccpCode=ccpCode)

        chemCompNmrRef = nmrRefStore.findFirstChemCompNmrRef(
            sourceName='RefDB')

        chemCompVarNmrRef = chemCompNmrRef.findFirstChemCompVarNmrRef(
            linking='any', descriptor='any')

        if chemCompVarNmrRef:

            chemAtomNmrRef = chemCompVarNmrRef.findFirstChemAtomNmrRef(
                name=atomName)

            if chemAtomNmrRef:

                distribution = chemAtomNmrRef.distribution

                maxIndex = max([
                    (value, index) for index, value in enumerate(distribution)
                ])[1]

                return chemAtomNmrRef.refValue + chemAtomNmrRef.valuePerPoint * (
                    maxIndex - chemAtomNmrRef.refPoint)

        return None

    def selectWindowPane(self, windowPane):

        if windowPane is not self.windowPane:
            self.windowPane = windowPane

    def updateWindows(self):

        index = 0
        windowPane = None
        windowPanes = []
        names = []
        peakList = None
        tryWindows = WindowBasic.getActiveWindows(self.project)

        windowData = []
        getName = WindowBasic.getWindowPaneName

        for window in tryWindows:
            for windowPane0 in window.spectrumWindowPanes:
                # if WindowBasic.isSpectrumInWindowPane(windowPane0, spectrum):
                windowData.append((getName(windowPane0), windowPane0))

            windowData.sort()
            names = [x[0] for x in windowData]
            windowPanes = [x[1] for x in windowData]

        if windowPanes:
            if windowPane not in windowPanes:
                windowPane = windowPanes[0]

            index = windowPanes.index(windowPane)

        else:
            windowPane = None

        self.selectWindowPane(windowPane)

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

    def selectSpinSystem(self, number, spinSystem):

        res = self.dataModel.chain.residues[self.resultsResidueNumber - 3 +
                                            number]

        oldSpinSystemForResidue = res.userDefinedSolution

        if oldSpinSystemForResidue and res.getSeqCode(
        ) in oldSpinSystemForResidue.userDefinedSolutions:

            oldSpinSystemForResidue.userDefinedSolutions.remove(
                res.getSeqCode())

        res.userDefinedSolution = spinSystem

        spinSystem.userDefinedSolutions.append(res.getSeqCode())

        # self.updateSpinSystemTable(spinSystem)
        self.updateLink()
        self.updateButtons()

    def updateSpinSystemTable(self, spinSystem):

        if not spinSystem:

            self.emptySpinSystemTable()
            return

        dataModel = self.dataModel

        residues = dataModel.chain.residues

        data = []
        colorMatrix = []

        for residue in spinSystem.allowedResidues:

            oneRow = []
            oneRowColor = []
            string = str(residue.getSeqCode()) + ' ' + residue.getCcpCode()

            oneRow.append(string)

            resonanceGroup = spinSystem.getCcpnResonanceGroup()
            ccpnResidue = residue.ccpnResidue

            # Assigned in the project to this residue
            if resonanceGroup and resonanceGroup.residue and resonanceGroup.residue is ccpnResidue:
                oneRow.append('x')
            else:
                oneRow.append(None)

            # The user selected this res for this spinsystem (could be more
            # than one res for which this happens)
            if residue.getSeqCode() in spinSystem.userDefinedSolutions:
                oneRow.append('x')
            else:
                oneRow.append(None)

            if residue.solutions[self.selectedSolution - 1] == spinSystem:
                oneRow.append('x')
            else:
                oneRow.append(None)

            if spinSystem.solutions:

                percentage = spinSystem.solutions.count(
                    residue.getSeqCode()) / float(len(
                        spinSystem.solutions)) * 100.0

            else:

                percentage = 0

            oneRow.append(int(percentage + 0.5))
            color = pick_color_by_percentage(percentage)
            oneRowColor = [color] * 5

            data.append(oneRow)
            colorMatrix.append(oneRowColor)

        self.spinSysTable.update(objectList=data,
                                 textMatrix=data,
                                 colorMatrix=colorMatrix)

        self.spinSysTable.sortDown = False
        self.spinSysTable.sortLine(-1, noUpdate=True)

    def emptySpinSystemTable(self):

        self.spinSysTable.update(objectList=[], textMatrix=[], colorMatrix=[])

    @lockUntillResults
    def adoptSolution(self):

        dataModel = self.dataModel
        selectedSolution = self.selectedSolution

        for res in dataModel.chain.residues:

            spinSystem = res.solutions[selectedSolution - 1]
            res.userDefinedSolution = spinSystem
            spinSystem.userDefinedSolutions = [res.getSeqCode()]

        self.updateLink()
        self.updateButtons()

    @lockUntillResults
    def resultsPrevSolution(self):

        if self.selectedSolution != 1:
            self.selectedSolution = self.selectedSolution - 1
            self.resultsSolutionNumberEntry.set(self.selectedSolution)

            self.updateLink()
            self.updateButtons()
            self.updateEnergy()

    @lockUntillResults
    def resultsNextSolution(self):

        amountOfRepeats = len(self.dataModel.chain.residues[0].solutions)

        if self.selectedSolution < amountOfRepeats:
            self.selectedSolution = self.selectedSolution + 1
            self.resultsSolutionNumberEntry.set(self.selectedSolution)

            self.updateLink()
            self.updateButtons()
            self.updateEnergy()

    @lockUntillResults
    def resultsPrevResidue(self):

        residues = self.dataModel.chain.residues
        #chainLength = len(residues)

        new_value = self.resultsResidueNumber
        if self.resultsSelectedCcpCode == 'residue':
            if self.resultsResidueNumber != 3:
                new_value = self.resultsResidueNumber - 1
        else:
            for res in residues:
                if res.getSeqCode() == self.resultsResidueNumber:
                    break
                elif res.getCcpCode() == self.resultsSelectedCcpCode:
                    new_value = res.getSeqCode()
                    if new_value < 3:
                        new_value = 3
        if self.resultsResidueNumber != new_value:
            self.resultsResidueNumber = new_value

            self.resultsResidueNumberEntry.set(self.resultsResidueNumber)

            self.updateLink()
            self.updateButtons()
            self.updateButtons()
            self.updateResultsTable()
            self.updateResidueLabels()

    @lockUntillResults
    def resultsNextResidue(self):

        residues = self.dataModel.chain.residues
        chainLength = len(residues)

        new_value = self.resultsResidueNumber
        if self.resultsSelectedCcpCode == 'residue':
            if self.resultsResidueNumber != chainLength - 2:
                new_value = self.resultsResidueNumber + 1
        else:
            for res in residues[(self.resultsResidueNumber):]:
                if res.getCcpCode() == self.resultsSelectedCcpCode:
                    new_value = res.getSeqCode()
                    if new_value > chainLength - 2:
                        new_value = chainLength - 2
                    break
        if self.resultsResidueNumber != new_value:
            self.resultsResidueNumber = new_value
            self.resultsResidueNumberEntry.set(self.resultsResidueNumber)

            self.updateLink()
            self.updateButtons()
            self.updateButtons()
            self.updateResultsTable()
            self.updateResidueLabels()

    def resultsChangeSelectedCcpCode(self, ccpCode):

        self.resultsSelectedCcpCode = ccpCode

    @lockUntillResults
    def resultsUpdateAfterEntry(self, event=None):
        '''
        Update for entry of residue number in strip plots
        '''

        residues = self.dataModel.chain.residues

        value = self.resultsResidueNumberEntry.get()
        if value == self.resultsResidueNumber:
            return
        else:
            self.resultsResidueNumber = value
        if value < 3:
            self.resultsResidueNumberEntry.set(3)
            self.resultsResidueNumber = 3

        elif value > len(residues) - 2:
            self.resultsResidueNumber = len(residues) - 2
            self.resultsResidueNumberEntry.set(self.resultsResidueNumber)

        else:
            self.resultsResidueNumberEntry.set(self.resultsResidueNumber)

        self.updateLink()
        self.updateButtons()
        self.updateButtons()
        self.updateResultsTable()
        self.updateResidueLabels()

    @lockUntillResults
    def solutionUpdateAfterEntry(self, event=None):
        '''
        Update for entry of residue number in strip plots
        '''

        Nsolutions = len(self.dataModel.chain.residues[0].solutions)

        value = self.resultsSolutionNumberEntry.get()
        if value == self.selectedSolution:
            return
        else:
            self.selectedSolution = value
        if value < 1:
            self.resultsSolutionNumberEntry.set(1)
            self.selectedSolution = 1
        elif value > Nsolutions:
            self.selectedSolution = Nsolutions
            self.resultsSolutionNumberEntry.set(self.selectedSolution)
        else:
            self.resultsSolutionNumberEntry.set(self.selectedSolution)

        self.updateLink()
        self.updateButtons()

    def update(self):

        self.updateLink()
        self.updateResidueLabels()
        self.updateResultsTable()
        self.updateButtons()
        self.updateButtons()
        self.updateEnergy()

    def updateResultsTable(self):

        resNumber = self.resultsResidueNumber

        dataModel = self.dataModel

        chain = dataModel.chain

        residues = chain.residues

        resA = residues[resNumber - 3]
        resB = residues[resNumber - 2]
        resC = residues[resNumber - 1]
        resD = residues[resNumber]
        resE = residues[resNumber + 1]

        resList = [resA, resB, resC, resD, resE]
        tableList = self.displayResultsTables

        for res, table in zip(resList, tableList):

            ccpCode = res.ccpCode

            spinSystemsWithThisCcpCode = dataModel.getSpinSystems()[ccpCode]

            data = []
            colorMatrix = []
            objectList = []

            jokers = []
            realSpinSystems = []

            for spinSys in spinSystemsWithThisCcpCode:

                if spinSys.getIsJoker():

                    jokers.append(spinSys)

                else:

                    realSpinSystems.append(spinSys)

            for spinsys in realSpinSystems:

                oneRow = []
                oneRowColor = []

                # self.getStringDescriptionOfSpinSystem(spinsys)
                spinSystemInfo = spinsys.getDescription()

                oneRow.append(spinSystemInfo)

                assignmentPercentage = int(
                    float(res.solutions.count(spinsys)) / len(res.solutions) *
                    100.0)

                oneRow.append(assignmentPercentage)

                objectList.append(spinsys)

                color = pick_color_by_percentage(assignmentPercentage)

                oneRowColor = [color, color]

                data.append(oneRow)
                colorMatrix.append(oneRowColor)

            if jokers:

                oneRow = ['Joker']

                NumberOfAssignmentsToJoker = 0

                for spinSys in jokers:

                    NumberOfAssignmentsToJoker += res.solutions.count(spinSys)

                assignmentPercentage = int(
                    float(NumberOfAssignmentsToJoker) / len(res.solutions) *
                    100.0)

                oneRow.append(assignmentPercentage)

                color = pick_color_by_percentage(assignmentPercentage)

                oneRowColor = [color, color]

                data.append(oneRow)
                colorMatrix.append(oneRowColor)
                objectList.append(jokers[0])

            percentages = [datapoint[1] for datapoint in data]

            tableData = sorted(zip(percentages, data, objectList, colorMatrix),
                               reverse=True)

            percentage, data, objectList, colorMatrix = zip(*tableData)

            table.update(objectList=objectList,
                         textMatrix=data,
                         colorMatrix=colorMatrix)

    def updateResidueLabels(self):

        resList = self.getCurrentlyDisplayedResidues()
        labels = self.residueLabels

        for residue, label in zip(resList, labels):

            text = str(residue.getSeqCode()) + ' ' + residue.getCcpCode()

            label.set(text)

    def updateButtons(self):

        self.updateButtonHighLights()
        self.updateResultsTopRowButtons()
        self.updateResultsBottomRowButtons()

    def updateResultsTopRowButtons(self):

        resList = self.getCurrentlyDisplayedResidues()

        buttons = self.sequenceButtons.buttons[::2]

        for button, res in zip(buttons, resList):

            spinsys = res.solutions[self.selectedSolution - 1]

            # str(res.getSeqCode()) + ' ' + res.getCcpCode() + ': ' +
            # spinsys.getDescription()
            # self.getStringDescriptionOfSpinSystem(spinsys)
            text = spinsys.getDescription(noSerialWhenSeqCodeIsPresent=False)

            button.config(text=text)

    def updateResultsBottomRowButtons(self):

        resList = self.getCurrentlyDisplayedResidues()

        buttons = self.sequenceButtonsB.buttons[::2]

        for button, res in zip(buttons, resList):

            if res.userDefinedSolution:

                selectedSpinSystem = res.userDefinedSolution
                text = selectedSpinSystem.getDescription(
                    noSerialWhenSeqCodeIsPresent=False)

                if len(selectedSpinSystem.userDefinedSolutions) > 1:

                    # The red color signals that the spinssystem is used in
                    # more than 1 place in the sequence
                    button.config(text=text, bg=highLightRed)

                else:

                    button.config(text=text)

            else:

                # str(res.getSeqCode()) + ' ' + res.getCcpCode() + ': -'
                text = '-'

                button.config(text=text)

    def updateButtonHighLights(self):

        self.setAllButtonsToGrey()

        if self.selectedResidueA:

            buttons = [
                self.sequenceButtons.buttons[0],
                self.sequenceButtons.buttons[2],
                self.sequenceButtons.buttons[4],
                self.sequenceButtons.buttons[6],
                self.sequenceButtons.buttons[8]
            ]
            buttons[self.selectedResidueA - 1].config(bg=highLightYellow)

        elif self.selectedResidueB:

            buttons = [
                self.sequenceButtonsB.buttons[0],
                self.sequenceButtonsB.buttons[2],
                self.sequenceButtonsB.buttons[4],
                self.sequenceButtonsB.buttons[6],
                self.sequenceButtonsB.buttons[8]
            ]
            buttons[self.selectedResidueB - 1].config(bg=highLightYellow)

        elif self.selectedLinkA:

            buttons = [
                self.sequenceButtons.buttons[1],
                self.sequenceButtons.buttons[3],
                self.sequenceButtons.buttons[5],
                self.sequenceButtons.buttons[7]
            ]
            buttons[self.selectedLinkA - 1].config(bg=highLightYellow)

        elif self.selectedLinkB:

            buttons = [
                self.sequenceButtonsB.buttons[1],
                self.sequenceButtonsB.buttons[3],
                self.sequenceButtonsB.buttons[5],
                self.sequenceButtonsB.buttons[7]
            ]
            buttons[self.selectedLinkB - 1].config(bg=highLightYellow)

    def updateEnergy(self):

        text = 'energy: %s' % int(
            self.dataModel.getEnergy(self.selectedSolution - 1) + 0.5)
        self.energyLabel.set(text)
        self.energyLabel.update()

    def setAllButtonsToGrey(self):

        for button in self.sequenceButtons.buttons + self.sequenceButtonsB.buttons:

            button.config(bg='grey83')

    def setAllRedButtonsToGrey(self):

        for button in self.sequenceButtons.buttons + self.sequenceButtonsB.buttons:

            if button.enableFg == highLightRed:

                button.config(bg='grey83')

    def getCurrentlyDisplayedResidues(self):

        resNumber = self.resultsResidueNumber

        residues = self.dataModel.chain.residues[resNumber - 3:resNumber + 2]

        return residues

    def toggleTab(self, index):

        pass
示例#2
0
class SequenceShiftPredictPopup(BasePopup):
    """
  **Predict Protein Shifts from Sequence**
  
  This popup window is designed to allow the prediction of chemical shifts
  for a protein chain from the sequence (so with no structural information),
  using the (external) program CamCoil.

  The Options to select are the Chain for which the prediction is made, and
  the prediction type and the pH used for the prediction, and also the Shift
  List, which is not used for the prediction but is used for the comparison
  with the prediction.

  CamCoil has two variations, one for the prediction of random coil chemical
  shifts and one for prediction of protein loops chemical shifts.

  The Chemical Shift Predictions table lists the atoms in the chain.
  For each atom the data listed is the residue number, residue type, atom
  name, first shift found for that atom in the chosen shiftList, chemical
  shift predicted by CamCoil, and the difference between the actual shift
  and the predicted shift (if both exist).
  
  To run the prediction click on the "Run CamCoil Prediction!" button.  This
  does not store any predicted shifts in the project.

  **Caveats & Tips**

  **References**

  The CamCoil programme:

  http://www-vendruscolo.ch.cam.ac.uk/camcoil.php

  *A. De Simone, A. Cavalli, S-T. D. Hsu, W. Vranken and M. Vendruscolo
  Accurate random coil chemical shifts from an analysis of loop regions in native states of proteins.
  J. Am. Chem. Soc. 131(45):16332-3
  """
    def __init__(self, parent, *args, **kw):

        self.chain = None
        self.shiftList = None
        self.predictionDict = {}

        BasePopup.__init__(
            self,
            parent=parent,
            title='Data Analysis : Predict Shifts from Sequence')

    def body(self, guiFrame):

        self.geometry('700x500')

        guiFrame.expandGrid(1, 0)

        row = 0

        # TOP LEFT FRAME

        frame = LabelFrame(guiFrame, text='Options')
        frame.grid(row=row, column=0, sticky='nsew')
        frame.columnconfigure(7, weight=1)

        label = Label(frame, text='Chain')
        label.grid(row=0, column=0, sticky='w')
        self.chainPulldown = PulldownList(
            frame,
            callback=self.changeChain,
            tipText='Choose the molecular system chain to make predictions for'
        )
        self.chainPulldown.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='Shift List')
        label.grid(row=0, column=2, sticky='w')
        self.shiftListPulldown = PulldownList(
            frame,
            callback=self.changeShiftList,
            tipText='Select the shift list to take input chemical shifts from')
        self.shiftListPulldown.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='Type')
        label.grid(row=0, column=4, sticky='w')
        self.scriptPulldown = PulldownList(
            frame,
            texts=SCRIPT_TEXTS,
            callback=self.changeScript,
            tipText='Select the algorithm script for this chain')
        self.scriptPulldown.grid(row=0, column=5, sticky='w')

        self.pHLabel = Label(frame, text='pH')
        self.pHLabel.grid(row=0, column=6, sticky='w')
        self.pHPulldown = PulldownList(
            frame,
            texts=SCRIPT_PHS,
            tipText='Select the pH to make the prediction for')
        self.pHPulldown.grid(row=0, column=7, sticky='w')

        row += 1

        # BOTTOM LEFT FRAME

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

        tipTexts = [
            'Residue number in chain', 'Residue type code', 'Atom name',
            'Actual shift (first one it finds for atom in chosen shiftList)',
            'CamCoil predicted shift', 'Predicted - Actual'
        ]

        headingList = [
            'Res\nNum', 'Res\nType', 'Atom\nName', 'Actual\nShift',
            'Predicted\nShift', 'Difference'
        ]

        n = len(headingList)
        editWidgets = n * [None]
        editGetCallbacks = n * [None]
        editSetCallbacks = n * [None]

        self.predictionMatrix = ScrolledMatrix(
            frame,
            headingList=headingList,
            tipTexts=tipTexts,
            editWidgets=editWidgets,
            editGetCallbacks=editGetCallbacks,
            editSetCallbacks=editSetCallbacks)
        self.predictionMatrix.grid(row=0, column=0, sticky='nsew')

        row += 1

        tipTexts = [
            'Run the CamCoil method to predict chemical shifts from sequence'
        ]

        texts = ['Run CamCoil Prediction!']
        commands = [self.runCamCoil]
        self.buttonList = createDismissHelpButtonList(guiFrame,
                                                      texts=texts,
                                                      commands=commands,
                                                      help_url=self.help_url,
                                                      expands=True,
                                                      tipTexts=tipTexts)
        self.buttonList.grid(row=row, column=0)

        self.update()

        self.notify(self.registerNotify)

    def destroy(self):

        self.notify(self.unregisterNotify)
        BasePopup.destroy(self)

    def notify(self, notifyfunc):

        for func in ('__init__', 'delete'):
            notifyfunc(self.updateChainPulldown,
                       'ccp.molecule.MolSystem.Chain', func)

        for func in ('setValue', ):
            notifyfunc(self.updatePredictionMatrixAfter, 'ccp.nmr.Nmr.Shift',
                       func)

    def update(self):

        self.updateShiftListPulldown()
        self.updateChainPulldown()
        self.updatePredictionMatrixAfter()

    def runCamCoil(self):

        chain = self.chain
        script = self.scriptPulldown.getText()
        if script == LFP_SCRIPT:
            pH = ''
        else:
            pH = self.pHPulldown.getText()

        if not chain:
            showError('Cannot Run CamCoil',
                      'Please specify a chain.',
                      parent=self)
            return

        self.predictionDict[chain] = runCamCoil(chain, pH=pH, script=script)

        self.updatePredictionMatrix()

    def updatePredictionMatrixAfter(self, index=None, text=None):

        self.after_idle(self.updatePredictionMatrix)

    def updatePredictionMatrix(self):

        objectList = []
        textMatrix = []

        chain = self.chain
        shiftList = self.shiftList
        if chain:
            atomShiftDict = self.predictionDict.get(chain, {})

            for residue in chain.sortedResidues():
                for atom in residue.sortedAtoms():
                    currShift = shiftList and findFirstAtomShiftInShiftList(
                        atom, shiftList)
                    value = currShift and currShift.value
                    predShift = atomShiftDict.get(atom)
                    if currShift and predShift:
                        delta = predShift - value
                    else:
                        delta = None
                    data = [
                        residue.seqCode, residue.ccpCode, atom.name, value,
                        predShift, delta
                    ]

                    textMatrix.append(data)
                    objectList.append(atom)

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

    def changeChain(self, chain):

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

    def changeShiftList(self, shiftList):

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

    def changeScript(self, script):

        if script == LFP_SCRIPT:
            self.pHLabel.grid_forget()
            self.pHPulldown.grid_forget()
        else:
            self.pHLabel.grid(row=0, column=6, sticky='w')
            self.pHPulldown.grid(row=0, column=7, sticky='w')

    def updateChainPulldown(self, obj=None):

        index = 0
        names = []
        chains = []
        chain = self.chain

        for molSystem in self.project.molSystems:
            msCode = molSystem.code

            for chainA in molSystem.chains:
                residues = chainA.residues

                if not residues:
                    continue

                for residue in residues:
                    # Must have at least one protein residue
                    if residue.molType == 'protein':
                        names.append('%s:%s' % (msCode, chainA.code))
                        chains.append(chainA)
                        break

        if chains:
            if chain not in chains:
                chain = chains[0]

            index = chains.index(chain)

        else:
            chain = None

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

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

    def updateShiftListPulldown(self, obj=None):

        index = 0
        names = []
        shiftLists = getShiftLists(self.nmrProject)

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

            index = shiftLists.index(self.shiftList)
            names = ['%s:%d' % (sl.name, sl.serial) for sl in shiftLists]

        else:
            self.shiftList = None

        self.shiftListPulldown.setup(names, shiftLists, index)
示例#3
0
class RepositoryFrame(Frame):
    def __init__(self, guiParent, basePopup):

        # Base popup required to handle notification of data model changes
        # e.g. new peak lists, so that the GUI can update to the latest
        # state
        self.basePopup = basePopup
        self.guiParent = guiParent

        # should the screen autorefresh
        self.autoRefresh = False

        # add this to shortcuts to ease navigation
        self.basePopup.frameShortcuts['Repository'] = self

        # get a port proxy instance
        # this should probably belong to the repository directly
        # or else should belong in a dictionary in the main gui
        # layer when it can be picked up easily

        # FIXME JMCI
        # need to work out how to get a number of these!

        loc = SharedBeanServiceLocator()
        self.port = loc.getSharedBean()

        self.registerNotify = basePopup.registerNotify
        self.unregisterNotify = basePopup.unregisterNotify

        Frame.__init__(self, guiParent)

        # set up the grid

        self.grid_columnconfigure(0, weight=0, minsize=20)
        self.grid_columnconfigure(1, weight=1, minsize=10)
        self.grid_columnconfigure(2, weight=0, minsize=20)

        self.grid_rowconfigure(0, weight=0, minsize=5)
        self.grid_rowconfigure(1, weight=0, minsize=0)
        self.grid_rowconfigure(2, weight=0, minsize=10)
        self.grid_rowconfigure(3, weight=0, minsize=10)
        self.grid_rowconfigure(4, weight=0, minsize=10)
        self.grid_rowconfigure(5, weight=1, minsize=10)
        self.grid_rowconfigure(6, weight=0, minsize=10)
        self.grid_rowconfigure(7, weight=0, minsize=10)

        # widgets for view when no data

        self.noDataWidgets = []

        self.noRepLabel = Label(self, text='No repository currently selected.')
        self.noDataWidgets.append(self.noRepLabel)

        # widgets for view when current repository set

        self.dataWidgets = []

        self.repTitle = Label(self, text='Repository:', font='Helvetica16')
        self.dataWidgets.append(self.repTitle)

        #self.repLabel = Label(self,text='All Projects in Repository')
        #self.dataWidgets.append(self.repLabel)

        self.repTree = Tree(self, doubleCallback=self.goto_project_tab)
        self.dataWidgets.append(self.repTree)

        sel = 1
        if self.autoRefresh:
            sel = 0
        self.autoRefreshSwitchLabel = Label(self, text='Auto Refresh')
        self.autoRefreshSwitch = RadioButtons(self, ['on', 'off'],
                                              select_callback=self.set_refresh,
                                              selected_index=sel)

        # need to decide whether this is static or not
        r_button_texts = [
            'Add to Basket', '  Import  ', '  Export  ', '  Refresh ',
            'Properties'
        ]
        r_button_cmds = [
            self.tmpCall, self.import_project, self.export_project,
            self.drawFrame, self.goto_project_tab
        ]

        self.rep_button_list = ButtonList(self, r_button_texts, r_button_cmds)
        self.dataWidgets.append(self.rep_button_list)

        self.filterFrame = FilterFrame(self, self.basePopup, text='Filter')
        self.dataWidgets.append(self.filterFrame)

        baskets = ('basket1', 'basket2', 'basket3')
        self.basketSelect = PulldownList(self, self.tmpCall, baskets)
        self.dataWidgets.append(self.basketSelect)

        basketElements = ('1ay3', '1ay7')
        self.basketList = ScrolledListbox(self, basketElements, 25, 18)
        self.dataWidgets.append(self.basketList)

        b_button_texts = ['Remove from Basket', 'New Basket']
        b_button_cmds = [self.tmpCall, self.tmpCall]

        self.b_button_list = ButtonList(self, b_button_texts, b_button_cmds)
        self.dataWidgets.append(self.b_button_list)

        # draw if not automatically refreshing
        if sel == 1:
            self.drawFrame()

        # set up a loop
        self.refresh()

    def drawFrame(self):

        if self.basePopup.repList.currentRepository == None:

            for widget in self.dataWidgets:
                widget.grid_remove()

            self.noRepLabel.grid(row=1, column=1, sticky='n')

        else:

            self.repository = self.basePopup.repList.currentRepository

            for widget in self.noDataWidgets:
                widget.grid_remove()

            # Column headers
            # want to have a general admin panel; current repository, button to change, info
            # about login and so on

            self.repTitle.set('Repository: ' + self.repository.user + '@' +
                              self.repository.name + '  ( ' +
                              self.repository.connect + ' )')

            self.repTitle.grid(row=1, column=1, sticky='w')

            # self.repLabel.grid(row=2, column=1, sticky='w')

            # Repository block

            #grid and update
            self.repTree.grid(row=3, column=1, rowspan=3, sticky='nsew')
            self.updateRepTree()

            self.autoRefreshSwitchLabel.grid(row=6,
                                             column=1,
                                             padx=10,
                                             sticky='w')
            self.autoRefreshSwitch.grid(row=6, column=1, padx=10, sticky='e')

            # the buttons for functionality in repository area
            self.rep_button_list.grid(row=7, column=1, padx=3, sticky='ew')

            # filter frame
            self.filterFrame.grid(row=3, column=2, stick='nsew')

            # list of baskest. Will callback to change current basket
            self.basketSelect.grid(row=4, column=2, padx=10, stick='w')

            # lists projects per basket
            self.basketList.grid(row=5,
                                 rowspan=2,
                                 column=2,
                                 padx=10,
                                 stick='nsew')

            self.b_button_list.grid(row=7, column=2, padx=5, stick='ew')

    def openLink(self, node):

        tree = node.tree
        par = node.object

        # this should be associated with the repository object
        request = getList()

        # FIXME JMCI

        # 1. Potentially need to traverse up the node tree
        # 2. Currently there is bug in expansion/contraction
        # 3. Search needs to work off proxy method (not off
        #    generated stubs

        # pass the parent name for now. may need other criteria later
        h1 = {'name': par.__str__()}
        h2 = {'project': h1}
        wsstr_in = WSString(h2)

        request._arg0 = 'org.pimslims.applet.server.ProjectVersionBean'
        request._arg1 = 'getListWithFields'
        request._arg2 = wsstr_in.str

        # get the response
        response = self.port.getList(request)

        # currently we just get a list of numbers. May want to send
        # all the fields for every object too to cut down on db calls
        wsstr_out = WSString(response._return)
        ss = wsstr_out.getStruct()

        for hm in ss:

            print 'handling ', hm, ', ', hm['status'].__str__()
            #if hm['status'].__str__() == 'AVAILABLE':
            icon = 'text-x-generic'
            #else:
            #  icon='emblem-readonly'
            pv = par.__str__() + '::' + hm['versionTag'].__str__()
            obj = pv
            text = hm['versionTag'].__str__()
            callback = None

            tree.add(node, obj, text, icon, callback)

    def set_refresh(self, text):

        print 'setting refresh ', text

        if text == 'on':
            self.autoRefresh = True
        else:
            self.autoRefresh = False

    def refresh(self):

        if self.autoRefresh:
            print 'refreshing frame ', time.time()
            self.drawFrame()

        self.after(5000, self.refresh)

    # FIME JMCI

    # it would probably be a good idea to have a method that allowed
    # a user to unlock a given project version. Would need to check
    # permissions very carefully, though

    def unlock_project_version(self):

        pass

    def goto_project_tab(self, node=None):

        if node is None:
            # get the selected node
            selected_nodes = self.repTree.getSelectedNodes()
            # restrict the choice to one
            node = selected_nodes[0]

        # we really need to traverse the tree a lot more carefully

        pv = node.object.__str__()
        print 'GOTO PROJECT ', pv, ', ', node, ', ', node.object
        pat = re.compile('::')
        matcher = pat.search(pv, 0)
        name = pv[0:matcher.start()]
        versionTag = pv[matcher.end():]

        print 'GOTO PROJECT ', name, ', ', versionTag

        #versionTag = node.object.__str__()
        #name = node.parent.object.__str__()

        #print node.__dict__
        #print node.parent.__dict__

        self.basePopup.repList.currentRepository.currentProjectName = name
        self.basePopup.repList.currentRepository.currentVersionTag = versionTag

        # this is going to have to be keyed on a natural key that then
        # gets set into the criteria of a ws query

        # hack for now. build in later. Essentially, we have to handle two
        # cases; that of a specific projectVersion request and that of a
        # request on a project alone. Probably the best behaviour would be
        # for the project-only request to default to the latest trunk
        # version of the project and the most elegent way of triggering
        # this would probably be to have this as a property of the project
        # returned in the main hash from Project.getFields().

        self.basePopup.tabbedFrame.select(1)
        if self.basePopup.frameShortcuts.has_key('Project'):
            self.basePopup.frameShortcuts['Project'].drawFrame()

    def import_project(self):

        # FIXME JMCI

        # need to preserve the current status. Take default from the
        # Wms layer
        rootDir = self.basePopup.repList.current_import_dir

        fileSelectPopup = FileSelectPopup(self, None, rootDir)

        new_project_dir = fileSelectPopup.getDirectory()
        self.basePopup.repList.current_import_dir = new_project_dir

        print 'in import project with directory', new_project_dir

        idx = new_project_dir.rfind('/')
        new_project_name = new_project_dir[idx + 1:]

        print 'in import project with project', new_project_name

        # FIXME

        # need to set the project version number somewhere. For now set to none
        # and this gets picked up and set to a default 1.1 later

        self.repository.import_project(new_project_name, None, new_project_dir)

        self.drawFrame()

    def export_project(self):

        # get the selected node
        selected_nodes = self.repTree.getSelectedNodes()

        # restrict the choice to one
        node = selected_nodes[0]

        # we really need to traverse the tree a lot more carefully
        name = node.parent.object.__str__()
        versionTag = node.object.__str__()[len(name) + 2:]

        # need to preserve the current status. Take a default from the
        # Wms layer
        rootDir = self.basePopup.repList.current_export_dir

        # This should be obtained from a query box. Hard code for now
        fileSelectPopup = FileSelectPopup(self, None, rootDir)

        exp_project_dir = fileSelectPopup.getDirectory()
        self.basePopup.repList.current_export_dir = exp_project_dir

        self.repository.export_project(name, versionTag, exp_project_dir)

    def disconnectRepository(self):

        # do we need to formally break a connection and destroy the session?
        # yes we probably should.

        # need an "are you sure" dialog box

        # need to protect

        self.repository.repList.repositories.remove(self.repository)
        self.grid_remove()
        for ff in self.guiParent.guiParent.parent.frames[0].children.values():
            ff.drawFrame()

    def tmpCall(self):

        return

    # This will need a separate call to the WS with an additional
    # criterion (picking up the checkout version)

    def updateRepTree(self):

        texts = []
        icons = []
        parents = []
        callbacks = []
        objects = []

        # OK, this would be a good point to access the list

        # this should be associated with the repository object
        loc = SharedBeanServiceLocator()
        port = loc.getSharedBean()
        request = getList()

        # these are actually static
        request._arg0 = 'org.pimslims.applet.server.ProjectBean'
        request._arg1 = 'getList'
        request._arg2 = ''

        # get the response
        response = port.getList(request)

        # this is a hack at present. It needs to be written properly
        wsstr = WSString(response._return)
        ss = wsstr.getStruct()

        for strg in ss:
            texts.append(strg)
            icons.append('folder')
            parents.append(None)
            objects.append(strg)
            callbacks.append(self.openLink)

        print 'UPDATE ', ss
        print 'UPDATE ', len(ss)

        if len(ss) > 0:
            print 'UPDATE: updating '
            self.repTree.update(parents, objects, texts, icons, callbacks)

    def administerNotifiers(self, notifyFunc):

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

    def updateAllAfter(self, obj):

        self.after_idle(self.updateAll)

    def updateAll(self, project=None):

        return

    def quit(self):

        self.guiParent.parent.destroy()

    def destroy(self):

        self.administerNotifiers(self.basePopup.unregisterNotify)
        Frame.destroy(self)
示例#4
0
class PeakSeparatorGui(BasePopup):
    """
  **Separate Merged Peaks Using Peak Models**

  The Peak Separator code uses a Markov Chain Monte Carlo search which, using
  idealised peak shapes, attempts to deconvolve overlapped peak regions into 
  their separate constituent peaks.
  
  This routine is also suitable for accurately fitting model shapes to single
  peaks in order to calculate precise intensities.
  
  **Options Peak Separator Parameters**
  *Min. Number of peaks* is by default set to one, it is not possible to set 
  this to a value less than one.
  *Max. Number of peaks* is by default set to one, increasing this value allows
  the search routine to fit more models. The best fit may be found with fewer than
  the maximum number models. Higher numbers slow the routine, and setting this
  value to 0 allows the routine to (effectively) fit unlimited peaks.
  *Only pick positive peaks*. If you are not interested in negative peaks, removing
  the possibility of fitting negative peaks can reduce search time.
  *Peak Model* fits the spectra with either a Gaussian peak model or a Lorentzian
  peak model.

  **Options Region**
  *Peak List* choose which peak list newly picked peaks should be added to. Peaks
  picked using this method will have their details appended with 'PeakSepartor' 
  so you know where they came from.
  *Region Table* shows which area of the current spectrum is about to be searched.
  *Add Region*. Once an area of spectra has been highlighted clicking this button
  will pass it's details on to the Peak Separator.
  *Reset All* will reset all search parameters.
  *Separate Peaks* will run the Peak Separator code with your current settings. This
  may take a few minutes to run, depending on the size of the spectral region being
  searched, the number of peaks being fitted and the speed of your machine. Please
  wait while this completes.
  
  After a successful Peak Separation run, the found peaks will be added to the 
  selected peak list. These peaks intensties (volume) have been found using the
  peak model selected.

  **Advanced Settings Tab**
  *Rate* affects the speed of the Markov Chain Monte Carlo routine. A smaller value
  results in longer execution, but possibly higher quality results. The default 
  setting is deemed sensible for the majority of runs.
  *Line Width* offers a finer degree of control over maximum and minimum peak widths
  for each dimension. The default values are *very* stupid and could do with 
  re-checking for each experiment.
  *Re-Pick Entire Peak List* if you would like to use the Peak Separator to repick
  *every* peak in your peak list, try this option - but note that this may take
  a very long time!

  """
    def __init__(self, parent, programName='Peak Separator', **kw):

        self.parent = parent
        self.programName = programName
        self.versionInfo = 'Version 0.2'
        self.help_url = 'http://www.ccpn.ac.uk/'

        self.window = None
        self.waiting = False
        self.rootWindow = None

        # just used for display - PeakSeparator will not see this
        self._minSigmaHz = None
        self._maxSigmaHz = None

        self.customSigma = False
        self.rePickPeakList = False

        self._sampleStartPpm = None
        self._sampleEndPpm = None

        try:
            self.project = parent.project
        except:
            pass

        self.params = PeakSeparatorParams()

        BasePopup.__init__(self,
                           parent=parent,
                           title=programName,
                           location='+100+100',
                           **kw)

        if not self.analysisProject:
            print '&&& init: No analysis project found ...'
        try:
            if parent.argumentServer:
                self.argServer = parent.argumentServer
            else:
                print '&&& init: No argument server found...'
        except:
            print '&&& init: Test'

    ###########################################################################

    def body(self, guiFrame):

        self.geometry('450x500')

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

        options = ['Peak Separator', 'Advanced Settings']

        tabbedFrame = TabbedFrame(guiFrame, options=options)
        tabbedFrame.grid(row=0, column=0, sticky='nsew')

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

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

        #
        # FrameA : Main Settings
        #

        frameA.grid_columnconfigure(1, weight=1)
        row = 0  # Label row

        row += 1
        div = LabelDivider(frameA, text='Peak Separator Parameters')
        div.grid(row=row, column=0, columnspan=2, sticky='ew')

        row += 1
        label = Label(frameA, text='Min. number of peaks:')
        label.grid(row=row, column=0, sticky='w')
        self.minPeaksEntry = IntEntry(frameA, returnCallback=self.applyChange, width=10, \
              tipText='Minimum number of peaks to find (must be > 0)')
        self.minPeaksEntry.grid(row=row, column=1, sticky='n')
        self.minPeaksEntry.bind('<Leave>', self.applyChange, '+')

        row += 1
        label = Label(frameA, text='Max. number of peaks:')
        label.grid(row=row, column=0, sticky='w')
        self.maxPeaksEntry = IntEntry(frameA, returnCallback=self.applyChange, width=10, \
              tipText='Maximum number of peaks to find (0 is unlimited - not recommended)')
        self.maxPeaksEntry.grid(row=row, column=1, sticky='n')
        self.maxPeaksEntry.bind('<Leave>', self.applyChange, '+')

        row += 1
        label = Label(frameA, text='Only pick positive peaks:')
        label.grid(row=row, column=0, sticky='w')
        entries = ['False', 'True']
        self.posPeaksButtons = RadioButtons(
            frameA,
            entries=entries,
            select_callback=self.applyChange,
            direction='horizontal',
            tipTexts=[
                'Search for both positive and negative intensity peaks',
                'Limit search to only positive peaks'
            ])
        self.posPeaksButtons.grid(row=row, column=1, sticky='n')

        row += 1
        label = Label(frameA, text='Peak Model:')
        label.grid(row=row, column=0, sticky='w')
        ### G/L Mixture works, but volume calculation involves Gamma function
        # entries = ['Gaussian', 'Lorentzian', 'G/L Mixture']
        entries = ['Gaussian', 'Lorentzian']
        self.shapeButtons = RadioButtons(
            frameA,
            entries=entries,
            select_callback=self.applyChange,
            direction='horizontal',
            tipTexts=[
                'Choose a Gaussian model peak shape to fit to peaks',
                'Choose a Lorentzian model peak shape to fit to peaks'
            ])
        self.shapeButtons.grid(row=row, column=1, sticky='n')

        row += 1
        div = LabelDivider(frameA,
                           text='Region',
                           tipText='Region that search will limit itself to')
        div.grid(row=row, column=0, columnspan=2, sticky='ew')

        row += 1
        label = Label(frameA, text='Peak List:')
        label.grid(row=row, column=0, sticky='nw')
        self.peakListPulldown = PulldownList(
            frameA,
            callback=self.setManuallyPickPeakList,
            tipText='Select which peak list new peaks are to be added to')
        self.peakListPulldown.grid(row=row, column=1, sticky='nw')

        # tricky scrolled matrix
        row += 1
        self.regionTable = None
        frameA.grid_rowconfigure(row, weight=1)
        headings = ('dim.', 'start (ppm)', 'end (ppm)', 'actual size')

        self.editDimEntry = IntEntry(self,
                                     returnCallback=self.applyChange,
                                     width=5,
                                     tipText='Dimension number')
        self.editStartEntry = FloatEntry(self,
                                         returnCallback=self.applyChange,
                                         width=5,
                                         tipText='Search area lower bound')
        self.editEndEntry = FloatEntry(self,
                                       returnCallback=self.applyChange,
                                       width=5,
                                       tipText='Search area upper bound')

        editWidgets = [
            self.editDimEntry, self.editStartEntry, self.editEndEntry, None
        ]

        editGetCallbacks = [None, None, None, None]
        editSetCallbacks = [None, None, None, None]

        self.regionTable = ScrolledMatrix(frameA,
                                          headingList=headings,
                                          multiSelect=False,
                                          editWidgets=editWidgets,
                                          editGetCallbacks=editGetCallbacks,
                                          editSetCallbacks=editSetCallbacks,
                                          initialRows=5)

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

        # Run Button
        row += 1
        texts = ['Add Region']
        commands = [self.updateFromRegion]
        self.addResetButtons = ButtonList(
            frameA,
            texts=texts,
            commands=commands,
            tipTexts=['Add selected specrtral region'])
        self.addResetButtons.grid(row=row, column=0, columnspan=2, sticky='ew')

        row += 1
        texts = ['Separate Peaks']
        commands = [self.runPeakSeparator]
        self.runButton = ButtonList(frameA,
                                    texts=texts,
                                    commands=commands,
                                    expands=True,
                                    tipTexts=['Run peak search now'])
        self.runButton.grid(row=row, column=0, columnspan=2, sticky='nsew')

        #
        # FrameB : Further Settings
        #

        frameB.grid_columnconfigure(0, weight=1)

        row = 0

        div = LabelDivider(frameB, text='Rate:')
        div.grid(row=row, column=0, columnspan=2, sticky='ew')
        row += 1

        label = Label(frameB, text='Rate of MCMC step size change')
        label.grid(row=row, column=0, columnspan=1, sticky='w')

        self.rateEntry = FloatEntry(frameB, returnCallback=self.applyChange, width=10, \
              tipText='Rate effects speed of run, smaller values take longer but may produce better results')
        self.rateEntry.grid(row=row, column=1, sticky='n')
        self.rateEntry.bind('<Leave>', self.applyChange, '+')
        self.rateEntry.set(self.params.rate)

        # tricky scrolled matrix for line width
        row += 2
        div = LabelDivider(frameB, text='Line Width (Hz):')
        div.grid(row=row, column=0, columnspan=2, sticky='ew')

        row += 1
        label = Label(frameB, text="Descr.")
        label.grid(row=row, rowspan=2, column=0, sticky='w')

        row += 1
        self.lineWidthTable = None
        frameB.grid_rowconfigure(row, weight=1)
        lineWidthHeadings = ('dim.', 'min. σ (Hz)', 'max. σ (Hz)')

        self.editMinSigmaEntry = FloatEntry(self,
                                            returnCallback=self.applyChange,
                                            width=5,
                                            tipText='Minimum line width (Hz)')
        self.editMaxSigmaEntry = FloatEntry(self,
                                            returnCallback=self.applyChange,
                                            width=5,
                                            tipText='Maximum line width (Hz)')

        # self.editDimEntry is also from regionTable
        initialWidthRows = 4

        editLineWidthWidgets = [
            None, self.editMinSigmaEntry, self.editMaxSigmaEntry
        ]
        editLineWidthGetCallbacks = [None, self.getSigmaMin, self.getSigmaMax]
        editLineWidthSetCallbacks = [None, self.setSigmaMin, self.setSigmaMax]

        self.lineWidthTable = ScrolledMatrix(
            frameB,
            headingList=lineWidthHeadings,
            multiSelect=False,
            editWidgets=editLineWidthWidgets,
            editGetCallbacks=editLineWidthGetCallbacks,
            editSetCallbacks=editLineWidthSetCallbacks,
            initialRows=initialWidthRows)

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

        # option to 'repick' exisiting peak list
        row += initialWidthRows
        div = LabelDivider(frameB, text='(optional - repick entire peak list)')
        div.grid(row=row, column=0, columnspan=2, sticky='ew')
        row += 1

        self.repickListPulldown = PulldownList(
            frameB,
            callback=self.setRePickPeakList,
            tipText=
            'Select which peak list to repick (new peaks will be put into a new peak list)'
        )
        self.repickListPulldown.grid(row=row, column=0, sticky='nw')

        texts = ['Repick Peak List']
        commands = [self.runRepickPeaks]
        self.runButton = ButtonList(
            frameB,
            texts=texts,
            commands=commands,
            expands=True,
            tipTexts=['Repick selected peak list into a new peak list.'])
        self.runButton.grid(row=row, column=1, columnspan=1, sticky='nsew')

        row += 1
        div = LabelDivider(frameB)
        row += 1
        texts = ['Separate Peaks']
        commands = [self.runPeakSeparator]
        self.runButton = ButtonList(frameB,
                                    texts=texts,
                                    commands=commands,
                                    expands=True,
                                    tipTexts=['Run peak search now'])
        self.runButton.grid(row=row, column=0, columnspan=2, sticky='nsew')

        self.setWidgetEntries()

        self.administerNotifiers(self.registerNotify)

    def administerNotifiers(self, notifyFunc):

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

        notifyFunc(self.updateAfter, 'ccp.nmr.Nmr.Experiment', 'setName')
        notifyFunc(self.updateAfter, 'ccp.nmr.Nmr.DataSource', 'setName')

    def destroy(self):

        self.administerNotifiers(self.unregisterNotify)
        BasePopup.destroy(self)

    ###########################################################################
    # update parameters from PS Region

    def updateFromRegion(self):

        if not self.params.peakList:
            print '&&& update from region: Need a peak list'
            return

        if (self.argServer.parent.currentRegion) == None:
            showError('No Region',
                      'Please select a peak region to be separated')
            return

        self.rePickPeakList = False

        getRegionParams(self.params, argServer=self.argServer)

        if not self.customSigma: self.initSigmaParams()

        self.setWidgetEntries()

    ###########################################################################
    # update parameters from PS PeakList

    def updateFromPeakList(self):

        if not self.params.peakList:
            print '&&& update from peakList: Need a peak list'
            return

        getPeakListParams(self.params)

        if not self.customSigma: self.initSigmaParams()

        self.setWidgetEntries()

    ###########################################################################
    # Run the C library!

    def runPeakSeparator(self):
        """ run the peak separator """

        # hack for Macs - focus isn't always lost on mouse move
        # so bind event not always called. Shouldn't affect other OS.
        self.applyChange()

        if not self.params.peakList:
            print '&&& Peak list not yet set'
        else:
            # SeparatePeakRoutine(self.params, self.params.peakList, routine='pymc' )
            SeparatePeakRoutine(self.params,
                                self.params.peakList,
                                routine='bayesys')

    def runRepickPeaks(self):
        """ Run the Peak Separator on entire chosen peak list """
        # hack for Macs - focus isn't always lost on mouse move
        # so bind event not always called. Shouldn't affect other OS.
        self.applyChange()

        if not self.params.peakList:
            print '&&& Peak list not yet set'
        else:
            SeparatePeaksInPeakList(self.params)

    ###########################################################################

    def setWidgetEntries(self):

        ### Page One widgets
        self.minPeaksEntry.set(self.params.minAtoms)
        self.maxPeaksEntry.set(self.params.maxAtoms)

        if self.params.positivePeaks == 1:
            self.posPeaksButtons.set('True')  # only pick pos peaks
        else:
            self.posPeaksButtons.set('False')

        # do something fancy if different shapes for each dim!
        n = self.params.peakShape - 3  # shape is only 3, 4, (5)
        self.shapeButtons.setIndex(n)

        if self.project is not None:
            self.updatePeakListList()
        self.updateSpectrumWindow()

        if self.params.sampleStart and self.params.peakList:

            if not self.rePickPeakList:
                objectList = []
                textMatrix = []

                if len(self.params.samplePpmStart) != self.params.Ndim: return

                for i in range(self.params.Ndim):
                    dim_entry = []
                    dim_entry.append('%2d' % (i + 1))
                    dim_entry.append('%7.3f' % self.params.samplePpmStart[i])
                    dim_entry.append('%7.3f' % self.params.samplePpmEnd[i])
                    dim_entry.append('%3d' % self.params.sampleSize[i])
                    textMatrix.append(dim_entry)

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

        ### Page Two widgets
        self.rateEntry.set(self.params.rate)

        if self.params.peakList and self.params.Ndim:

            textMatrix = []
            objectList = []

            for i in range(self.params.Ndim):
                if self.params.isFreqDim[i]:
                    dim_entry = []
                    objectList.append(i)
                    dim_entry.append('%2d' % (i + 1))
                    dim_entry.append('%7.3f' % self._minSigmaHz[i])
                    dim_entry.append('%7.3f' % self._maxSigmaHz[i])
                    textMatrix.append(dim_entry)

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

    def applyChange(self, *event):
        """ Upon change, add settings to params """

        # Page One apply changes
        self.params.minAtoms = self.minPeaksEntry.get()
        self.params.maxAtoms = self.maxPeaksEntry.get()

        if self.posPeaksButtons.get() == 'True':  # asked only pick pos peaks
            self.params.positivePeaks = 1
        else:
            self.params.positivePeaks = 0

        # do something fancy if different shapes for each dim!
        n = self.shapeButtons.getIndex()  # shape is only 3, 4, (5)
        self.params.peakShape = n + 3

        # Page Two apply changes
        self.params.rate = float(self.rateEntry.get())

        self.updateSigmaParams()

    ###########################################################################
    # Peak list functions provide PeakSeparator some inherited params

    def getPeakListList(self):
        """ given a spectrum, get list of peak lists """
        project = self.project

        peakLists = []
        for experiment in self.nmrProject.experiments:
            for spectrum in experiment.dataSources:
                for peakList in spectrum.peakLists:
                    peakLists.append([
                        '%s:%s:%d' %
                        (experiment.name, spectrum.name, peakList.serial),
                        peakList
                    ])
        peakLists.sort()
        return peakLists

    def updatePeakListList(self):
        """ set the peaklist list in the pulldown menu """
        peakListData = self.getPeakListList()

        index = -1
        names = []
        peakList = self.params.peakList

        if peakListData:
            names = [x[0] for x in peakListData]
            peakLists = [x[1] for x in peakListData]

            if peakList not in peakLists:
                peakList = peakLists[0]

            index = peakLists.index(peakList)

        else:
            peakList = None
            peakLists = []

        if peakList is not self.params.peakList:
            self.params.peakList = peakList

        self.peakListPulldown.setup(names, peakLists, index)
        self.repickListPulldown.setup(names, peakLists, index)

    def setRePickPeakList(self, peakList):
        """ Set the peak list to be repicked (and hit a Flag) """
        self.rePickPeakList = True
        self.setPeakList(peakList)

    def setManuallyPickPeakList(self, peakList):
        """ Set the peak list to add new peaks to (and hit a Flag) """
        self.rePickPeakList = False
        self.setPeakList(peakList)

    def setPeakList(self, peakList):
        """ Sets the Peak List """
        if peakList is not self.params.peakList:
            self.params.peakList = peakList
            # # interrogate the peak list and get all the usefull parameters out
            self.updateFromPeakList()
            self.updateSpectrumWindow()
            self.setWidgetEntries()

    ###########################################################################
    # TBD I suspect this is for matching region with peak list, but may be obsolete now

    def getSpectrumWindowList(self):
        """ get list of windows which spectrum could be in """
        windows = {}
        if self.params.peakList:
            views = getSpectrumViews(self.params.peakList.dataSource)
            for view in views:
                windows[view.spectrumWindowPane.spectrumWindow] = None

        return [[w.name, w] for w in windows.keys()]

    def updateSpectrumWindow(self):
        """ update the spectrum window """
        windowData = self.getSpectrumWindowList()

        index = -1
        names = []
        window = self.rootWindow

        if windowData:
            names = [x[0] for x in windowData]
            windows = [x[1] for x in windowData]

            if window not in windows:
                window = windows[0]

            index = windows.index(window)

        else:
            window = None
            windows = []

        if window is not self.rootWindow:
            self.rootWindow = window

    ###########################################################################
    # get and set sigma stuff
    def setSigmaMin(self, dim):

        value = self.editMinSigmaEntry.get()
        self._minSigmaHz[dim] = value

        # dont go and re-write users settings
        self.customSigma = True

        # make sure changes are in params object
        self.updateSigmaParams(dim)
        self.setWidgetEntries()

    def getSigmaMin(self, dim):

        if dim is not None:
            self.editMinSigmaEntry.set(self._minSigmaHz[dim])

    def setSigmaMax(self, dim):

        value = self.editMaxSigmaEntry.get()
        self._maxSigmaHz[dim] = value

        # dont go and re-write users settings
        self.customSigma = True

        # make sure changes are in params object
        self.updateSigmaParams(dim)
        self.setWidgetEntries()

    def getSigmaMax(self, dim):

        if dim is not None:
            self.editMaxSigmaEntry.set(self._maxSigmaHz[dim])

    def updateSigmaParams(self, dim=None):
        """ updateSigmaParams Just updates the parameters (params obj) for sigma values. 
        If dim is None, do this for each dim
    """

        dataDimRefs = self.params.dataDimRefs

        if not dataDimRefs: return

        if not self.params.minSigma or len(
                self.params.minSigma) != self.params.Ndim:
            self.params.minSigma = [0.] * self.params.Ndim

        if not self.params.maxSigma or len(
                self.params.maxSigma) != self.params.Ndim:
            self.params.maxSigma = [0.] * self.params.Ndim

        def updateSigmaParam(dim, dataDimRefs):
            """ Convert and update sigma for dim """

            if self.params.isFreqDim[dim]:
                # note factor of two!
                self.params.minSigma[dim] = self.rHz2pnt(
                    self._minSigmaHz[dim], dataDimRefs[dim]) / 2.
                self.params.maxSigma[dim] = self.rHz2pnt(
                    self._maxSigmaHz[dim], dataDimRefs[dim]) / 2.
            else:
                self.params.minSigma[dim] = 1.0
                self.params.maxSigma[dim] = 1.0

        if dim:
            updateSigmaParam(dim, dataDimRefs)
        else:
            for dim in range(self.params.Ndim):
                updateSigmaParam(dim, dataDimRefs)

    # utility functions for sigma values
    def pnt2rHz(self, point, dataDimRef):
        """ Point to relative Hz frequency relative to frequency at Zeroeth point
        Necessary when (for example) looking for width of peak in Hz
    """
        assert point, dataDimRef

        sigmaBase = pnt2hz(0, dataDimRef)
        sigmaHz = pnt2hz(point, dataDimRef)

        return abs(sigmaHz - sigmaBase)

    def rHz2pnt(self, freq, dataDimRef):
        """ Relative Hz to point frequency relative to frequency at Zeroeth point
        Necessary when (for example) looking for width of peak in Hz
    """
        assert freq, dataDimRef

        sigmaBase = hz2pnt(0, dataDimRef)
        sigmaPoint = hz2pnt(freq, dataDimRef)

        return abs(sigmaPoint - sigmaBase)

    def initSigmaParams(self):
        """ Set some initial default values for sigma """

        self._minSigmaHz = []
        self._maxSigmaHz = []

        if self.params.Ndim:
            for dim in range(self.params.Ndim):
                self._minSigmaHz.append(6.)
                self._maxSigmaHz.append(28.)

    ###########################################################################

    def updateAll(self):

        self.updateSpectrumWindow()
        self.updatePeakListList()

        self.waiting = False

    def updateAfter(self, obj=None):

        if self.waiting:
            return
        else:
            self.waiting = True
            self.after_idle(self.updateAll)
示例#5
0
class AddContourFilePopup(BasePopup):
    """
  **Add Existing Contour Files to Project**

  The purpose of this dialog is to allow the user to add pre-existing
  contour files to the project.  Contour files only depend on the spectrum
  data so the same contour files can be used across multiple projects,
  and that is the reason this dialog might be used.

  See also: `Spectrum Contour Files`_, `Creating Contour Files`_.

  .. _`Spectrum Contour Files`: EditContourFilesPopup.html
  .. _`Creating Contour Files`: CreateContourFilePopup.html
"""
    def __init__(self, parent, *args, **kw):

        self.spectrum = None

        BasePopup.__init__(self,
                           parent=parent,
                           title='Add existing contour file',
                           **kw)

    def body(self, master):

        self.geometry('600x130')
        master.grid_columnconfigure(1, weight=1)
        for n in range(5):
            master.grid_rowconfigure(n, weight=1)

        row = 0
        label = Label(master, text='Spectrum: ')
        label.grid(row=row, column=0, sticky='e')
        tipText = 'The spectrum for which the contour file is being added'
        self.expt_spectrum = PulldownList(master,
                                          callback=self.updateContourDir,
                                          tipText=tipText)
        self.expt_spectrum.grid(row=row, column=1, sticky='w')

        row = row + 1
        tipText = 'The location of the directory where contour files are stored on disk'
        label = Label(master, text='Contour dir: ')
        label.grid(row=row, column=0, sticky='e')
        self.dir_label = Label(master, text='', tipText=tipText)
        self.dir_label.grid(row=row, column=1, sticky='w')

        row = row + 1
        label = Label(
            master,
            text=
            '(file will be copied into Contour dir if it is not already in there)'
        )
        label.grid(row=row, column=1, sticky='w')

        row = row + 1
        tipText = 'Browse for a file store contour data'
        button = Button(master,
                        text='File name: ',
                        command=self.selectFile,
                        tipText=tipText)
        button.grid(row=row, column=0, sticky='e')
        tipText = 'Enter the name of the file to store contour data'
        self.file_entry = Entry(master, tipText=tipText)
        self.file_entry.grid(row=row, column=1, sticky='ew')

        row = row + 1
        texts = ['Add File']
        commands = [self.addFile]
        tipTexts = [
            'Use the selected contour file in the current project, copying it to the contour directory if required',
        ]
        self.buttons = UtilityButtonList(master,
                                         texts=texts,
                                         doClone=False,
                                         tipTexts=tipTexts,
                                         commands=commands,
                                         helpUrl=self.help_url)
        self.buttons.grid(row=row, column=0, columnspan=2, sticky='ew')

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

    def destroy(self):

        self.curateNotifiers(self.unregisterNotify)

        BasePopup.destroy(self)

    def curateNotifiers(self, notifyFunc):

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

    def updateSpectrum(self, spectrum=None):

        if not spectrum:
            spectrum = self.spectrum

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

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

        self.updateContourDir(spectrum)

    def updateNotifier(self, *extra):

        self.updateSpectrum()

    def updateContourDir(self, spectrum):

        if spectrum is self.spectrum:
            return

        self.spectrum = spectrum

        if spectrum:
            path = spectrum.analysisSpectrum.contourDir.dataLocation
        else:
            path = ''
        self.dir_label.set(path)

    def selectFile(self):

        spectrum = self.spectrum
        if spectrum:
            directory = spectrum.analysisSpectrum.contourDir.dataLocation
        else:
            directory = os.getcwd()
        popup = FileSelectPopup(self, directory=directory)
        fileName = popup.getFile()
        popup.destroy()
        if fileName:
            self.file_entry.set(fileName)

    def addFile(self):

        spectrum = self.spectrum
        if not spectrum:
            return

        dataStore = spectrum.dataStore
        if not dataStore:
            showError('No dataStore',
                      'Spectrum does not have associated dataStore',
                      parent=self)
            return

        if not isinstance(dataStore, BlockedBinaryMatrix):
            showError('No blockedBinaryMatrix',
                      'Spectrum dataStore is not a blockedBinaryMatrix',
                      parent=self)
            return

        if not dataStore.blockSizes:
            showError('No blockSize',
                      'Spectrum dataStore does not have blockSize set',
                      parent=self)
            return

        blockSize = list(dataStore.blockSizes)

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

        fileName = normalisePath(fileName, makeAbsolute=True)

        contourDir = spectrum.analysisSpectrum.contourDir.dataLocation
        if fileName.startswith(contourDir):
            path = fileName[len(contourDir) + 1:]
        else:
            path = os.path.basename(fileName)
            if not os.path.exists(contourDir):
                os.makedirs(contourDir)
            print 'Copying %s to %s' % (fileName, contourDir)
            shutil.copy(fileName, contourDir)

        try:
            header = getStoredContourHeader(fileName)
        except Exception, e:
            showError('File error', str(e), parent=self)
            return

        if header['ndim'] != spectrum.numDim:
            showError(
                'Number of dimensions',
                'Number of dimensions in file (%d) does not match spectrum (%d)'
                % (header['ndim'], spectrum.numDim),
                parent=self)
            return

        dataDims = spectrum.sortedDataDims()
        npoints = [x.numPoints for x in dataDims]
        if header['npoints'] != npoints:
            showError(
                'Number of points',
                'Number of points in file (%s) does not match spectrum (%s)' %
                (header['npoints'], npoints),
                parent=self)
            return

        if header['blockSize'] != blockSize:
            showError('Block size',
                      'Block size in file (%s) does not match spectrum (%s)' %
                      (header['blockSize'], blockSize),
                      parent=self)
            return

        createStoredContour(spectrum, path, header['xdim'], header['ydim'])

        showInfo('Added file',
                 'Successfully added stored contour file',
                 parent=self)
示例#6
0
class CingFrame(NmrSimRunFrame):

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

    project = application.project
    simStore = project.findFirstNmrSimStore(application=APP_NAME) or \
               project.newNmrSimStore(application=APP_NAME, name=APP_NAME)

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

    NmrSimRunFrame.__init__(self, parent, project, simStore, *args, **kw)

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

    self.structureFrame.grid_forget()

    tab = self.tabbedFrame.frames[0]

    frame = Frame(tab, grid=(1,0))
    frame.expandGrid(2,1)

    div = LabelDivider(frame, text='Structures', grid=(0,0), gridSpan=(1,2))

    label = Label(frame, text='Ensemble: ', grid=(1,0))
    self.structurePulldown = PulldownList(frame, callback=self.changeStructure, grid=(1,1))

    headingList = ['Model','Use']
    editWidgets      = [None,None]
    editGetCallbacks = [None,self.toggleModel]
    editSetCallbacks = [None,None,]
    self.modelTable = ScrolledMatrix(frame, grid=(2,0), gridSpan=(1,2),
                                     callback=self.selectStructModel,
                                     editWidgets=editWidgets,
                                     editGetCallbacks=editGetCallbacks,
                                     editSetCallbacks=editSetCallbacks,
                                     headingList=headingList)

    texts = ['Activate Selected','Inactivate Selected']
    commands = [self.activateModels, self.disableModels]
    buttons = ButtonList(frame, texts=texts, commands=commands, grid=(3,0), gridSpan=(1,2))


    # # # # # # Submission frame # # # # # #

    tab = self.tabbedFrame.frames[1]
    tab.expandGrid(1,0)

    frame = LabelFrame(tab, text='Server Job Submission', grid=(0,0))
    frame.expandGrid(None,2)

    srow = 0
    label = Label(frame, text='iCing URL:', grid=(srow, 0))
    urls = [DEFAULT_URL,]
    self.iCingBaseUrlPulldown = PulldownList(frame, texts=urls, objects=urls, index=0, grid=(srow,1))


    srow +=1
    label = Label(frame, text='Results File:', grid=(srow, 0))
    self.resultFileEntry = Entry(frame, bd=1, text='', grid=(srow,1), width=50)
    self.setZipFileName()
    button = Button(frame, text='Choose File', bd=1, sticky='ew',
                    command=self.chooseZipFile, grid=(srow, 2))

    srow +=1
    label = Label(frame, text='Results URL:', grid=(srow, 0))
    self.resultUrlEntry = Entry(frame, bd=1, text='', grid=(srow,1), width=50)
    button = Button(frame, text='View Results HTML', bd=1, sticky='ew',
                    command=self.viewHtmlResults, grid=(srow, 2))

    srow +=1
    texts    = ['Submit Project!', 'Check Run Status',
                'Purge Server Result', 'Download Results']
    commands = [self.runCingServer, self.checkStatus,
                self.purgeCingServer, self.downloadResults]

    self.buttonBar = ButtonList(frame, texts=texts, commands=commands,
                                grid=(srow, 0), gridSpan=(1,3))

    for button in self.buttonBar.buttons[:1]:
      button.config(bg=CING_BLUE)

    # # # # # # Residue frame # # # # # #

    frame = LabelFrame(tab, text='Residue Options', grid=(1,0))
    frame.expandGrid(1,1)

    label = Label(frame, text='Chain: ')
    label.grid(row=0,column=0,sticky='w')
    self.chainPulldown = PulldownList(frame, callback=self.changeChain)
    self.chainPulldown.grid(row=0,column=1,sticky='w')

    headingList = ['#','Residue','Linking','Decriptor','Use?']
    editWidgets      = [None,None,None,None,None]
    editGetCallbacks = [None,None,None,None,self.toggleResidue]
    editSetCallbacks = [None,None,None,None,None,]
    self.residueMatrix = ScrolledMatrix(frame,
                                        headingList=headingList,
                                        multiSelect=True,
                                        editWidgets=editWidgets,
                                        editGetCallbacks=editGetCallbacks,
                                        editSetCallbacks=editSetCallbacks,
                                        callback=self.selectResidue)
    self.residueMatrix.grid(row=1, column=0, columnspan=2, sticky = 'nsew')

    texts = ['Activate Selected','Inactivate Selected']
    commands = [self.activateResidues, self.deactivateResidues]
    self.resButtons = ButtonList(frame, texts=texts, commands=commands,)
    self.resButtons.grid(row=2, column=0, columnspan=2, sticky='ew')

    """
    # # # # # # Validate frame # # # # # #

    frame = LabelFrame(tab, text='Validation Options', grid=(2,0))
    frame.expandGrid(None,2)

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

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

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

    srow += 1
    self.selectCheckScript = CheckButton(frame)
    self.selectCheckScript.grid(row=srow, column=0,sticky='nw' )
    self.selectCheckScript.set(False)
    label = Label(frame, text='User Python script\n(overriding option)')
    label.grid(row=srow,column=1,sticky='nw')

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

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

    # # # # # # # # # #

    self.update(simStore)

    self.administerNotifiers(application.registerNotify)

  def downloadResults(self):

    if not self.run:
      msg = 'No current iCing run'
      showWarning('Failure', msg, parent=self)
      return

    credentials = self.serverCredentials
    if not credentials:
      msg = 'No current iCing server job'
      showWarning('Failure', msg, parent=self)
      return

    fileName = self.resultFileEntry.get()
    if not fileName:
      msg = 'No save file specified'
      showWarning('Failure', msg, parent=self)
      return

    if os.path.exists(fileName):
      msg = 'File %s already exists. Overwite?' % fileName
      if not showOkCancel('Query', msg, parent=self):
        return

    url = self.iCingBaseUrl
    iCingUrl = self.getServerUrl(url)
    logText = iCingRobot.iCingFetch(credentials, url, iCingUrl, fileName)
    print logText

    msg = 'Results saved to file %s\n' % fileName
    msg += 'Purge results from iCing server?'
    if showYesNo('Query',msg, parent=self):
      self.purgeCingServer()


  def getServerUrl(self, baseUrl):

    iCingUrl = os.path.join(baseUrl, 'icing/serv/iCingServlet')
    return iCingUrl

  def viewHtmlResults(self):

    resultsUrl = self.resultsUrl
    if not resultsUrl:
      msg = 'No current iCing results URL'
      showWarning('Failure', msg, parent=self)
      return

    webBrowser = WebBrowser(self.application, popup=self.application)
    webBrowser.open(self.resultsUrl)


  def runCingServer(self):

    if not self.project:
      return

    run = self.run
    if not run:
      msg = 'No CING run setup'
      showWarning('Failure', msg, parent=self)
      return

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

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

    residueText = getResiduesString(structure)
    if not residueText:
      msg = 'No active residues selected in structure'
      showWarning('Failure', msg, parent=self)
      return

    url = self.iCingBaseUrlPulldown.getObject()
    url.strip()
    if not url:
      msg = 'No iCing server URL specified'
      showWarning('Failure', msg, parent=self)
      self.iCingBaseUrl = None
      return

    msg = 'Submit job now? You will be informed when the job is done.'
    if not showOkCancel('Confirm', msg, parent=self):
      return

    self.iCingBaseUrl = url
    iCingUrl = self.getServerUrl(url)
    self.serverCredentials, results, tarFileName = iCingRobot.iCingSetup(self.project, userId='ccpnAp', url=iCingUrl)

    if not results:
      # Message already issued on failure
      self.serverCredentials = None
      self.resultsUrl = None
      self.update()
      return

    else:
      credentials = self.serverCredentials
      os.unlink(tarFileName)

    entryId = iCingRobot.iCingProjectName(credentials, iCingUrl).get(iCingRobot.RESPONSE_RESULT)
    baseUrl, htmlUrl, logUrl, zipUrl = iCingRobot.getResultUrls(credentials, entryId, url)

    self.resultsUrl = htmlUrl

    # Save server data in this run for persistence

    setRunParameter(run, iCingRobot.FORM_USER_ID, self.serverCredentials[0][1])
    setRunParameter(run, iCingRobot.FORM_ACCESS_KEY, self.serverCredentials[1][1])
    setRunParameter(run, ICING_BASE_URL, url)
    setRunParameter(run, HTML_RESULTS_URL, htmlUrl)
    self.update()

    run.inputStructures = structure.sortedModels()

    # select residues from the structure's chain
    #iCingRobot.iCingResidueSelection(credentials, iCingUrl, residueText)

    # Select models from ensemble
    #iCingRobot.iCingEnsembleSelection(credentials, iCingUrl, ensembleText)

    # Start the actual run
    self.serverDone = False
    iCingRobot.iCingRun(credentials, iCingUrl)

    # Fetch server progress occasionally, report when done
    # this function will call itself again and again
    self.after(CHECK_INTERVAL, self.timedCheckStatus)

    self.update()

  def timedCheckStatus(self):

    if not self.serverCredentials:
      return

    if self.serverDone:
      return

    status = iCingRobot.iCingStatus(self.serverCredentials, self.getServerUrl(self.iCingBaseUrl))

    if not status:
      #something broke, already warned
      return

    result = status.get(iCingRobot.RESPONSE_RESULT)
    if result == iCingRobot.RESPONSE_DONE:
      self.serverDone = True
      msg = 'CING run is complete!'
      showInfo('Completion', msg, parent=self)
      return

    self.after(CHECK_INTERVAL, self.timedCheckStatus)

  def checkStatus(self):

    if not self.serverCredentials:
      return

    status = iCingRobot.iCingStatus(self.serverCredentials, self.getServerUrl(self.iCingBaseUrl))

    if not status:
      #something broke, already warned
      return

    result = status.get(iCingRobot.RESPONSE_RESULT)
    if result == iCingRobot.RESPONSE_DONE:
      msg = 'CING run is complete!'
      showInfo('Completion', msg, parent=self)
      self.serverDone = True
      return

    else:
      msg = 'CING job is not done.'
      showInfo('Processing', msg, parent=self)
      self.serverDone = False
      return


  def purgeCingServer(self):

    if not self.project:
      return

    if not self.run:
      msg = 'No CING run setup'
      showWarning('Failure', msg, parent=self)
      return

    if not self.serverCredentials:
      msg = 'No current iCing server job'
      showWarning('Failure', msg, parent=self)
      return

    url = self.iCingBaseUrl
    results = iCingRobot.iCingPurge(self.serverCredentials, self.getServerUrl(url))

    if results:
      showInfo('Info','iCing server results cleared')
      self.serverCredentials = None
      self.iCingBaseUrl = None
      self.serverDone = False
      deleteRunParameter(self.run, iCingRobot.FORM_USER_ID)
      deleteRunParameter(self.run, iCingRobot.FORM_ACCESS_KEY)
      deleteRunParameter(self.run, HTML_RESULTS_URL)
    else:
      showInfo('Info','Purge failed')

    self.update()

  def chooseZipFile(self):

    fileTypes = [  FileType('Zip', ['*.zip']), ]
    popup = FileSelectPopup(self, file_types=fileTypes, file=self.resultFileEntry.get(),
                            title='Results zip file location', dismiss_text='Cancel',
                            selected_file_must_exist=False)

    fileName = popup.getFile()

    if fileName:
      self.resultFileEntry.set(fileName)
    popup.destroy()

  def setZipFileName(self):

    zipFile = '%s_CING_report.zip' % self.project.name
    self.resultFileEntry.set(zipFile)

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

    self.model = model

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

    self.residue = residue

  def deactivateResidues(self):

    for residue in self.residueMatrix.currentObjects:
      residue.useInCing = False

    self.updateResidues()

  def activateResidues(self):

    for residue in self.residueMatrix.currentObjects:
      residue.useInCing = True

    self.updateResidues()

  def activateModels(self):

    if self.run:
      for model in self.modelTable.currentObjects:
        if model not in self.run.inputStructures:
          self.run.addInputStructure(model)

      self.updateModels()

  def disableModels(self):

    if self.run:
      for model in self.modelTable.currentObjects:
        if model in self.run.inputStructures:
          self.run.removeInputStructure(model)

      self.updateModels()

  def toggleModel(self, *opt):

    if self.model and self.run:
      if self.model in self.run.inputStructures:
        self.run.removeInputStructure(self.model)
      else:
        self.run.addInputStructure(self.model)

      self.updateModels()

  def toggleResidue(self, *opt):

    if self.residue:
      self.residue.useInCing = not self.residue.useInCing
      self.updateResidues()


  def updateResidues(self):

    if self.residue and (self.residue.topObject is not self.structure):
      self.residue = None

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

    if self.chain:
      chainCode = self.chain.code

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

        if not hasattr(residue, 'useInCing'):
          residue.useInCing = True

        if residue.useInCing:
          colors = [None, None, None, None, CING_BLUE]
          use = 'Yes'

        else:
          colors = [None, None, None, None, None]
          use = 'No'

        datum = [residue.seqCode,
                 msResidue.ccpCode,
                 msResidue.linking,
                 msResidue.descriptor,
                 use,]

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

    self.residueMatrix.update(objectList=objectList,
                              textMatrix=textMatrix,
                              colorMatrix=colorMatrix)


  def updateChains(self):

    index = 0
    names = []
    chains = []
    chain = self.chain

    if self.structure:
      chains = self.structure.sortedCoordChains()
      names = [chain.code for chain in chains]

      if chains:
        if chain not in chains:
          chain = chains[0]
          index = chains.index(chain)

        self.changeChain(chain)

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


  def updateStructures(self):

    index = 0
    names = []
    structures = []
    structure = self.structure

    if self.run:
      model = self.run.findFirstInputStructure()
      if model:
        structure = model.structureEnsemble

      structures0 = [(s.ensembleId, s) for s in self.project.structureEnsembles]
      structures0.sort()

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

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

      index = structures.index(structure)

    self.changeStructure(structure)

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


  def updateModels(self):

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

    if self.structure and self.run:
      used = self.run.inputStructures

      for model in self.structure.sortedModels():


        if model in used:
          colors = [None, CING_BLUE]
          use = 'Yes'

        else:
          colors = [None, None]
          use = 'No'

        datum = [model.serial,use]

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

    self.modelTable.update(objectList=objectList,
                           textMatrix=textMatrix,
                           colorMatrix=colorMatrix)


  def changeStructure(self, structure):

    if self.project and (self.structure is not structure):
      self.project.currentEstructureEnsemble = structure
      self.structure = structure

      if self.run:
        self.run.inputStructures = structure.sortedModels()

      self.updateModels()
      self.updateChains()


  def changeChain(self, chain):

    if self.project and (self.chain is not chain):
      self.chain = chain
      self.updateResidues()

  def chooseValidScript(self):

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

    fileName = popup.getFile()
    self.validScriptEntry.set(fileName)
    popup.destroy()

  def updateAll(self, project=None):

    if project:
      self.project = project
      self.nmrProject = project.currentNmrProject
      simStore = project.findFirstNmrSimStore(application='CING') or \
                 project.newNmrSimStore(application='CING', name='CING')
    else:
      simStore = None

    if not self.project:
      return

    self.setZipFileName()
    if not self.project.currentNmrProject:
      name = self.project.name
      self.nmrProject = self.project.newNmrProject(name=name)
    else:
      self.nmrProject = self.project.currentNmrProject

    self.update(simStore)

  def update(self, simStore=None):

    NmrSimRunFrame.update(self, simStore)

    run = self.run
    urls = [DEFAULT_URL,]
    index = 0

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

      url = getRunParameter(run, ICING_BASE_URL)
      if url:
        htmlUrl = getRunParameter(run, HTML_RESULTS_URL)
        self.iCingBaseUrl = url
        self.resultsUrl = htmlUrl # May be None

      self.resultUrlEntry.set(self.resultsUrl)

      if self.iCingBaseUrl and self.iCingBaseUrl not in urls:
        index = len(urls)
        urls.append(self.iCingBaseUrl)

    self.iCingBaseUrlPulldown.setup(urls, urls, index)

    self.updateButtons()
    self.updateStructures()
    self.updateModels()
    self.updateChains()

  def updateButtons(self, event=None):

    buttons = self.buttonBar.buttons
    if self.project and self.run:
      buttons[0].enable()

      if self.resultsUrl and self.serverCredentials:
        buttons[1].enable()
        buttons[2].enable()
        buttons[3].enable()

      else:
        buttons[1].disable()
        buttons[2].disable()
        buttons[3].disable()

    else:
      buttons[0].disable()
      buttons[1].disable()
      buttons[2].disable()
      buttons[3].disable()
示例#7
0
class BrukerPseudoPopup(BasePopup):

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

    self.dim = dim
    self.params = params

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

  def body(self, master):

    pseudoExpts = getSampledDimExperiments(self.parent.nmrProject)

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

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

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

    row = 0
    if pseudoExpts:
      tipText = 'Select from existing pseudo nD experiments to copy sampled axis values from'
      texts = [x.name for x in pseudoExpts]
      label = Label(frame, text='Existing pseudo expts: ')
      label.grid(row=row, column=0, sticky='e')
      self.pseudoList = PulldownList(frame, texts=texts, objects=pseudoExpts, tipText=tipText)
      self.pseudoList.grid(row=row, column=1, sticky='w')
      tipText = 'Transfer the sampled axis values from the existing experiment to the new one'
      Button(frame, text='Copy values down', command=self.copyValues,
             tipText=tipText, grid=(row,2))
      
      row += 1

    npts = self.params.npts[self.dim]
    tipText = 'Number of data points (planes) along sampled axis'
    label = Label(frame, text='Number of points: ')
    label.grid(row=row, column=0, sticky='e')
    self.nptsEntry = IntEntry(frame, text=npts, tipText=tipText, width=8, grid=(row,1))
     
    tipText = 'Load the values for the sampled axis from a text file containing a list of numeric values'
    Button(frame, text='Load File', command=self.loadValues,
           tipText=tipText, grid=(row,2), sticky='ew')
     
    row += 1

    tipText = 'The values (e.g. T1, T2) corresponding to each data point (plane) along sampled axis'
    label = Label(frame, text='Point values: ')
    label.grid(row=row, column=0, sticky='e')
    self.valueEntry = FloatEntry(frame, isArray=True, tipText=tipText)
    #minRows = self.params.npts[self.dim]
    #self.valueEntry = MultiWidget(frame, FloatEntry, callback=None, minRows=minRows, maxRows=None,
    #                              options=None, values=[], useImages=False)
    self.valueEntry.grid(row=row, column=1, columnspan=2, sticky='ew')
    row += 1

    label = Label(frame, text='(requires comma-separated list, of length number of points)')
    label.grid(row=row, column=1, columnspan=2, sticky='w')
    row += 1

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

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

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

    fileName = fileSelectPopup.file_select.getFile()
    
    fileObj = open(fileName, 'rU')
    
    data = ''
    line = fileObj.readline()
    while line:
      data += line
      line = fileObj.readline()
    
    data = re.sub(',\s+', ',', data)
    data = re.sub('\s+', ',', data)
    data = re.sub(',,', ',', data)
    data = re.sub('[^0-9,.\-+eE]', '', data)
      
    self.valueEntry.set(data)

  def copyValues(self):

    expt = self.pseudoList.getObject()
    if expt:
      dataDim = getExperimentSampledDim(expt)
      values = dataDim.pointValues
      self.nptsEntry.set(len(values))
      self.valueEntry.set(values)

  def updateParams(self):

    params = self.params
    if self.pseudoButton.get() == self.pseudoEntries[0]:
      npts = self.nptsEntry.get()
      params.npts[self.dim] = npts
      values = self.valueEntry.get()
      try:
        params.setSampledDim(self.dim, values)
      except ApiError, e:
        showError('Set Sampled Dim', e.error_msg, parent=self)
        return
    else:
示例#8
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
示例#9
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)
示例#10
0
class CingFrame(NmrCalcRunFrame):
    def __init__(self, parent, application, *args, **kw):

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

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

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

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

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

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

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

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

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

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

        # # # # # # Submission frame # # # # # #

        tab = self.tabbedFrame.frames[1]
        tab.expandGrid(1, 0)

        frame = LabelFrame(tab, text='Server Job Submission', grid=(0, 0))
        frame.expandGrid(None, 2)

        srow = 0
        label = Label(frame, text='iCing URL:', grid=(srow, 0))
        self.iCingBaseUrlPulldown = PulldownList(
            frame,
            texts=URLS,
            objects=URLS,
            index=0,
            grid=(srow, 1),
            tipText='Web location of iCING server to use')

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

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

        srow += 1
        tipTexts = [
            'Submit the CCPN project to the CING server',
            'Determin whether the iCING job is complete, pending or has failed',
            'Remove all trace of the last submissionfrom the iCING server',
            'Download the compressed CING results, including HTML'
        ]
        texts = [
            'Submit Project!', 'Check Run Status', 'Purge Server Result',
            'Download Results'
        ]
        commands = [
            self.runCingServer, self.checkStatus, self.purgeCingServer,
            self.downloadResults
        ]

        self.buttonBar = ButtonList(frame,
                                    texts=texts,
                                    commands=commands,
                                    grid=(srow, 0),
                                    gridSpan=(1, 3),
                                    tipTexts=tipTexts)

        for button in self.buttonBar.buttons[:1]:
            button.config(bg=CING_BLUE)

        # # # # # # Residue frame # # # # # #

        frame = LabelFrame(tab, text='Residue Options', grid=(1, 0))
        frame.expandGrid(1, 1)

        label = Label(frame, text='Chain: ')
        label.grid(row=0, column=0, sticky='w')
        self.chainPulldown = PulldownList(
            frame,
            callback=self.changeChain,
            tipText='Select the molecular system chain to consider')
        self.chainPulldown.grid(row=0, column=1, sticky='w')

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

        tipTexts = [
            'Use the selected residues in the analysis',
            'Do not use the selected residues in the analysis'
        ]
        texts = ['Activate Selected', 'Inactivate Selected']
        commands = [self.activateResidues, self.deactivateResidues]
        self.resButtons = ButtonList(frame,
                                     texts=texts,
                                     commands=commands,
                                     tipTexts=tipTexts)
        self.resButtons.grid(row=2, column=0, columnspan=2, sticky='ew')
        """
    # # # # # # Validate frame # # # # # #

    frame = LabelFrame(tab, text='Validation Options', grid=(2,0))
    frame.expandGrid(None,2)

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

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

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

    srow += 1
    self.selectCheckScript = CheckButton(frame)
    self.selectCheckScript.grid(row=srow, column=0,sticky='nw' )
    self.selectCheckScript.set(False)
    label = Label(frame, text='User Python script\n(overriding option)')
    label.grid(row=srow,column=1,sticky='nw')

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

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

        # # # # # # # # # #

        self.update(calcStore)

        self.administerNotifiers(application.registerNotify)

    def downloadResults(self):

        if not self.run:
            msg = 'No current iCing run'
            showWarning('Failure', msg, parent=self)
            return

        credentials = self.serverCredentials
        if not credentials:
            msg = 'No current iCing server job'
            showWarning('Failure', msg, parent=self)
            return

        fileName = self.resultFileEntry.get()
        if not fileName:
            msg = 'No save file specified'
            showWarning('Failure', msg, parent=self)
            return

        if os.path.exists(fileName):
            msg = 'File %s already exists. Overwite?' % fileName
            if not showOkCancel('Query', msg, parent=self):
                return

        url = self.iCingBaseUrl
        iCingUrl = self.getServerUrl(url)
        logText = iCingRobot.iCingFetch(credentials, url, iCingUrl, fileName)
        print logText

        msg = 'Results saved to file %s\n' % fileName
        msg += 'Purge results from iCing server?'
        if showYesNo('Query', msg, parent=self):
            self.purgeCingServer()

    def getServerUrl(self, baseUrl):

        iCingUrl = os.path.join(baseUrl, 'icing/icing/serv/iCingServlet')
        return iCingUrl

    def viewHtmlResults(self):

        resultsUrl = self.resultsUrl
        if not resultsUrl:
            msg = 'No current iCing results URL'
            showWarning('Failure', msg, parent=self)
            return

        webBrowser = WebBrowser(self.application, popup=self.application)
        webBrowser.open(self.resultsUrl)

    def runCingServer(self):

        if not self.project:
            return

        run = self.run
        if not run:
            msg = 'No CING run setup'
            showWarning('Failure', msg, parent=self)
            return

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

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

        residueData = self.getResidueData()
        if not (residueData and residueData.residues):
            msg = 'No active residues selected in structure'
            showWarning('Failure', msg, parent=self)
            return

        url = self.iCingBaseUrlPulldown.getObject()
        url.strip()
        if not url:
            msg = 'No iCing server URL specified'
            showWarning('Failure', msg, parent=self)
            self.iCingBaseUrl = None
            return

        msg = 'Submit job now? You will be informed when the job is done.'
        if not showOkCancel('Confirm', msg, parent=self):
            return

        self.run.status = 'pending'

        self.iCingBaseUrl = url
        iCingUrl = self.getServerUrl(url)
        self.serverCredentials, results, tarFileName = iCingRobot.iCingSetup(
            self.project, userId='ccpnAp', url=iCingUrl)

        if not results:
            # Message already issued on failure
            self.run.status = 'failed'
            self.serverCredentials = None
            self.resultsUrl = None
            self.update()
            return

        else:
            credentials = self.serverCredentials
            os.unlink(tarFileName)

        entryId = iCingRobot.iCingProjectName(credentials, iCingUrl).get(
            iCingRobot.RESPONSE_RESULT)
        baseUrl, htmlUrl, logUrl, zipUrl = iCingRobot.getResultUrls(
            credentials, entryId, url)

        self.resultsUrl = htmlUrl

        # Save server data in this run for persistence

        setRunParameter(run, iCingRobot.FORM_USER_ID,
                        self.serverCredentials[0][1])
        setRunParameter(run, iCingRobot.FORM_ACCESS_KEY,
                        self.serverCredentials[1][1])
        setRunParameter(run, ICING_BASE_URL, url)
        setRunParameter(run, HTML_RESULTS_URL, htmlUrl)
        self.update()

        #run.inputStructures = structure.sortedModels()

        # select residues from the structure's chain
        #iCingRobot.iCingResidueSelection(credentials, iCingUrl, residueText)

        # Select models from ensemble
        #iCingRobot.iCingEnsembleSelection(credentials, iCingUrl, ensembleText)

        # Start the actual run
        self.serverDone = False
        iCingRobot.iCingRun(credentials, iCingUrl)

        # Fetch server progress occasionally, report when done
        # this function will call itself again and again
        self.after(CHECK_INTERVAL, self.timedCheckStatus)

        self.update()

    def timedCheckStatus(self):

        if not self.serverCredentials:
            return

        if self.serverDone:
            return

        status = iCingRobot.iCingStatus(self.serverCredentials,
                                        self.getServerUrl(self.iCingBaseUrl))

        if not status:
            #something broke, already warned
            self.run.status = 'failed'
            return

        result = status.get(iCingRobot.RESPONSE_RESULT)
        if result == iCingRobot.RESPONSE_DONE:
            self.serverDone = True
            self.run.status = 'completed'
            msg = 'CING run is complete!'
            showInfo('Completion', msg, parent=self)
            return

        self.after(CHECK_INTERVAL, self.timedCheckStatus)

    def checkStatus(self):

        if not self.serverCredentials:
            return

        status = iCingRobot.iCingStatus(self.serverCredentials,
                                        self.getServerUrl(self.iCingBaseUrl))

        if not status:
            #something broke, already warned
            return

        result = status.get(iCingRobot.RESPONSE_RESULT)
        if result == iCingRobot.RESPONSE_DONE:
            msg = 'CING run is complete!'
            showInfo('Completion', msg, parent=self)
            self.serverDone = True
            return

        else:
            msg = 'CING job is not done.'
            showInfo('Processing', msg, parent=self)
            self.serverDone = False
            return

    def purgeCingServer(self):

        if not self.project:
            return

        if not self.run:
            msg = 'No CING run setup'
            showWarning('Failure', msg, parent=self)
            return

        if not self.serverCredentials:
            msg = 'No current iCing server job'
            showWarning('Failure', msg, parent=self)
            return

        url = self.iCingBaseUrl
        results = iCingRobot.iCingPurge(self.serverCredentials,
                                        self.getServerUrl(url))

        if results:
            showInfo('Info', 'iCing server results cleared')
            self.serverCredentials = None
            self.iCingBaseUrl = None
            self.serverDone = False
            deleteRunParameter(self.run, iCingRobot.FORM_USER_ID)
            deleteRunParameter(self.run, iCingRobot.FORM_ACCESS_KEY)
            deleteRunParameter(self.run, HTML_RESULTS_URL)
        else:
            showInfo('Info', 'Purge failed')

        self.update()

    def chooseZipFile(self):

        fileTypes = [
            FileType('Zip', ['*.zip']),
        ]
        popup = FileSelectPopup(self,
                                file_types=fileTypes,
                                file=self.resultFileEntry.get(),
                                title='Results zip file location',
                                dismiss_text='Cancel',
                                selected_file_must_exist=False)

        fileName = popup.getFile()

        if fileName:
            self.resultFileEntry.set(fileName)
        popup.destroy()

    def setZipFileName(self):

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

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

        self.model = model

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

        self.residue = residue

    def getResidueData(self):

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

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

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

        return dataObj

    def getStructureData(self):

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

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

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

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

        return dataObj

    def deactivateResidues(self):

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

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

                if seqId in seqIds:
                    seqIds.remove(seqId)

            seqIds = list(seqIds)
            seqIds.sort()

            dataObj.residueSeqIds = seqIds

            self.updateResidues()

    def activateResidues(self):

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

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

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

                seqIds = list(seqIds)
                seqIds.sort()

                dataObj.residueSeqIds = seqIds

            self.updateResidues()

    def activateModels(self):

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

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

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

            serials = list(serials)
            serials.sort()

            dataObj.modelSerials = serials

            self.updateModels()

    def disableModels(self):

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

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

                if serial in serials:
                    serials.remove(serial)

            serials = list(serials)
            serials.sort()

            dataObj.modelSerials = serials

            self.updateModels()

    def toggleModel(self, *opt):

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

            serial = self.model.serial

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

            serials = list(serials)
            serials.sort()

            dataObj.modelSerials = serials

            self.updateModels()

    def toggleResidue(self, *opt):

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

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

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

            self.updateResidues()

    def updateResidues(self):

        if self.residue and (self.residue.topObject is not self.structure):
            self.residue = None

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

        if self.chain:
            resDataObj = self.getResidueData()
            selectedRes = set(resDataObj.residues)
            chainCode = self.chain.code

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

                if msResidue in selectedRes:
                    colors = [None, None, None, None, CING_BLUE]
                    use = 'Yes'

                else:
                    colors = [None, None, None, None, None]
                    use = 'No'

                datum = [
                    residue.seqCode,
                    msResidue.ccpCode,
                    msResidue.linking,
                    msResidue.descriptor,
                    use,
                ]

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

        self.residueMatrix.update(objectList=objectList,
                                  textMatrix=textMatrix,
                                  colorMatrix=colorMatrix)

    def updateChains(self):

        index = 0
        names = []
        chains = []
        chain = self.chain

        if self.structure:
            chains = self.structure.sortedCoordChains()
            names = [chain.code for chain in chains]

            if chains:
                if chain not in chains:
                    chain = chains[0]
                    index = chains.index(chain)

                self.changeChain(chain)

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

    def updateStructures(self):

        index = 0
        names = []
        structures = []
        structure = self.structure

        if self.run:
            structures0 = [(s.ensembleId, s)
                           for s in self.project.structureEnsembles]
            structures0.sort()

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

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

            index = structures.index(structure)

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

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

    def updateModels(self, obj=None):

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

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

            for model in self.structure.sortedModels():

                if model.serial in selectedSerials:
                    colors = [None, CING_BLUE]
                    use = 'Yes'

                else:
                    colors = [None, None]
                    use = 'No'

                datum = [model.serial, use]

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

        self.modelTable.update(objectList=objectList,
                               textMatrix=textMatrix,
                               colorMatrix=colorMatrix)

    def changeStructure(self, structure):

        if self.project and (self.structure is not structure):
            self.project.currentEstructureEnsemble = structure
            self.structure = structure

            if self.run:
                dataObj = self.getStructureData()
                serials = set(dataObj.modelSerials)
                serials2 = set([m.serial for m in structure.models])
                serials = list(serials & serials2)
                serials.sort()

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

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

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

            self.updateModels()
            self.updateChains()

    def changeChain(self, chain):

        if self.project and (self.chain is not chain):
            self.chain = chain
            self.updateResidues()

    #def chooseValidScript(self):
    #
    #  # Prepend default Cyana file extension below
    #  fileTypes = [  FileType('Python', ['*.py']), ]
    #  popup = FileSelectPopup(self, file_types = fileTypes,
    #                          title='Python file', dismiss_text='Cancel',
    #                          selected_file_must_exist = True)

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

    def updateAll(self, project=None):

        if project:
            self.project = project
            self.nmrProject = nmrProject = project.currentNmrProject
            calcStore = project.findFirstNmrCalcStore(name='CING', nmrProject=nmrProject) or \
                        project.newNmrCalcStore(name='CING', nmrProject=nmrProject)
        else:
            calcStore = None

        if not self.project:
            return

        self.setZipFileName()
        if not self.project.currentNmrProject:
            name = self.project.name
            self.nmrProject = self.project.newNmrProject(name=name)
        else:
            self.nmrProject = self.project.currentNmrProject

        self.update(calcStore)

    def update(self, calcStore=None):

        NmrCalcRunFrame.update(self, calcStore)

        run = self.run
        urls = URLS
        index = 0

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

            url = getRunTextParameter(run, ICING_BASE_URL)
            if url:
                htmlUrl = getRunTextParameter(run, HTML_RESULTS_URL)
                self.iCingBaseUrl = url
                self.resultsUrl = htmlUrl  # May be None

            self.resultUrlEntry.set(self.resultsUrl)

            if self.iCingBaseUrl and self.iCingBaseUrl not in urls:
                index = len(urls)
                urls.append(self.iCingBaseUrl)

        self.iCingBaseUrlPulldown.setup(urls, urls, index)

        self.updateButtons()
        self.updateStructures()
        self.updateModels()
        self.updateChains()

    def updateButtons(self, event=None):

        buttons = self.buttonBar.buttons
        if self.project and self.run:
            buttons[0].enable()

            if self.resultsUrl and self.serverCredentials:
                buttons[1].enable()
                buttons[2].enable()
                buttons[3].enable()

            else:
                buttons[1].disable()
                buttons[2].disable()
                buttons[3].disable()

        else:
            buttons[0].disable()
            buttons[1].disable()
            buttons[2].disable()
            buttons[3].disable()
示例#11
0
class PrintFrame(LabelFrame):
    def __init__(self,
                 parent,
                 getOption=None,
                 setOption=None,
                 text='Print Options',
                 haveTicks=False,
                 doOutlineBox=True,
                 *args,
                 **kw):

        self.getOption = getOption
        self.setOption = setOption
        self.haveTicks = haveTicks
        self.doOutlineBox = doOutlineBox

        LabelFrame.__init__(self, parent=parent, text=text, *args, **kw)

        self.file_select_popup = None

        self.getOptionValues()

        try:
            size_index = self.paper_types.index(self.paper_type)
        except:
            size_index = 0

        try:
            other_unit_index = self.paper_units.index(self.other_unit)
        except:
            other_unit_index = 0

        try:
            orientation_index = self.paper_orientations.index(self.orientation)
        except:
            orientation_index = 0

        try:
            style_index = self.style_choices.index(self.output_style)
        except:
            style_index = 0

        try:
            format_index = self.format_choices.index(self.output_format)
        except:
            format_index = 0

        if haveTicks:
            try:
                tick_location_index = self.tick_locations.index(
                    self.tick_location)
            except:
                tick_location_index = 0

        self.grid_columnconfigure(2, weight=1)

        row = 0
        label = Label(self, text='File:')
        label.grid(row=row, column=0, sticky='e')
        self.file_entry = Entry(self, width=40, text=self.file_name)
        self.file_entry.grid(row=row, column=1, columnspan=2, sticky='ew')
        button = Button(self, text='Choose File', command=self.findFile)
        button.grid(row=row, column=3, rowspan=2, sticky='nsew')

        row += 1
        label = Label(self, text='Title:')
        label.grid(row=row, column=0, sticky='e')
        self.title_entry = Entry(self, width=40, text=self.title)
        self.title_entry.grid(row=row, column=1, columnspan=2, sticky='ew')

        row += 1
        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=4, sticky='ew')
        frame.grid_columnconfigure(4, weight=1)

        label = Label(frame, text='Paper size:')
        label.grid(row=0, column=0, sticky='e')
        entries = []
        for t in paper_types:
            if t == Output.other_paper_type:
                entry = t
            else:
                (w, h, u) = paper_sizes[t]
                entry = t + ' (%2.1f %s x %2.1f %s)' % (w, u, h, u)
            entries.append(entry)
        self.size_menu = PulldownList(frame,
                                      callback=self.changedSize,
                                      texts=entries,
                                      index=size_index)
        self.size_menu.grid(row=0, column=1, sticky='w')

        self.other_frame = Frame(frame)

        self.other_frame.grid_columnconfigure(0, weight=1)
        self.other_entry = FloatEntry(self.other_frame,
                                      text=self.other_size,
                                      isArray=True)
        self.other_entry.grid(row=0, column=0, sticky='ew')
        self.other_unit_menu = PulldownList(self.other_frame,
                                            texts=paper_units,
                                            index=other_unit_index)
        self.other_unit_menu.grid(row=0, column=1, sticky='ew')

        row += 1
        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=4, sticky='ew')
        frame.grid_columnconfigure(1, weight=1)
        frame.grid_columnconfigure(3, weight=1)
        frame.grid_columnconfigure(5, weight=1)

        label = Label(frame, text='Orientation:')
        label.grid(row=0, column=0, sticky='e')
        self.orientation_menu = PulldownList(frame,
                                             texts=paper_orientations,
                                             index=orientation_index)
        self.orientation_menu.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='  Style:')
        label.grid(row=0, column=2, sticky='e')
        self.style_menu = PulldownList(frame,
                                       texts=style_choices,
                                       index=style_index)
        self.style_menu.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='  Format:')
        label.grid(row=0, column=4, sticky='e')
        self.format_menu = PulldownList(frame,
                                        callback=self.changedFormat,
                                        texts=format_choices,
                                        index=format_index)

        self.format_menu.grid(row=0, column=5, sticky='w')

        if haveTicks:

            row += 1
            frame = Frame(self)
            frame.grid(row=row, column=0, columnspan=4, sticky='ew')
            frame.grid_columnconfigure(1, weight=1)
            frame.grid_columnconfigure(3, weight=1)

            label = Label(frame, text='Tick Location:')
            label.grid(row=0, column=0, sticky='e')
            self.tick_menu = PulldownList(frame,
                                          texts=tick_locations,
                                          index=tick_location_index)
            self.tick_menu.grid(row=0, column=1, sticky='w')

            label = Label(frame, text='  Tick Placement:')
            label.grid(row=0, column=2, sticky='e')
            self.tick_buttons = CheckButtons(frame,
                                             entries=tick_placements,
                                             selected=self.tick_placement)
            self.tick_buttons.grid(row=0, column=3, sticky='w')

        row += 1
        frame = Frame(self)
        frame.grid(row=row, column=0, columnspan=4, sticky='ew')
        frame.grid_columnconfigure(3, weight=1)

        label = Label(frame, text='Include:')
        label.grid(row=0, column=0, sticky='e')
        self.border_buttons = CheckButtons(frame,
                                           entries=border_decorations,
                                           selected=self.border_decoration)
        self.border_buttons.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='  Scaling:')
        label.grid(row=0, column=2, sticky='e')
        self.scaling_scale = Scale(frame,
                                   orient=Tkinter.HORIZONTAL,
                                   value=self.scaling)
        self.scaling_scale.grid(row=0, column=3, sticky='ew')

    def destroy(self):

        self.setOptionValues()

        if self.file_select_popup:
            self.file_select_popup.destroy()

        Frame.destroy(self)

    def getOptionValues(self):

        getOption = self.getOption
        if getOption:

            file_name = getOption('FileName', defaultValue='')
            title = getOption('Title', defaultValue='')
            paper_type = getOption('PaperSize', defaultValue=paper_types[0])
            paper_type = paper_type_dict.get(paper_type, paper_types[0])
            other_height = getOption('OtherHeight', defaultValue=10)
            other_width = getOption('OtherWidth', defaultValue=10)
            other_size = [other_height, other_width]
            other_unit = getOption('OtherUnit', defaultValue=paper_units[0])
            orientation = getOption('Orientation',
                                    defaultValue=paper_orientations[0])
            in_color = getOption('InColor', defaultValue=True)
            if in_color:
                output_style = style_choices[0]
            else:
                output_style = style_choices[1]
            format_option = getOption('OutputFormat',
                                      defaultValue=format_options[0])
            output_format = format_choices[format_options.index(format_option)]
            if self.haveTicks:
                tick_outside = getOption('TickOutside',
                                         defaultValue=tick_locations[0])
                if tick_outside:
                    tick_location = tick_locations.index(PrintTicks.Outside)
                else:
                    tick_location = tick_locations.index(PrintTicks.Inside)
                tick_placement = getTickPlacement1(
                    getOption('TickPlacement', defaultValue='nsew'))
            dateTime = getOption('ShowsDateTime', defaultValue=True)
            fileName = getOption('ShowsFileName', defaultValue=True)
            border_decoration = []
            if dateTime:
                border_decoration.append(border_decorations[0])
            if fileName:
                border_decoration.append(border_decorations[1])
            scaling = getOption('Scaling', defaultValue=0.9)
            scaling = int(round(100.0 * scaling))

        else:

            file_name = ''
            title = ''
            paper_type = paper_types[0]
            other_unit = paper_units[0]
            other_size = ''
            orientation = paper_orientations[0]
            output_style = style_choices[0]
            output_format = format_choices[0]
            if self.haveTicks:
                tick_location = tick_locations[0]
                tick_placement = tick_placements
            border_decoration = border_decorations
            scaling = 90

        if not self.haveTicks:
            tick_location = None
            tick_placement = None

        self.file_name = file_name
        self.title = title
        self.paper_type = paper_type
        self.other_unit = other_unit
        self.other_size = other_size
        self.orientation = orientation
        self.output_style = output_style
        self.output_format = output_format
        self.tick_location = tick_location
        self.tick_placement = tick_placement
        self.border_decoration = border_decoration
        self.scaling = scaling

    def setOptionValues(self):

        self.file_name = file_name = self.file_entry.get()
        self.title = title = self.title_entry.get()

        n = self.size_menu.getSelectedIndex()
        self.paper_type = paper_type = paper_types[n]
        if paper_type == Output.other_paper_type:
            other_size = self.other_entry.get()
            other_unit = self.other_unit_menu.getText()
        else:
            other_size = None
            other_unit = None
        self.other_size = other_size
        self.other_unit = other_unit

        self.paper_orientation = paper_orientation = self.orientation_menu.getText(
        )
        self.output_style = output_style = self.style_menu.getText()
        self.output_format = output_format = self.format_menu.getText()

        if self.haveTicks:
            tick_location = self.tick_menu.getText()
            tick_placement = self.tick_buttons.getSelected()
        else:
            tick_location = tick_placement = None
        self.tick_location = tick_location
        self.tick_placement = tick_placement

        self.border_decoration = border_decoration = self.border_buttons.getSelected(
        )
        scaling = self.scaling_scale.get()
        self.scaling = scaling = int(round(scaling))

        setOption = self.setOption
        if setOption:
            setOption('FileName', value=file_name)
            setOption('Title', value=title)
            if paper_type == Output.other_paper_type:
                setOption('OtherHeight', value=other_size[0])
                setOption('OtherWidth', value=other_size[1])
                setOption('OtherUnit', value=other_unit)
            else:
                paper_type = paper_type_inverse_dict[paper_type]
                setOption('PaperSize', value=paper_type)
            setOption('Orientation', value=paper_orientation)
            in_color = (output_style == style_choices[0])
            setOption('InColor', value=in_color)
            output_format = format_options[format_choices.index(output_format)]
            setOption('OutputFormat', value=output_format)
            if self.haveTicks:
                tick_outside = (tick_location == PrintTicks.Outside)
                setOption('TickOutside', value=tick_outside)
                tick_placement = getTickPlacement2(tick_placement)
                setOption('TickPlacement', value=tick_placement)
            dateTime = (border_decorations[0] in border_decoration)
            fileName = (border_decorations[1] in border_decoration)
            setOption('ShowsDateTime', value=dateTime)
            setOption('ShowsFileName', value=fileName)
            setOption('Scaling', value=0.01 * scaling)

    def findFile(self):

        if self.file_select_popup:
            self.file_select_popup.open()
        else:
            file_types = [
                FileType('All', ['*']),
                FileType('PostScript', ['*.ps', '*.eps']),
                FileType('PDF', ['*.pdf', '*.ai'])
            ]
            self.file_select_popup = FileSelectPopup(self,
                                                     file_types=file_types)

        file = self.file_select_popup.getFile()
        if file:
            self.file_entry.set(file)

    def changedSize(self, entry):

        if entry == Output.other_paper_type:
            self.other_frame.grid(row=0, column=2, columnspan=2, sticky='w')
        else:
            self.other_frame.grid_forget()

    def changedFormat(self, entry):

        file_suffix = file_suffixes.get(entry)
        if not file_suffix:
            return

        file_name = self.file_entry.get()
        if not file_name:
            return

        for suffix in format_suffixes:
            if file_name.endswith(suffix):
                if suffix != file_suffix:
                    n = len(suffix)
                    file_name = file_name[:-n] + file_suffix
                    self.file_entry.set(file_name)
                break
        else:
            file_name = file_name + file_suffix
            self.file_entry.set(file_name)

    # width and height are of plot, in pixels
    def getOutputHandler(self, width, height, fonts=None):

        if not fonts:
            fonts = []
        else:
            fonts = list(fonts)

        for n in range(len(fonts)):
            if fonts[n] == 'Times':
                fonts[n] = 'Times-Roman'

        self.setOptionValues()

        if not self.file_name:
            showError('No file', 'No file specified', parent=self)
            return None

        if os.path.exists(self.file_name):
            if not showYesNo('File exists',
                             'File "%s" exists, overwrite?' % self.file_name,
                             parent=self):
                return None

        if (self.paper_type == Output.other_paper_type):
            paper_size = self.other_size + [self.other_unit]
        else:
            paper_size = paper_sizes[self.paper_type]
        output_scaling = self.scaling / 100.0

        font = 'Times-Roman'
        border_text = {}
        for decoration in self.border_decoration:
            if (decoration == 'Time & date'):
                location = 'se'
                text = time.ctime(time.time())
            elif (decoration == 'File name'):
                location = 'sw'
                text = self.file_name
            else:
                continue  # should not be here
            border_text[location] = (text, font, 12)
        if (self.title):
            location = 'n'
            border_text[location] = (self.title, font, 18)

        if font not in fonts:
            fonts.append(font)

        outputHandler = PrintHandler.getOutputHandler(
            self.file_name,
            width,
            height,
            output_scaling=output_scaling,
            paper_size=paper_size,
            paper_orientation=self.paper_orientation,
            output_style=self.output_style,
            output_format=self.output_format,
            border_text=border_text,
            fonts=fonts,
            do_outline_box=self.doOutlineBox)

        return outputHandler

    def getAspectRatio(self):

        self.setOptionValues()

        if self.paper_type == Output.other_paper_type:
            paper_size = self.other_size
        else:
            paper_size = paper_sizes[self.paper_type]

        r = paper_size[1] / paper_size[0]
        if self.paper_orientation == 'Landscape':
            r = 1.0 / r

        return r
示例#12
0
class PrintFrame(Frame):

  def __init__(self, parent, getOption = None, setOption = None,
               haveTicks = False, doOutlineBox = True, *args, **kw):

    self.getOption = getOption
    self.setOption = setOption
    self.haveTicks = haveTicks
    self.doOutlineBox = doOutlineBox

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

    self.file_select_popup = None

    self.getOptionValues()

    try:
      size_index = paper_types.index(self.paper_type)
    except:
      size_index = 0

    try:
      other_unit_index = paper_units.index(self.other_unit)
    except:
      other_unit_index = 0

    try:
      orientation_index = paper_orientations.index(self.paper_orientation)
    except:
      orientation_index = 0

    try:
      style_index = style_choices.index(self.output_style)
    except:
      style_index = 0

    try:
      format_index = format_choices.index(self.output_format)
    except:
      format_index = 0

    if haveTicks:
      try:
        tick_location_index = tick_locations.index(self.tick_location)
      except:
        tick_location_index = 0

    self.grid_columnconfigure(1, weight=1)

    row = 0
    button = Button(self, text='File:', command=self.findFile,
                    tipText='Select location to save print file')
    button.grid(row=row, column=0, sticky='e')
    self.file_entry = Entry(self, width=40, text=self.file_name,
                tipText='Location where file is saved on disk')
    self.file_entry.grid(row=row, column=1, sticky='ew')

    row += 1
    label = Label(self, text='Title:')
    label.grid(row=row, column=0, sticky='e')
    self.title_entry = Entry(self, width=40, text=self.title,
                    tipText='Title of the printout, displayed at top')
    self.title_entry.grid(row=row, column=1, sticky='ew')

    row += 1
    label = Label(self, text='X axis label:')
    label.grid(row=row, column=0, sticky='e')
    self.x_axis_entry = Entry(self, width=40, text=self.x_axis_label,
                    tipText='X axis label for the printout')
    self.x_axis_entry.grid(row=row, column=1, sticky='ew')

    row += 1
    label = Label(self, text='Y axis label:')
    label.grid(row=row, column=0, sticky='e')
    self.y_axis_entry = Entry(self, width=40, text=self.y_axis_label,
                    tipText='Y axis label for the printout')
    self.y_axis_entry.grid(row=row, column=1, sticky='ew')

    row += 1
    frame = Frame(self)
    frame.grid(row=row, column=0, columnspan=2, sticky='ew')
    frame.grid_columnconfigure(4, weight=1)
    
    label = Label(frame, text='Paper size:')
    label.grid(row=0, column=0, sticky='e')
    entries = []
    for t in paper_types:
      if t == Output.other_paper_type:
        entry = t
      else:
        (w, h, u) = paper_sizes[t]
        entry = t + ' (%2.1f %s x %2.1f %s)' % (w, u, h, u)
      entries.append(entry)
    self.size_menu = PulldownList(frame, callback=self.changedSize,
                                  texts=entries, index=size_index,
                                  tipText='The paper size for the printout')
    self.size_menu.grid(row=0, column=1, sticky='w')

    self.other_frame = Frame(frame)

    self.other_frame.grid_columnconfigure(0, weight=1)
    self.other_entry = FloatEntry(self.other_frame, text=self.other_size,
                                  isArray=True,
                                  tipText='The size of the Other paper in both dimensions; this requires two values, space or comma separated')
    self.other_entry.grid(row=0, column=0, sticky='ew')
    self.other_unit_menu= PulldownList(self.other_frame, texts=paper_units,
                                       index=other_unit_index,
                                       tipText='The unit for the Other paper size')
    self.other_unit_menu.grid(row=0, column=1, sticky='ew')

    row += 1
    frame = Frame(self)
    frame.grid(row=row, column=0, columnspan=4, sticky='ew')
    frame.grid_columnconfigure(1, weight=1)
    frame.grid_columnconfigure(3, weight=1)
    frame.grid_columnconfigure(5, weight=1)

    label = Label(frame, text='Orientation:')
    label.grid(row=0, column=0, sticky='e')
    self.orientation_menu = PulldownList(frame, texts=paper_orientations,
                                         index=orientation_index,
                                         tipText='Whether the paper should be set in Portrait or Landscape mode')
    self.orientation_menu.grid(row=0, column=1, sticky='w')

    label = Label(frame, text='  Style:')
    label.grid(row=0, column=2, sticky='e')
    self.style_menu = PulldownList(frame, texts=style_choices,
                                   index=style_index,
                                   tipText='Whether the printout should be in colour or black and white')
    self.style_menu.grid(row=0, column=3, sticky='w')

    label = Label(frame, text='  Format:')
    label.grid(row=0, column=4, sticky='e')
    self.format_menu = PulldownList(frame, callback=self.changedFormat,
                                    texts=format_choices, index=format_index,
                                    tipText='Whether to save as PS, EPS or PDF')

    self.format_menu.grid(row=0, column=5, sticky='w')

    if haveTicks:

      row += 1
      frame = Frame(self)
      frame.grid(row=row, column=0, columnspan=4, sticky='ew')
      frame.grid_columnconfigure(1, weight=1)
      frame.grid_columnconfigure(3, weight=1)
      
      label = Label(frame, text='Tick Location:')
      label.grid(row=0, column=0, sticky='e')
      self.tick_menu = PulldownList(frame, texts=tick_locations,
                                    index=tick_location_index,
                                    tipText='Whether the tick marks appear on the inside or outside of the frame')
      self.tick_menu.grid(row=0, column=1, sticky='w')

      label = Label(frame, text='  Tick Placement:')
      label.grid(row=0, column=2, sticky='e')
      if self.tick_placement is None:
        selected = None
      else:
        selected = [(x in self.tick_placement) for x in tick_placements]
      self.tick_buttons = CheckButtons(frame, entries=tick_placements,
                                       selected=selected,
                                       tipTexts=('Whether the tick marks appear on the top and/or bottom and/or left and/or right',))
      self.tick_buttons.grid(row=0, column=3, sticky='w')

      row += 1
      frame = Frame(self)
      frame.grid(row=row, column=0, columnspan=4, sticky='ew')
      frame.grid_columnconfigure(1, weight=1)
      frame.grid_columnconfigure(3, weight=1)
      
      label = Label(frame, text='Tick Font:')
      label.grid(row=0, column=0, sticky='e')
      self.tick_font_list = FontList(frame, mode='Print',
                            selected=self.tick_font,
                            extraTexts=[PrintTicks.no_tick_text],
                            tipText='The font used for the tick mark labels')
      self.tick_font_list.grid(row=0, column=1, sticky='w')

      label = Label(frame, text='Tick Spacing:')
      label.grid(row=0, column=2, sticky='e')
      # TBD: put preferred choice in data model
      self.spacing_menu = PulldownList(frame, texts=spacing_choices, index=0,
                                       callback=self.changedSpacing,
                                       tipText='Whether the program should automatically calculate the major/minor tick spacings and how many decimal places are used for the ticks, or whether the these are specified manually')
      self.spacing_menu.grid(row=0, column=3, sticky='w')

      ff = self.spacing_frame = Frame(frame)
      ff.grid_columnconfigure(1, weight=1)
      ff.grid_columnconfigure(2, weight=1)
      label = Label(ff, text='Tick Spacing')
      label.grid(row=0, column=0, sticky='w')
      label = Label(ff, text='Major')
      label.grid(row=0, column=1, sticky='ew')
      label = Label(ff, text='Minor')
      label.grid(row=0, column=2, sticky='ew')
      label = Label(ff, text='Decimals')
      label.grid(row=0, column=3, sticky='ew')
      label = Label(ff, text='X:')
      label.grid(row=1, column=0, sticky='w')
      self.x_major_entry = FloatEntry(ff, tipText='The spacing in display units of the major tick marks in the X dimension')
      self.x_major_entry.grid(row=1, column=1, sticky='ew')
      self.x_minor_entry = FloatEntry(ff, tipText='The spacing in display units of the minor tick marks in the X dimension (not printed if left blank)')
      self.x_minor_entry.grid(row=1, column=2, sticky='ew')
      self.x_decimal_entry = IntEntry(ff, tipText='The number of decimal places for the tick numbers in the X dimension')
      self.x_decimal_entry.grid(row=1, column=3, sticky='ew')
      label = Label(ff, text='Y:')
      label.grid(row=2, column=0, sticky='w')
      self.y_major_entry = FloatEntry(ff, tipText='The spacing in display units of the major tick marks in the Y dimension')
      self.y_major_entry.grid(row=2, column=1, sticky='ew')
      self.y_minor_entry = FloatEntry(ff, tipText='The spacing in display units of the minor tick marks in the Y dimension (not printed if left blank)')
      self.y_minor_entry.grid(row=2, column=2, sticky='ew')
      self.y_decimal_entry = IntEntry(ff, tipText='The number of decimal places for the tick numbers in the Y dimension')
      self.y_decimal_entry.grid(row=2, column=3, sticky='ew')

      row += 1
      frame = Frame(self)
      frame.grid(row=row, column=0, columnspan=4, sticky='ew')
      frame.grid_columnconfigure(1, weight=1)
      
      label = Label(frame, text='Tick Length:')
      label.grid(row=0, column=0, sticky='e')
      # TBD: put preferred choice in data model
      self.tick_length_menu = PulldownList(frame, texts=tick_length_choices, index=0,
                                       callback=self.changedLength,
                                       tipText='Whether the program should automatically calculate the major/minor tick lengths, or whether the these are specified manually')
      self.tick_length_menu.grid(row=0, column=1, sticky='w')

      ff = self.length_frame = Frame(frame)
      ff.grid_columnconfigure(1, weight=1)
      label = Label(ff, text='  Major length:')
      label.grid(row=0, column=0, sticky='w')
      self.length_major_entry = FloatEntry(ff, tipText='The length in points of the major tick marks')
      self.length_major_entry.grid(row=0, column=1, sticky='w')
      label = Label(ff, text='Minor length:')
      label.grid(row=0, column=2, sticky='w')
      self.length_minor_entry = FloatEntry(ff, tipText='The length in points of the minor tick marks')
      self.length_minor_entry.grid(row=0, column=3, sticky='w')

    row += 1
    frame = Frame(self)
    frame.grid(row=row, column=0, columnspan=4, sticky='ew')
    frame.grid_columnconfigure(3, weight=1)
    frame.grid_columnconfigure(4, weight=1)

    label = Label(frame, text='Scaling:')
    label.grid(row=0, column=0, sticky='e')
    # TBD: put preferred choice in data model
    self.scaling_menu = PulldownList(frame, texts=scaling_choices, index=0,
                                     callback=self.changedScaling,
                                     tipText='Whether the plot should be scaled as a percentage of the maximum size that would fit on the paper, or instead should be specified by the number of cms or inches per unit')
    self.scaling_menu.grid(row=0, column=1, sticky='ew')

    self.scaling_scale = Scale(frame, orient=Tkinter.HORIZONTAL, value=self.scaling, tipText='The percentage of the maximum size that would fit on the paper that the plot is scaled by')
    self.scaling_scale.grid(row=0, column=2, columnspan=3, sticky='ew')

    self.x_scaling_label = Label(frame, text='X:')
    self.x_scaling_entry = FloatEntry(frame, tipText='The scaling that should be used in the X dimension as cms or inches per unit')
    self.y_scaling_label = Label(frame, text='Y:')
    self.y_scaling_entry = FloatEntry(frame, tipText='The scaling that should be used in the Y dimension as cms or inches per unit')

    row += 1
    frame = Frame(self)
    frame.grid(row=row, column=0, columnspan=4, sticky='w')
    frame.grid_columnconfigure(2, weight=1)
  
    label = Label(frame, text='Include:')
    label.grid(row=0, column=0, sticky='e')
    tipTexts = ('Whether the time and date should be included in the printout',
                'Whether the file name should be included in the printout')
    if self.border_decoration is None:
      selected = None
    else:
      selected = [(x in self.border_decoration) for x in border_decorations]
    self.border_buttons = CheckButtons(frame, entries=border_decorations,
                                       selected=selected,
                                       tipTexts=tipTexts)
    self.border_buttons.grid(row=0, column=1, sticky='w')

    label = Label(frame, text='    Using Font:')
    label.grid(row=0, column=2, sticky='e')
    self.border_font_list = FontList(frame, mode='Print',
                          selected=self.border_font,
                          tipText='The font used for the border texts')
    self.border_font_list.grid(row=0, column=3, sticky='w')

    row += 1
    label = Label(self, text='Line width:')
    label.grid(row=row, column=0, sticky='w')
    self.linewidth_entry = FloatEntry(self, width=10,
                                  text=self.linewidth,
                                  tipText='Line width for drawing')
    self.linewidth_entry.grid(row=row, column=1, sticky='w')
 
  def destroy(self):

    self.setOptionValues()

    if self.file_select_popup:
      self.file_select_popup.destroy()

    Frame.destroy(self)

  def getOptionValues(self):

    getOption = self.getOption
    if getOption:

      file_name = getOption('FileName', defaultValue='')
      title = getOption('Title', defaultValue='')
      x_axis_label = getOption('XAxisLabel', defaultValue='')
      y_axis_label = getOption('YAxisLabel', defaultValue='')
      paper_type = getOption('PaperSize', defaultValue=paper_types[0])
      paper_type = paper_type_dict.get(paper_type, paper_types[0])
      other_height = getOption('OtherHeight', defaultValue=10)
      other_width = getOption('OtherWidth', defaultValue=10)
      other_size = [other_height, other_width]
      other_unit = getOption('OtherUnit', defaultValue=paper_units[0])
      paper_orientation = getOption('Orientation', defaultValue=paper_orientations[0])
      in_color = getOption('InColor', defaultValue=True)
      if in_color:
        output_style = style_choices[0]
      else:
        output_style = style_choices[1]
      format_option = getOption('OutputFormat', defaultValue=format_options[0])
      output_format = format_choices[format_options.index(format_option)]
      if self.haveTicks:
        tick_outside = getOption('TickOutside', defaultValue=tick_locations[0])
        if tick_outside:
          tick_location = tick_locations.index(PrintTicks.Outside)
        else:
          tick_location = tick_locations.index(PrintTicks.Inside)
        tick_placement = getTickPlacement1(getOption('TickPlacement', defaultValue='nsew'))
      dateTime = getOption('ShowsDateTime', defaultValue=True)
      fileName = getOption('ShowsFileName', defaultValue=True)
      border_font = getOption('BorderFont', defaultValue='Helvetica 10')
      border_decoration = []
      if dateTime:
        border_decoration.append(border_decorations[0])
      if fileName:
        border_decoration.append(border_decorations[1])

      if self.haveTicks:
        spacing_choice = getOption('SpacingChoice', defaultValue=spacing_choices[0])
        x_major = getOption('XMajor', defaultValue=1.0)
        x_minor = getOption('XMinor', defaultValue=1.0)
        x_decimal = getOption('XDecimal', defaultValue=3)
        y_major = getOption('YMajor', defaultValue=1.0)
        y_minor = getOption('YMinor', defaultValue=1.0)
        y_decimal = getOption('YDecimal', defaultValue=3)

        tick_length_choice = getOption('TickLengthChoice', defaultValue=tick_length_choices[0])
        tick_major = getOption('TickMajor', defaultValue=10)
        tick_minor = getOption('TickMinor', defaultValue=5)

      scaling_choice = getOption('ScalingChoice', defaultValue=scaling_choices[0])
      scaling = getOption('Scaling', defaultValue=0.7)
      scaling = int(round(100.0 * scaling))
      x_scaling = getOption('XScaling', defaultValue=1.0)
      y_scaling = getOption('YScaling', defaultValue=1.0)

      if self.haveTicks:
        tick_font = getOption('TickFont', defaultValue='Helvetica 10')

      linewidth = getOption('LineWidth', defaultValue=Output.default_linewidth)

    else:
      file_name = ''
      title = ''
      x_axis_label = ''
      y_axis_label = ''
      paper_type = paper_types[0]
      other_unit = paper_units[0]
      other_size = ''
      paper_orientation = paper_orientations[0]
      output_style = style_choices[0]
      output_format = format_choices[0]
      if self.haveTicks:
        tick_location = tick_locations[0]
        tick_placement = tick_placements
      border_decoration = border_decorations
      border_font = 'Helvetica 10'
      if self.haveTicks:
        spacing_choice = spacing_choices[0]
        x_major = 1.0
        x_minor = 1.0
        x_decimal = 3
        y_major = 1.0
        y_minor = 1.0
        y_decimal = 3
        tick_length_choice = tick_length_choices[0]
        tick_major = 10
        tick_minor = 5
      scaling_choice = scaling_choices[0]
      scaling = 70
      x_scaling = 1.0
      y_scaling = 1.0
      if self.haveTicks:
        tick_font = 'Helvetica 10'
      linewidth = Output.default_linewidth

    if not self.haveTicks:
      tick_location = None
      tick_placement = None
      spacing_choice = spacing_choices[0]
      x_major = 1.0
      x_minor = 1.0
      x_decimal = 3
      y_major = 1.0
      y_minor = 1.0
      y_decimal = 3
      tick_font = 'Helvetica 10'
      tick_length_choice = tick_length_choices[0]
      tick_major = 10
      tick_minor = 5

    self.file_name = file_name
    self.title = title
    self.x_axis_label = x_axis_label
    self.y_axis_label = y_axis_label
    self.paper_type = paper_type
    self.other_unit = other_unit
    self.other_size = other_size
    self.paper_orientation = paper_orientation
    self.output_style = output_style
    self.output_format = output_format
    self.tick_location = tick_location
    self.tick_placement = tick_placement
    self.border_decoration = border_decoration
    self.border_font = border_font

    self.spacing_choice = spacing_choice
    self.x_major = x_major
    self.x_minor = x_minor
    self.x_decimal = x_decimal
    self.y_major = y_major
    self.y_minor = y_minor
    self.y_decimal = y_decimal

    self.scaling_choice = scaling_choices[0]
    self.scaling = scaling
    self.x_scaling = x_scaling
    self.y_scaling = y_scaling

    self.tick_font = tick_font
    self.linewidth = linewidth

    self.tick_length_choice = tick_length_choice
    self.tick_major = tick_major
    self.tick_minor = tick_minor

  def setOptionValues(self):

    if not hasattr(self, 'file_entry'):
      # it looks like on destroy can have function called but file_entry deleted already
      return

    self.file_name = file_name = self.file_entry.get()
    self.title = title = self.title_entry.get()
    self.x_axis_label = x_axis_label = self.x_axis_entry.get()
    self.y_axis_label = y_axis_label = self.y_axis_entry.get()

    n = self.size_menu.getSelectedIndex()
    self.paper_type = paper_type = paper_types[n]
    if paper_type == Output.other_paper_type:
      other_size = self.other_entry.get()
      other_unit = self.other_unit_menu.getText()
    else:
      other_size = None
      other_unit = None
    self.other_size = other_size
    self.other_unit = other_unit

    self.paper_orientation = paper_orientation = self.orientation_menu.getText()
    self.output_style = output_style = self.style_menu.getText()
    self.output_format = output_format = self.format_menu.getText()

    if self.haveTicks:
      tick_location = self.tick_menu.getText()
      tick_placement = self.tick_buttons.getSelected()
    else:
      tick_location = tick_placement = None
    self.tick_location = tick_location
    self.tick_placement = tick_placement

    self.border_decoration = border_decoration = self.border_buttons.getSelected()
    self.border_font = border_font = self.border_font_list.getText()

    if self.haveTicks:
      self.spacing_choice = spacing_choice = self.spacing_menu.getText()
      if spacing_choice != spacing_choices[0]:
        self.x_major = self.x_major_entry.get()
        self.x_minor = self.x_minor_entry.get()
        self.x_decimal = self.x_decimal_entry.get()
        self.y_major = self.y_major_entry.get()
        self.y_minor = self.y_minor_entry.get()
        self.y_decimal = self.y_decimal_entry.get()

      self.tick_length_choice = tick_length_choice = self.tick_length_menu.getText()
      if tick_length_choice != tick_length_choices[0]:
        self.tick_major = self.length_major_entry.get()
        self.tick_minor = self.length_minor_entry.get()

    self.scaling_choice = scaling_choice = self.scaling_menu.getText()
    if self.scaling_choice == scaling_choices[0]:
      scaling = self.scaling_scale.get()
      self.scaling = int(round(scaling))
    else:
      self.x_scaling = self.x_scaling_entry.get()
      self.y_scaling = self.y_scaling_entry.get()

    if self.haveTicks:
      self.tick_font = self.tick_font_list.getText()

    self.linewidth = self.linewidth_entry.get()

    setOption = self.setOption
    if setOption:
      setOption('FileName', value=file_name)
      setOption('Title', value=title)
      setOption('XAxisLabel', value=x_axis_label)
      setOption('YAxisLabel', value=y_axis_label)
      if paper_type == Output.other_paper_type:
        setOption('OtherHeight', value=other_size[0])
        setOption('OtherWidth', value=other_size[1])
        setOption('OtherUnit', value=other_unit)
      else:
        paper_type = paper_type_inverse_dict[paper_type]
        setOption('PaperSize', value=paper_type)
      setOption('Orientation', value=paper_orientation)
      in_color = (output_style == style_choices[0])
      setOption('InColor', value=in_color)
      output_format = format_options[format_choices.index(output_format)]
      setOption('OutputFormat', value=output_format)
      if self.haveTicks:
        tick_outside = (tick_location == PrintTicks.Outside)
        setOption('TickOutside', value=tick_outside)
        tick_placement = getTickPlacement2(tick_placement)
        setOption('TickPlacement', value=tick_placement)
      dateTime = (border_decorations[0] in border_decoration)
      fileName = (border_decorations[1] in border_decoration)
      setOption('ShowsDateTime', value=dateTime)
      setOption('ShowsFileName', value=fileName)
      setOption('BorderFont', value=border_font)

      if self.haveTicks:
        setOption('SpacingChoice', value=spacing_choice)
        if spacing_choice != spacing_choices[0]:
          setOption('XMajor', self.x_major)
          setOption('XMinor', self.x_minor)
          setOption('XDecimal', self.x_decimal)
          setOption('YMajor', self.y_major)
          setOption('YMinor', self.y_minor)
          setOption('YDecimal', self.y_decimal)

        setOption('TickLengthChoice', value=tick_length_choice)
        if tick_length_choice != tick_length_choices[0]:
          setOption('TickMajor', self.tick_major)
          setOption('TickMinor', self.tick_minor)

      setOption('ScalingChoice', value=scaling_choice)
      if scaling_choice == scaling_choices[0]:
        setOption('Scaling', value=0.01*self.scaling)
      else:
        setOption('XScaling', value=self.x_scaling)
        setOption('YScaling', value=self.y_scaling)

      if self.haveTicks:
        setOption('TickFont', self.tick_font)

      setOption('LineWidth', self.linewidth)

  def findFile(self):

    if self.file_select_popup:
      self.file_select_popup.open()
    else:
      file_types = [ FileType('All', ['*']),
                     FileType('PostScript', ['*.ps', '*.eps']),
                     FileType('PDF', ['*.pdf', '*.ai']) ]
      self.file_select_popup = FileSelectPopup(self, file_types=file_types)

    file = self.file_select_popup.getFile()
    if file:
      self.file_entry.set(file)

  def changedSize(self, entry):

    if entry == Output.other_paper_type:
      self.other_frame.grid(row=0, column=2, columnspan=2, sticky='w')
    else:
      self.other_frame.grid_forget()

  def changedFormat(self, entry):

    file_suffix = file_suffixes.get(entry)
    if not file_suffix:
      return

    file_name = self.file_entry.get()
    if not file_name:
      return

    for suffix in format_suffixes:
      if file_name.endswith(suffix):
        if suffix != file_suffix:
          n = len(suffix)
          file_name = file_name[:-n] + file_suffix
          self.file_entry.set(file_name)
        break
    else:
      file_name = file_name + file_suffix
      self.file_entry.set(file_name)

  def changedScaling(self, choice):

    if choice == scaling_choices[0]:
      self.scaling_scale.grid(row=0, column=2, columnspan=3, sticky='ew')
      self.x_scaling_label.grid_forget()
      self.x_scaling_entry.grid_forget()
      self.y_scaling_label.grid_forget()
      self.y_scaling_entry.grid_forget()
    else:
      self.scaling_scale.grid_forget()
      self.x_scaling_label.grid(row=0, column=2, sticky='w')
      self.x_scaling_entry.grid(row=0, column=3, columnspan=2, sticky='ew')
      self.y_scaling_label.grid(row=1, column=2, sticky='w')
      self.y_scaling_entry.grid(row=1, column=3, columnspan=2, sticky='ew')

    self.setOptionValues()

  def changedSpacing(self, choice):

    if choice == spacing_choices[0]:
      self.spacing_frame.grid_forget()
    else:
      self.spacing_frame.grid(row=1, column=1, columnspan=3, sticky='ew')

    self.setOptionValues()

  def changedLength(self, choice):

    if choice == tick_length_choices[0]:
      self.length_frame.grid_forget()
    else:
      self.length_frame.grid(row=1, column=0, columnspan=4, sticky='ew')

    self.setOptionValues()

  # width and height are of plot, in pixels
  def getOutputHandler(self, pixel_width, pixel_height, unit_width=1.0, unit_height=1.0, fonts=None):

    if not fonts:
      fonts = []
    else:
      fonts = list(fonts)

    for n in range(len(fonts)):
      if fonts[n] == 'Times':
        fonts[n] = 'Times-Roman'

    self.setOptionValues()

    if not self.file_name:
      showError('No file', 'No file specified', parent=self)
      return None

    x_scaling = y_scaling = 1.0
    if self.scaling_choice != scaling_choices[0]:
      try:
        x_scaling = float(self.x_scaling)
      except:
        showError('Bad X Scaling', 'Specified X Scaling must be floating point', parent=self)
        return None
      try:
        y_scaling = float(self.y_scaling)
      except:
        showError('Bad Y Scaling', 'Specified Y Scaling must be floating point', parent=self)
        return None

    if os.path.exists(self.file_name):
      if not showYesNo('File exists', 'File "%s" exists, overwrite?' % self.file_name, parent=self):
        return None

    if self.paper_type == Output.other_paper_type:
      paper_size = self.other_size + [ self.other_unit ]
    else:
      paper_size = paper_sizes[self.paper_type]

    output_scaling = self.scaling / 100.0

    border_font = self.border_font
    (font, size) = border_font.split()
    size = int(size)
    border_text = {}
    for decoration in self.border_decoration:
      if decoration == 'Time and Date':
        location = 'se'
        text = time.ctime(time.time())
      elif decoration == 'File Name':
        location = 'sw'
        text = self.file_name
      else:
        continue # should not be here
      border_text[location] = (text, font, size)
    if self.title:
      location = 'n'
      border_text[location] = (self.title, font, size+6)

    if font not in fonts:
      fonts.append(font)

    if self.haveTicks and self.tick_location == PrintTicks.Outside:
      axis_label_offset = 2
    else:
      axis_label_offset = 0
     
    outputHandler = PrintHandler.getOutputHandler(self.file_name,
                              pixel_width, pixel_height,
                              unit_width, unit_height,
                              scaling_choice=self.scaling_choice,
                              output_scaling=output_scaling,
                              w_scaling=x_scaling,
                              h_scaling=y_scaling,
                              paper_size=paper_size,
                              paper_orientation=self.paper_orientation,
                              output_style=self.output_style,
                              output_format=self.output_format,
                              border_text=border_text,
                              x_axis_label=self.x_axis_label,
                              y_axis_label=self.y_axis_label,
                              axis_label_font=font,
                              axis_label_size=size,
                              axis_label_offset=axis_label_offset,
                              fonts=fonts,
                              linewidth=self.linewidth,
                              do_outline_box=self.doOutlineBox)

    return outputHandler

  def getAspectRatio(self):

    self.setOptionValues()

    if self.paper_type == Output.other_paper_type:
      paper_size = self.other_size
    else:
      paper_size = paper_sizes[self.paper_type]

    r = paper_size[1] / paper_size[0]
    if self.paper_orientation == 'Landscape':
      r = 1.0 / r

    return r
示例#13
0
class CreateAxisTypePopup(BasePopup):
    def __init__(self, parent, *args, **kw):

        self.measurementType = None

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

    def body(self, master):

        master.grid_columnconfigure(1, weight=1)

        row = 0
        label = Label(master, text='Axis name: ', grid=(row, 0))
        tipText = 'Short text name for new type of axis e.g. "17O"'
        self.name_entry = Entry(master,
                                width=15,
                                grid=(row, 1),
                                tipText=tipText)

        row += 1
        label = Label(master, text='Axis region: ', grid=(row, 0))
        tipText = 'Comma separated values for the upper and lower bound of the axis allowed range of values'
        self.region_entry = FloatEntry(master,
                                       text=[0.0, 1.0],
                                       isArray=True,
                                       width=15,
                                       grid=(row, 1),
                                       tipText=tipText)

        row += 1
        label = Label(master, text='Measurement type:', grid=(row, 0))
        tipText = 'The physical entity that is being measured along the axis'
        self.measurement_list = PulldownList(master, tipText=tipText)
        self.measurement_list.grid(row=row, column=1, sticky='w')

        row += 1
        label = Label(master, text='Dimension is sampled: ', grid=(row, 0))
        tipText = 'Whether the axis is discretely sampled or a continuous range (albeit on a grid)'
        self.sampled_popup = BooleanPulldownMenu(master,
                                                 grid=(row, 1),
                                                 tipText=tipText)

        row += 1
        label = Label(master, text='Decimal places: ', grid=(row, 0))
        tipText = 'The number of decimal places that the axis values are rounded to for display purposes'
        self.decimals_entry = IntEntry(master,
                                       text=0,
                                       width=15,
                                       grid=(row, 1),
                                       tipText=tipText)

        row += 1
        label = Label(master, text='Peak size: ', grid=(row, 0))
        tipText = 'The relative scale for the peak symbol (i.e the "X" shape) size compared to other axes'
        self.peak_size_entry = FloatEntry(master,
                                          text=1.0,
                                          width=15,
                                          grid=(row, 1),
                                          tipText=tipText)

        row += 1
        label = Label(master, text='Allowed axis units:', grid=(row, 0))
        tipTexts = [
            'Units of measurement allowed for this kind of axis',
        ]
        units = [au.unit for au in self.parent.getAxisUnits()]
        selected = [True] * len(units)
        self.units_list = CheckButtons(master,
                                       units,
                                       selected=selected,
                                       direction='vertical',
                                       grid=(row, 1),
                                       tipTexts=tipTexts)

        row += 1
        tipTexts = [
            'Make a new axis specification of the selected type and close this popup'
        ]
        texts = ['Create']
        commands = [self.ok]
        buttons = UtilityButtonList(master,
                                    texts=texts,
                                    commands=commands,
                                    doClone=False,
                                    closeText='Cancel',
                                    helpUrl=self.help_url,
                                    grid=(row, 0),
                                    gridSpan=(1, 2),
                                    tipTexts=tipTexts)

        master.grid_rowconfigure(row, weight=1)

        self.update()

    def update(self, *extra):

        measurementType = self.measurementType
        measurementTypes = self.parent.getMeasurementTypes()
        if measurementTypes:
            if measurementType not in measurementTypes:
                self.measurementType = measurementType = measurementTypes[0]
            index = measurementTypes.index(measurementType)
        else:
            index = 0
            self.measurementType = None

        self.measurement_list.setup(measurementTypes, None, index)

    def apply(self):

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

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

        region = self.region_entry.get()
        if ((region is None) or (len(region) != 2)):
            showError('Region error',
                      'Region must be float array of length two', self)
            return False

        if (region[0] >= region[1]):
            showError('Region error',
                      'Region must have first number < second number', self)
            return False

        measurementType = self.measurement_list.getText()
        isSampled = self.sampled_popup.getSelected()

        numDecimals = self.decimals_entry.get()
        if ((numDecimals is None) or (numDecimals < 0)):
            showError('Decimals error',
                      'Number of decimal places must be >= 0', self)
            return False

        peakSize = self.peak_size_entry.get()
        if ((peakSize is None) or (peakSize <= 0)):
            showError('Peak size error', 'Peak size must be > 0', self)
            return False

        selected = self.units_list.getSelected()
        allUnits = self.parent.getAxisUnits()
        axisUnits = [au for au in allUnits if au.unit in selected]

        self.analysisProject.newAxisType(name=name,
                                         region=region,
                                         isSampled=isSampled,
                                         axisUnits=axisUnits,
                                         numDecimals=numDecimals,
                                         peakSize=peakSize,
                                         measurementType=measurementType)

        return True
示例#14
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                   
示例#15
0
class ProjectFrame(Frame):

  def __init__(self, guiParent, basePopup):

    self.basePopup = basePopup
    self.guiParent = guiParent

    self.basePopup.frameShortcuts['Project'] = self

    #self.registerNotify=basePopup.registerNotify
    #self.unregisterNotify=basePopup.unregisterNotify

    Frame.__init__(self, guiParent)
  
    # set up the grid

    self.grid_columnconfigure(0, weight=0, minsize=10)
    self.grid_columnconfigure(1, weight=0, minsize=50)
    self.grid_columnconfigure(2, weight=1, minsize=20)
    self.grid_columnconfigure(3, weight=0, minsize=40)


    self.grid_rowconfigure(0, weight=0, minsize=5)
    self.grid_rowconfigure(1, weight=0, minsize=10)
    self.grid_rowconfigure(2, weight=0, minsize=10)
    self.grid_rowconfigure(3, weight=0, minsize=10)

    # we could in theory choose to store the last visited
    # project in the user config file and load this on log in

    # if we then decide that login is mandatory then this
    # would give as a project from the start
    
    self.repository = None
    self.projectName = None
    self.versionTag = None


    # we define as much as possible once on startup and use the
    # grid manager to control the display thereafter

    # when no data
    
    self.noData_widgets = []
    
    self.null_proj_label = Label(self, text='No Project selected')
    self.noData_widgets.append(self.null_proj_label)

    # when data

    self.data_widgets = []
    
    self.proj_rep_title = Label(self, text='Project:', font='Helvetica16')
    self.data_widgets.append(self.proj_rep_title)

    self.proj_rep_label = Label(self, text='Repository:')
    self.data_widgets.append(self.proj_rep_label)
    self.proj_rep_value = Label(self, text='')
    self.data_widgets.append(self.proj_rep_value)
        
    # This is more complex than it seems. We need to have some
    # user information accoisated with this too (who has the lock)
    self.proj_status_label = Label(self, text = 'Status:')
    self.data_widgets.append(self.proj_status_label)
    self.proj_status_value = Label(self, text='')
    self.data_widgets.append(self.proj_status_value)

    self.proj_details_label = Label(self, text='Description:')
    self.proj_details = Text(self, width=75, height=6, text='')
    self.data_widgets.append(self.proj_details)

    info_modes = ['versions','tasks','raw data']
    self.info_mode_select = PulldownList(self, self.tmpCall, info_modes)
    self.data_widgets.append(self.info_mode_select)
    
    initial_cols = ['Project','Version','Created by Task', 'Created from Project version']
    self.proj_history_matrix = ScrolledMatrix(self, headingList=initial_cols, initialRows=7,
                                      doubleCallback=self.history_callback)
    self.data_widgets.append(self.proj_history_matrix)

    initial_cols = ['ID','Task','User','Status', 'Date']
    self.proj_tasks_matrix = ScrolledMatrix(self, headingList=initial_cols, initialRows=7,
                                            doubleCallback=self.history_callback)
    self.data_widgets.append(self.proj_tasks_matrix)

    initial_cols = ['name','type','size','details']
    self.proj_files_matrix = ScrolledMatrix(self, headingList=initial_cols, initialRows=7,
                                            doubleCallback=self.history_callback)
    self.data_widgets.append(self.proj_files_matrix)

    
    self.proj_export_button = Button(self, 
                                     height=1, width=14,text='Export',
                                     command=self.export_project)
    self.data_widgets.append(self.proj_export_button)

    self.proj_import_button = Button(self, 
                                     height=1, width=14,text='Import',
                                     command=self.export_project)
    self.data_widgets.append(self.proj_import_button)
   
    self.run_testtask1_button = Button(self, 
                                       height=1, width=14,text='Run TestTask1',
                                       command=self.goto_task1_tab)
    self.data_widgets.append(self.run_testtask1_button)

    # FIXME JMCI

    # insert this inside this Frame directly: not worth abstracting out

    self.filter_frame = FilterFrame(self, self.basePopup, text='Filter')
    self.data_widgets.append(self.filter_frame)


    self.drawFrame()



  # Refreshing of the Frame is meaningless without setting the full
  # connection parameters


  def drawFrame(self):

    if self.basePopup.repList:
      self.repository = self.basePopup.repList.currentRepository
      if self.repository:      
        self.projectName = self.repository.currentProjectName
        self.versionTag = self.repository.currentVersionTag
    
    print 'in drawFrame ', self.repository, self.projectName, self.versionTag

    
    if self.projectName == None:

      for widget in self.data_widgets:
        widget.grid_remove()
      
      self.null_proj_label.grid(row=1, column=1, columnspan=4, sticky='nswe')
     
    else:

    # build up the body.

      for widget in self.noData_widgets:
        widget.grid_remove()

      # OK, so we need to determine the project that we are showing
      # in this frame. To uniquely describe a project we need to
      # know the repository, the project name, and the project version
      # so all these need to be set somehow. Maybe the best approach is
      # so have a public method that takes these arguments and to force
      # every refresh to operate through this. Then the drawFrame() method
      # would be private.

      loc = SharedBeanServiceLocator()
      port = loc.getSharedBean()

      # need two calls, one for the Project and one for the version
      hm1 = {'name': self.projectName }
      wsstr_in1 = WSString(hm1)

      request1 = getFields();
      request1._arg0 = 'org.pimslims.applet.server.ProjectBean';
      request1._arg1 = 'getFields';
      request1._arg2 = wsstr_in1.str

      response1 = port.getFields(request1)

      wsstr_out1 = WSString(response1._return)
      hm_proj = wsstr_out1.getStructHM()

      # now the version
  
      hm2 = {'project' : { 'name': self.projectName },
            'versionTag': self.versionTag }

      wsstr_in2 = WSString(hm2)

      request2 = getFields();
      request2._arg0 = 'org.pimslims.applet.server.ProjectVersionBean';
      request2._arg1 = 'getFields';
      request2._arg2 = wsstr_in2.str

      response2 = port.getFields(request2)

      wsstr_out2 = WSString(response2._return)
      hm_pv = wsstr_out2.getStructHM()


      self.proj_rep_title.set('Project: ' + self.projectName + ' v ' + self.versionTag)
      self.proj_rep_title.grid(row=1, column=1, sticky='w')

      self.proj_rep_label.grid(row=2, column=1, sticky='w')
      self.proj_rep_value.set(self.repository.name)
      self.proj_rep_value.grid(row=2, column=2, sticky='w')

      status = 'N/A'
      if hm_pv['status'] != 'valIsNullPointer':
        status = hm_pv['status']
        
      self.proj_status_label.grid(row=3, column=1, sticky='w')
      self.proj_status_value.set(status)
      self.proj_status_value.grid(row=3, column=2, sticky='w')

      # also want to know:
      # * how this file was created
      # * what external file (e.g. spectrum files) it uses
      # * the log history
      # * what processes it has been used in
      # * if locked, what process, user is responsible for this

      details = 'N/A'
      if hm_proj['details'] != 'valIsNullPointer':
        details = hm_proj['details']
      
      self.proj_details_label.grid(row=4, column=1, columnspan=2, sticky='nw')
      self.proj_details.setText(details)
      self.proj_details.grid(row=4, column=2, pady=10, sticky='nw')

      self.info_mode_select.grid(row=5, column=1, sticky='w')

      # this needs to go into a separate subroutine

      # get al the version
  
      hm3 = {'project' : { 'name': self.projectName }}
      wsstr_in3 = WSString(hm3)

      request3 = getList()
      request3._arg0 = 'org.pimslims.applet.server.ProjectVersionBean';
      request3._arg1 = 'getListWithFields';
      request3._arg2 =  wsstr_in3.str

      response3 = port.getList(request3)

      wsstr_out3 = WSString(response3._return)
      vers = wsstr_out3.getStruct()

      matrix = [];
      objs = [];

      print 'PROJECT: ', vers

      for ver in vers:

        taskSerial = 'unknown'
        if (ver.has_key('createdByTask')):
          task = ver['createdByTask']
          taskSerial = task['serial']

        # FIXME JMCI

        # Really should get this from the task, of it exists

        parentVersionTag = 'unknown'
        if (ver.has_key('sourceVersion')):
          pv = ver['sourceVersion']
          pvp = pv['project']
          parentName = pvp['name']
          parentVersionTag = pvp['name'] + ' ' + pv['versionTag']

        new_row = (self.projectName, ver['versionTag'], taskSerial, parentVersionTag )
        matrix.append(new_row)
        objs.append(ver)

      self.proj_history_matrix.update(objectList=objs, textMatrix=matrix)
      self.proj_history_matrix.grid(row=6, column=1, columnspan=2, pady=10, sticky='nsew')

      self.filter_frame.grid(row=6, column=3, pady=10, sticky='n')
      

      # have a button to export. It should now be clear which version
      # of which project in which repository should be exported

      self.proj_import_button.grid(row=1, column=3, padx=3,pady=3, sticky='ew')
      self.proj_export_button.grid(row=2, column=3, padx=3,pady=3, sticky='ew')
        
      self.run_testtask1_button.grid(row=4, column=3, padx=3,pady=3, sticky='ew')

      # It is not clear precisely how methods should be triggered from
      # the project frame, as there may be >1 input to a given task with
      # a specific role. It maybe that we need to parse out a metadescription
      # of the task and use this to produce the correct buttons (maybe
      # even depending on the contents of the file ?)

      #self.task_button_texts=['Test1Task','Test2Task']
      #self.task_button_cmds=[self.runTest1Task, self.runTest2Task]
      #self.task_button_list = ButtonList(self, self.task_button_texts, self.task_button_cmds,
      #                                    None, 1, 1, True, None, Tkinter.VERTICAL)
      # 
      #self.task_button_list.grid(row=1, rowspan=3, column=4, padx=3, sticky='w')

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

    if (col == 1):
      pv = obj['versionTag']
      print 'PROJECT -> PROJECT (DIRECT) ', pv
      self.repository.currentVersionTag = pv.__str__()

      self.drawFrame()
      
    elif (col == 2):
      task = obj['createdByTask']
      taskSerial = task['serial']
      
      print 'PROJECT -> TASK ', taskSerial

      self.basePopup.currentTask = taskSerial.__str__()    

      # FIXME

      # This is more complex. Need to navigate to the correct
      # panel within the Task submenu

      if self.basePopup.frameShortcuts.has_key('Task'):
        taskFrame = self.basePopup.frameShortcuts['Task']
        # really need to check on the type of task
        if taskFrame.frameShortcuts.has_key('Test1'):
          taskFrame.frameShortcuts['Test1'].drawFrame()
      # also need to select the current tabbed frame
      self.basePopup.tabbedFrame.select(2)
      

    # FIXME JMCI

    # need to look into this. Really we need both the project and
    # the version for this (in theory this could be based on a different
    # project although it is highly unlikely!)

    elif (col == 3):
      pv = obj['sourceVersion']
      parentVersion = pv['versionTag']
      
      pvp = pv['project']
      parentName = pvp['name']
      
      print 'PROJECT -> PROJECT (SOURCE) ', parentVersion

      self.repository.currentVersionTag = parentVersion.__str__()
      self.repository.currentProjectName = parentName.__str__()

      self.drawFrame()
 

  # create a new task with this project as an input

  # it is not clear how we should do this:- construct data locally
  # and then save, or save a first cut and then ammend. On the basis
  # that the serial has to be generated by the DB, we will go for the
  # former for now

  # it would be better to pass this to a processor layer that
  # determines parameters and then builds the stub.

  def goto_task1_tab(self):

    # create a new task (provisional status)

    loc = SharedBeanServiceLocator()
    port = loc.getSharedBean()

    #hm0 = { 'project': { 'name': self.projectName},
    #        'versionTag' : self.versionTag,
    #        '_handle' : 'findOrFail' }

    # FIXME

    # We have an error here (it seems to be a problem between the CCPN
    # and hibernate layers that is not picking objects as the same for
    # some reason. Therefore do not set the inputVersion for now

    hm0 = { 'project': { 'name': self.projectName},
            'versionTag' : self.versionTag}
    hm2 = { 'inputVersion' : hm0,
            'status' : 'PROVISIONAL' }

    #hm2 = { 'status' : 'PROVISIONAL' }

    wsstr_in1 = WSString(hm2)
            
    req1 = recordAndLoad();

    req1._arg0 = 'org.pimslims.applet.server.TaskBean';
    req1._arg1 = 'recordTest1';
    req1._arg2 =  wsstr_in1.str
    
    resp1 = port.recordAndLoad(req1)
    wsstr_out1 = WSString(resp1._return)
    v = wsstr_out1.getStructHM()

    self.basePopup.currentTask =   v['serial'].__str__()

    # FIXME

    # This is more complex. Need to navigate to the correct
    # panel within the Task submenu

    if self.basePopup.frameShortcuts.has_key('Task'):
      taskFrame = self.basePopup.frameShortcuts['Task']
      # really need to check on the type of task
      if taskFrame.frameShortcuts.has_key('Test1'):
        taskFrame.frameShortcuts['Test1'].drawFrame()
    # also need to select the current tabbed frame
    self.basePopup.tabbedFrame.select(2)

    
  # method for exporting repository directory to local file
  # system. This is a very basic approach, essentially first
  # listing all the files required for transfer and then
  # copying them over one by one. Note that due to limitations
  # in ZSI we cannot do much better than base64 encoding each
  # file. We could consider storing a tgz on the server and
  # exporting that. It might be a considerable improvement as
  # the compression leads to a file < 10% of the original size
  # which would cut down on traffic enormously

  def export_project(self):

    versionTag = self.versionTag
    name = self.projectName

    # need to preserve the current status. Take a default from the
    # Wms layer 
    rootDir = self.basePopup.repList.current_export_dir

    # This should be obtained from a query box. Hard code for now
    fileSelectPopup = FileSelectPopup(self, None, rootDir)

    exp_project_dir = fileSelectPopup.getDirectory()
    self.basePopup.repList.current_export_dir = exp_project_dir

    # These should come from the repository object
    loc = SharedBeanServiceLocator()
    port = loc.getSharedBean()

    req1 = getList()

    hm1 = {'projectName': name,
           'versionTag': versionTag,
           'segment': 'jionides' }
    wsstr1 = WSString(hm1)

    # these are actually static
    req1._arg0 = 'org.pimslims.applet.server.CcpnFileBean';
    req1._arg1 = 'getList';
    req1._arg2 = wsstr1.str

    # get the response
    resp1 = port.getList(req1)

    # this is a hack at present. It needs to be written properly
    wsstr = WSString(resp1._return)
    ss = wsstr.getStruct()

    print 'got array ', ss

    for strg in ss:

      print 'trying to handle file ', strg

      hm2 = {'projectName': name,
             'versionTag': versionTag,
             'segment': 'jionides',
             'fileName' : '/' + strg.__str__(),
             'random' : 'test',
             'raw' : False}
      
      print 'trying to handle file 2 ', strg
      print 'trying to handle file 2 ', hm2

      req2 = getDocWithParams()
      
      wsstr2 = WSString(hm2)

      # these are actually static
      req2._arg0 = 'org.pimslims.applet.server.CcpnFileBean';
      req2._arg1 = wsstr2.str

      # get the response
      resp2 = port.getDocWithParams(req2)

      local_file_path = exp_project_dir + '/' + name + '/' + strg

      idx = local_file_path.rfind('/')
      local_dir = local_file_path[:idx]
      print 'trying to create ', local_dir
      os.makedirs(local_dir)

      print 'writing to local area; ', local_file_path

      f = open(local_file_path, 'w')
      f.write(resp2._return)
          

  # it is likely that these methods are going to have to be highly specialised
  # as some tasks are going to have many input files and we need to know which
  # role the project we are in takes in the task.

  def runTest1Task(self):

    pass

  def runTest2Task(self):

    pass

  def view_project(self, project):

    self.project = project

    self.drawFrame()


  def tmpCall(self):

    return


  def administerNotifiers(self, notifyFunc):

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

  def updateAllAfter(self, obj):

    self.after_idle(self.updateAll)

  def updateAll(self, project=None):

      return

  def quit(self):
  
    self.guiParent.parent.destroy()
    
  def destroy(self):
  
    self.administerNotifiers(self.basePopup.unregisterNotify)
    Frame.destroy(self)
示例#16
0
class EditPeakFindParamsPopup(BasePopup):
    """
  ** Peak Settings and Non-Interactive Peak Finding **
  
  The purpose of this dialog is to allow the user to select settings for
  finding and integrating peaks, and also to be able to find peaks in an
  arbitrary region that is specified in a table rather than via a spectrum
  window.
  
  ** Find Parameters tab **

  This can be used to specify how peak finding works.

  First of all, you can search for just positive peaks, just negative
  peaks or both, and the default is that it is just positive peaks.
  However, this is further filtered by what the contour levels are.
  If there are no positive contour levels for a given spectrum then
  positive peaks are not found even if this dialog says they can be,
  and similarly if there are no negative contour levels for a given
  spectrum then negative peaks are not found even if this dialog says
  they can be.

  The peak finding algorithm looks for local extrema (maximum for
  positive peaks and minima for negative peaks).  But on a grid there
  are various ways to define what you mean by an extremum.  Suppose
  you are trying to determine if point p is a maximum (similar
  considerations apply for minimum).  You would want the intensity
  at all nearby points to be less than or equal to the intensity at p.
  You can just check points that are just +- one point from p in each
  dimension, or you can also check "diagonal" points.  For
  example, if you are looking at point p = (x, y) in 2D, then the
  former would mean checking the four points (x-1, y), (x+1, y)
  (x, y-1) and (x, y+1), whereas for the latter you would also have
  to check (x-1, y-1), (x-1, y+1), (x+1, y-1) and (x+1, y+1).  In
  N dimensions the "diagonal" method involves checking 3^N-1 points
  whereas the "non-diagonal" method involves checking only 2N points.
  In general the "non-diagonal" method is probably the one to use,
  and it is the default.

  Peaks are only found above (for positive peaks) or below (for negative
  peaks) some threshold.  By default this is determined by the contour level
  for the spectrum.  For positive peaks the threshold is the minimum
  positive contour level, and for negative peaks the threshold is the
  maximum negative contour level.  However these levels can be scaled up
  (or down) using the "Scale relative to contour levels" option (default
  value 1).  For example, if you have drawn the contour levels low to
  show a bit of noise, but do not want the noise picked as peaks, then
  you could select a scale of 2 (or whatever) to increase the threshold.

  The "Exclusion buffer around peaks" is so that in crowded regions you
  do not get too many peaks near one location.  By default the exclusion
  buffer is 1 point in each dimension, but this can be increased to make
  the algorithm find fewer peaks.

  By default the peak finding only looks at the orthogonal region that
  is displayed in the given window where peak finding is taking place.
  Sometimes it looks like a peak should be found because in x, y you
  can see an extremum, but unless it is also an extremum in the orthogonal
  dimensions it is not picked.  You can widen out the points being
  examined in the orthogonal dimensions by using the "Extra thickness in
  orthogonal dims" option, which is specified in points.

  The "Minimum drop factor" is by what factor the intensity needs to drop
  from its extreme value for there to be considered to be a peak.  This
  could help remove sinc wiggle peaks, for example.  The default is that
  the drop factor is 0, which in effect means that there is no condition.

  The "Volume method" is what is used to estimate the volume of peaks that
  are found.  The default is "box sum", which just looks at a fixed size
  box around the peak centre and sums the intensities in that.  The size
  of the box is set in the table in the Spectrum Widths tab.  The
  "truncated box sum" is the same as "box sum" except that the summing
  stops in a given direction when (if) the intensities start increasing.
  The "parabolic" fit fits a quadratic equation in each dimension to the
  intensity at the peak centre and ad +- 1 points and then uses the
  equivalent Gaussian fit to estimate the volume.

  ** Spectrum Widths **

  This can be used to specify minimum linewidths (in Hz) for there to be
  considered a peak to exist in the peak finding algorithm.  It is also
  where the Boxwidth for each dimension in each spectrum is specified.

  ** Diagonal Exclusions **

  This can be used to exclude peaks from being found in regions near
  the diagonal (so in homonuclear experiments).  The exclusion region
  is specified in ppm and is independent of spectrum.

  ** Region Peak Find **

  This can be used to find peaks non-interactively (so not having to
  control shift drag inside a spectrum window).  The region being
  analysed is specified in the table.  There are two types of conditions
  that can be specified, "include" for regions that should be included
  and "exclude" for regions that should be excluded.  The regions are
  specified in ppm.

  The "Whole Region" button will set the selected row in the table to be
  the entire fundamental region of the spectrum.

  The "Add Region" button adds an extra row to the table, and the "Delete
  Region" button removes the selected row.

  The "Adjust Params" button goes to the Find Parameters tab.

  The "Find Peaks!" button does the peak finding.

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

        self.spectrum = None

        BasePopup.__init__(self,
                           parent=parent,
                           title='Peak : Peak Finding',
                           **kw)

    def body(self, guiFrame):

        self.geometry('600x350')

        guiFrame.expandGrid(0, 0)

        tipTexts = ['', '', '', '']
        options = [
            'Find Parameters', 'Spectrum Widths', 'Diagonal Exclusions',
            'Region Peak Find'
        ]
        tabbedFrame = TabbedFrame(guiFrame, options=options, grid=(0, 0))

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

        # Find Params

        frameA.expandGrid(2, 0)

        row = 0
        label = LabelFrame(frameA,
                           text='Extrema to search for:',
                           grid=(row, 0),
                           gridSpan=(1, 2))
        label.expandGrid(0, 1)

        entries = ['positive and negative', 'positive only', 'negative only']
        tipTexts = [
            'Sets whether peak picking within spectra find intensity maxima, minima or both maxima and minima',
        ]
        self.extrema_buttons = RadioButtons(label,
                                            entries=entries,
                                            select_callback=self.apply,
                                            direction='horizontal',
                                            grid=(0, 0),
                                            tipTexts=tipTexts)

        row += 1
        label = LabelFrame(frameA,
                           text='Nearby points to check:',
                           grid=(row, 0),
                           gridSpan=(1, 2))
        label.expandGrid(None, 1)

        entries = ['+-1 in at most one dim', '+-1 allowed in any dim']
        tipTexts = [
            'Sets how permissive the peak picking in when searching for intensity extrema; by adding extra points to the selected search region',
        ]
        self.adjacent_buttons = RadioButtons(label,
                                             entries=entries,
                                             select_callback=self.apply,
                                             direction='horizontal',
                                             grid=(0, 0),
                                             tipTexts=tipTexts)

        row += 1
        labelFrame = LabelFrame(frameA,
                                text='Other parameters:',
                                grid=(row, 0),
                                gridSpan=(1, 2))
        labelFrame.expandGrid(5, 2)

        frow = 0
        label = Label(labelFrame,
                      text='Scale relative to contour levels:',
                      grid=(frow, 0),
                      sticky='e')
        tipText = 'Threshold above which peaks are picked, relative to the lowest displayed contour; 1.0 means picking exactly what is visible'
        self.scale_entry = FloatEntry(labelFrame,
                                      grid=(frow, 1),
                                      tipText=tipText,
                                      returnCallback=self.apply,
                                      width=10)
        self.scale_entry.bind('<Leave>', self.apply, '+')

        frow += 1
        label = Label(labelFrame,
                      text='Exclusion buffer around peaks (in points):',
                      grid=(frow, 0),
                      sticky='e')
        tipText = 'The size of the no-pick region, in data points, around existing picked peaks; eliminates duplicate picking'
        self.buffer_entry = IntEntry(labelFrame,
                                     returnCallback=self.apply,
                                     grid=(frow, 1),
                                     width=10,
                                     tipText=tipText)
        self.buffer_entry.bind('<Leave>', self.apply, '+')

        frow += 1
        label = Label(labelFrame,
                      text='Extra thickness in orthogonal dims (in points):',
                      grid=(frow, 0),
                      sticky='e')
        tipText = 'Sets whether to consider any additional planes (Z dimension) when calculating peak volume integrals'
        self.thickness_entry = IntEntry(labelFrame,
                                        returnCallback=self.apply,
                                        width=10,
                                        grid=(frow, 1),
                                        tipText=tipText)
        self.thickness_entry.bind('<Leave>', self.apply, '+')

        frow += 1
        label = Label(labelFrame,
                      text='Minimum drop factor (0.0-1.0):',
                      grid=(frow, 0),
                      sticky='e')
        tipText = ''
        self.drop_entry = FloatEntry(labelFrame,
                                     returnCallback=self.apply,
                                     width=10,
                                     grid=(frow, 1),
                                     tipText=tipText)
        self.drop_entry.bind('<Leave>', self.apply, '+')

        frow += 1
        label = Label(labelFrame,
                      text='Volume method:',
                      grid=(frow, 0),
                      sticky='e')
        tipText = 'Selects which method to use to calculate peak volume integrals when peaks are picked; box sizes are specified in "Spectrum Widths"'
        self.method_menu = PulldownList(labelFrame,
                                        texts=PeakBasic.PEAK_VOLUME_METHODS,
                                        grid=(frow, 1),
                                        callback=self.apply,
                                        tipText=tipText)

        # Spectrum widths

        frameB.expandGrid(1, 1)

        label = Label(frameB, text='Spectrum: ')
        label.grid(row=0, column=0, sticky='e')

        tipText = 'The spectrum which determines the widths being shown'
        self.expt_spectrum = PulldownList(frameB,
                                          tipText=tipText,
                                          callback=self.setSpectrumProperties)
        self.expt_spectrum.grid(row=0, column=1, sticky='w')

        self.editLinewidthEntry = FloatEntry(self,
                                             text='',
                                             returnCallback=self.setLinewidth,
                                             width=10)
        self.editBoxwidthEntry = FloatEntry(self,
                                            text='',
                                            returnCallback=self.setBoxwidth,
                                            width=10)
        tipTexts = [
            'The number of the spectrum dimension to which the settings apply',
            'The nuclear isotope measures in the spectrum dimension',
            'The smallest value for the linewidth of a peak for it to be picked',
            'The size of the spectrum region to perform the volume integral over'
        ]
        headingList = [
            'Dimension', 'Isotope', 'Minimum Linewidth (Hz)', 'Boxwidth'
        ]
        editSetCallbacks = [None, None, self.setLinewidth, self.setBoxwidth]
        editGetCallbacks = [None, None, self.getLinewidth, self.getBoxwidth]
        editWidgets = [
            None, None, self.editLinewidthEntry, self.editBoxwidthEntry
        ]
        self.spectrumMatrix = ScrolledMatrix(frameB,
                                             initialRows=6,
                                             editSetCallbacks=editSetCallbacks,
                                             editGetCallbacks=editGetCallbacks,
                                             editWidgets=editWidgets,
                                             headingList=headingList,
                                             callback=self.selectCell,
                                             tipTexts=tipTexts)
        self.spectrumMatrix.grid(row=1, column=0, columnspan=2, sticky='nsew')

        # Diagonal Exclusions

        frameC.expandGrid(0, 0)

        tipTexts = [
            'The isotope as measures on the axis of a spectrum window',
            'The distance from the homonuclear diagonal line within which no peak picking can occur'
        ]
        self.exclusionEntry = FloatEntry(self,
                                         text='',
                                         returnCallback=self.setExclusion,
                                         width=10)
        headingList = ['Isotope', 'Diagonal Exclusion (ppm)']
        editSetCallbacks = [None, self.setExclusion]
        editGetCallbacks = [None, self.getExclusion]
        editWidgets = [None, self.exclusionEntry]
        self.isotopeMatrix = ScrolledMatrix(frameC,
                                            editSetCallbacks=editSetCallbacks,
                                            editGetCallbacks=editGetCallbacks,
                                            editWidgets=editWidgets,
                                            headingList=headingList,
                                            grid=(0, 0),
                                            tipTexts=tipTexts)

        # Region peak find

        self.regionFindPeakList = None
        self.regionCondition = None
        self.regionConditions = []
        self.regionCol = 1

        row = 0

        label = Label(frameD, text='Peak List: ', grid=(0, 0))
        tipText = 'Selects which peak list to perform region-wide peak picking for'
        self.regionPeakListPulldown = PulldownList(
            frameD,
            callback=self.changeRegionPeakList,
            grid=(0, 1),
            tipText=tipText)

        row += 1
        frameD.expandGrid(row, 1)

        self.regionEntry = FloatEntry(self,
                                      text='',
                                      returnCallback=self.setRegion,
                                      width=10)
        self.conditionMenu = PulldownList(self,
                                          texts=('include', 'exclude'),
                                          callback=self.setCondition)

        tipTexts = [
            'Whether to include or exclude the states region from region-wide peak picking',
        ]
        headingList = ['Condition']
        editSetCallbacks = [None]
        editGetCallbacks = [None]
        editWidgets = [self.conditionMenu]
        self.regionFindMatrix = ScrolledMatrix(
            frameD,
            headingList=headingList,
            callback=self.selectRegionCell,
            editWidgets=editWidgets,
            editGetCallbacks=editGetCallbacks,
            editSetCallbacks=editSetCallbacks,
            grid=(row, 0),
            gridSpan=(1, 2))

        row += 1
        tipTexts = [
            'Sets the currently selected region row to cover the whole spectrum',
            'Add a new region row, which may them be set for exclusion or inclusion when peak picking large areas',
            'Remove the selected region specification',
            'Go to the panel for setting the parameters that control how peaks extrema are picked',
            'Using the stated regions and parameters, perform region-wide peak picking'
        ]
        texts = [
            'Whole Region', 'Add Region', 'Delete Region', 'Adjust Params',
            'Find Peaks!'
        ]
        commands = [
            self.wholeRegion, self.addCondition, self.deleteCondition,
            self.adjustParams, self.regionFindPeaks
        ]

        buttons = ButtonList(frameD,
                             texts=texts,
                             commands=commands,
                             grid=(row, 0),
                             gridSpan=(1, 2),
                             tipTexts=tipTexts)
        buttons.buttons[4].config(bg='#B0FFB0')

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

        self.dataDim = None
        self.setParamsEntries()
        self.updateSpectrum()
        self.setIsotopeProperties()
        self.updateRegionPeakLists()

        self.administerNotifiers(self.registerNotify)

    def administerNotifiers(self, notifyFunc):

        # Many more needed here, esp on the AnalysisProject prams

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

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

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

        for func in ('setPeakFindBoxWidth', 'setPeakFindMinLineWidth'):
            notifyFunc(self.updateSpectrumTable,
                       'ccpnmr.Analysis.AnalysisDataDim', func)

    def destroy(self):

        self.administerNotifiers(self.unregisterNotify)
        BasePopup.destroy(self)

    def updateSpectrum(self, spectrum=None):

        if not spectrum:
            spectrum = self.spectrum

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

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

        self.setSpectrumProperties(spectrum)

    def updateNotifier(self, *extra):

        self.updateSpectrum()

    def setLinewidth(self, *event):

        value = self.editLinewidthEntry.get()
        if value is not None:
            PeakFindParams.setPeakFindMinLinewidth(self.dataDim, value)
            self.setSpectrumProperties(self.dataDim.dataSource)

    def getLinewidth(self, dataDim):

        if dataDim:
            self.editLinewidthEntry.set(
                PeakFindParams.getPeakFindMinLinewidth(self.dataDim))

    def setBoxwidth(self, *event):

        value = self.editBoxwidthEntry.get()
        if value is not None:
            PeakFindParams.setPeakFindBoxwidth(self.dataDim, value)
            self.setSpectrumProperties(self.dataDim.dataSource)

    def getBoxwidth(self, dataDim):

        if dataDim:
            self.editBoxwidthEntry.set(
                PeakFindParams.getPeakFindBoxwidth(self.dataDim))

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

        self.dataDim = object

    def setExclusion(self, *extra):

        isotope = self.isotopeMatrix.currentObject
        if not isotope:
            return

        value = self.exclusionEntry.get()
        if value is not None:
            setIsotopeExclusion(isotope, value)
            self.setIsotopeProperties()

    def getExclusion(self, isotope):

        value = getIsotopeExclusion(isotope)
        self.exclusionEntry.set(value)

    def setParamsEntries(self):

        project = self.project
        params = PeakFindParams.getPeakFindParams(project)

        self.scale_entry.set(params['scale'])
        self.buffer_entry.set(params['buffer'])
        self.thickness_entry.set(params['thickness'])
        self.drop_entry.set(params['drop'])
        volumeMethod = params['volumeMethod']
        if volumeMethod == 'parabolic fit':
            volumeMethod = PeakBasic.PEAK_VOLUME_METHODS[0]
        self.method_menu.set(params['volumeMethod'])

        if (params['nonadjacent']):
            n = 1
        else:
            n = 0
        self.adjacent_buttons.setIndex(n)

        have_high = params['haveHigh']
        have_low = params['haveLow']
        if (have_high and have_low):
            n = 0
        elif (have_high):
            n = 1
        else:
            n = 2
        self.extrema_buttons.setIndex(n)

    def apply(self, *extra):

        params = {}
        params['scale'] = self.scale_entry.get()
        params['buffer'] = self.buffer_entry.get()
        params['thickness'] = self.thickness_entry.get()
        params['drop'] = self.drop_entry.get()
        params['volumeMethod'] = self.method_menu.getText()

        n = self.adjacent_buttons.getIndex()
        if (n == 0):
            nonadjacent = False
        else:
            nonadjacent = True
        params['nonadjacent'] = nonadjacent

        n = self.extrema_buttons.getIndex()
        if (n == 0):
            have_high = True
            have_low = True
        elif (n == 1):
            have_high = True
            have_low = False
        elif (n == 2):
            have_high = False
            have_low = True
        params['haveHigh'] = have_high
        params['haveLow'] = have_low

        project = self.project
        try:
            PeakFindParams.setPeakFindParams(project, params)
        except Implementation.ApiError, e:
            showError('Parameter error', e.error_msg, parent=self)
示例#17
0
class DangleFrame(Frame):
    def __init__(self, parent, dangleGui, project=None, *args, **kw):

        self.guiParent = parent
        self.dangleGui = dangleGui
        self.dangleDir = None
        self.dangleChain = None
        self.dangleResidue = None
        #self.outDir      = OUTDIR
        self.row = None
        self.col = None
        self.project = project
        self.nmrProject = None
        self.colorScheme = 'red'

        self.chain = None
        self.shiftList = None
        self.dangleStore = False  # Not None
        self.constraintSet = None
        self.ensemble = None

        Frame.__init__(self, parent=parent)

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

        row = 0

        # TOP LEFT FRAME

        frame = LabelFrame(self, text='Options')
        frame.grid(row=row, column=0, sticky='nsew')
        frame.columnconfigure(5, weight=1)

        label = Label(frame, text='Chain')
        label.grid(row=0, column=0, sticky='w')
        self.chainPulldown = PulldownList(
            frame,
            callback=self.changeChain,
            tipText='Choose the molecular system chain to make predictions for'
        )
        self.chainPulldown.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='Shift List')
        label.grid(row=0, column=2, sticky='w')
        self.shiftListPulldown = PulldownList(
            frame,
            callback=self.changeShiftList,
            tipText='Select the shift list to take input chemical shifts from')
        self.shiftListPulldown.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='Max No. of Islands:')
        label.grid(row=0, column=4, sticky='w')
        sizes = range(10)
        texts = [str(s) for s in sizes] + [
            'Do not reject',
        ]
        self.rejectPulldown = PulldownList(
            frame,
            texts=texts,
            objects=sizes + [
                None,
            ],
            tipText=
            'Select the maximum allowed number of disontinuous prediction islands'
        )
        self.rejectPulldown.set(DEFAULT_MAX_ISLANDS)  # Actual value not index
        self.rejectPulldown.grid(row=0, column=5, sticky='w')

        label = Label(frame, text='Dangle Run:')
        label.grid(row=1, column=0, sticky='w')
        self.dangleStorePulldown = PulldownList(
            frame,
            callback=self.changeDangleStore,
            tipText='Select a run number to store DANGLE results within')
        self.dangleStorePulldown.grid(row=1, column=1, sticky='w')

        label = Label(frame, text='Ensemble:')
        label.grid(row=1, column=2, sticky='w')
        self.ensemblePulldown = PulldownList(
            frame,
            callback=self.changeEnsemble,
            tipText=
            'Select the structure ensemble for superimposition of angle values on the GLE plots'
        )
        self.ensemblePulldown.grid(row=1, column=3, sticky='w')

        label = Label(frame, text='Restraint Set:')
        label.grid(row=1, column=4, sticky='w')
        self.constrSetPulldown = PulldownList(
            frame,
            callback=self.changeConstraintSet,
            tipText=
            'Select the CCPN restraint set to store DANGLE dihedral angle restraints in'
        )
        self.constrSetPulldown.grid(row=1, column=5, sticky='w')

        # TOP RIGHT FRAME

        outerFrame = Frame(self)
        outerFrame.grid(row=row, column=1, rowspan=2, sticky='nsew')
        outerFrame.rowconfigure(0, weight=1)
        outerFrame.columnconfigure(0, weight=1)

        frame = LabelFrame(outerFrame, text='Global Likelihood Estimates')
        frame.grid(row=0, column=0, sticky='nsew')
        frame.rowconfigure(1, weight=1)
        frame.columnconfigure(2, weight=1)

        self.prevPlot = ViewRamachandranFrame(frame,
                                              relief='sunken',
                                              defaultPlot=False,
                                              width=180,
                                              height=180,
                                              bgColor=self.cget('bg'),
                                              nullColor='#000000',
                                              titleText='Previous',
                                              xTicks=False,
                                              yTicks=False,
                                              xLabel='',
                                              yLabel='',
                                              showCoords=False)
        self.prevPlot.grid(row=0, column=0, sticky='nsew')
        self.prevPlot.getPlotColor = self.getPlotColor

        self.nextPlot = ViewRamachandranFrame(frame,
                                              relief='sunken',
                                              defaultPlot=False,
                                              width=180,
                                              height=180,
                                              bgColor=self.cget('bg'),
                                              nullColor='#000000',
                                              titleText='Next',
                                              xTicks=False,
                                              yTicks=False,
                                              xLabel='',
                                              yLabel='',
                                              showCoords=False)
        self.nextPlot.grid(row=0, column=1, sticky='nsew')
        self.nextPlot.getPlotColor = self.getPlotColor

        self.plot = ViewRamachandranFrame(frame,
                                          relief='sunken',
                                          defaultPlot=False,
                                          width=360,
                                          height=360,
                                          bgColor=self.cget('bg'),
                                          nullColor='#000000')
        self.plot.grid(row=1, column=0, columnspan=2, sticky='nsew')
        self.plot.selectColor = '#FFB0B0'
        self.plot.getPlotColor = self.getPlotColor

        # BOTTOM RIGHT FRAME

        frame = Frame(outerFrame)
        frame.grid(row=1, column=0, sticky='nsew')
        frame.rowconfigure(0, weight=1)
        frame.columnconfigure(0, weight=1)

        texts = ('Previous', '  Next  ')
        commands = (self.showPrevious, self.showNext)
        tipTexts = [
            'Show GLE plot of angle predictions for previous residue in chain',
            'Show GLE plot of angle predictions for next residue in chain'
        ]
        buttonList = ButtonList(frame, texts, commands, tipTexts=tipTexts)
        buttonList.grid(row=0, column=0, sticky='nsew')

        row += 1

        # BOTTOM LEFT FRAME

        frame = LabelFrame(self, text='Dihedral Angle Predictions')
        frame.grid(row=row, column=0, sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        self.floatEntry = FloatEntry(self,
                                     text='',
                                     returnCallback=self.setFloatEntry,
                                     width=10,
                                     formatPlaces=9)

        tipTexts = [
            'Residue number in chain', 'Residue type code',
            'Number of high scoring discontinuous angle predictions',
            'Predicted secondary structure code',
            'Predicted phi dihedral angle (CO-N-CA-CO)',
            'Predicted psi dihedral angle (N-CA-CO-N)',
            'Upper bound of phi angle prediction',
            'Lower bound of phi angle prediction',
            'Upper bound of psi angle prediction',
            'Lower bound of phi angle prediction',
            'Chemical shifts used in prediction'
        ]

        headingList = [
            'Res\nNum', 'Res\nType', 'No. of\nIslands', 'SS', 'Phi', 'Psi',
            'Phi\nUpper', 'Phi\nLower', 'Psi\nUpper', 'Psi\nLower',
            'Chemical Shifts'
        ]

        editWidgets = [
            None, None, None, None, self.floatEntry, self.floatEntry,
            self.floatEntry, self.floatEntry, self.floatEntry, self.floatEntry
        ]

        editGetCallbacks = [
            None, None, None, None, self.getFloatEntry, self.getFloatEntry,
            self.getFloatEntry, self.getFloatEntry, self.getFloatEntry,
            self.getFloatEntry
        ]

        editSetCallbacks = [
            None, None, None, None, self.setFloatEntry, self.setFloatEntry,
            self.setFloatEntry, self.setFloatEntry, self.setFloatEntry,
            self.setFloatEntry
        ]

        self.predictionMatrix = ScrolledMatrix(
            frame,
            headingList=headingList,
            multiSelect=True,
            callback=self.selectCell,
            tipTexts=tipTexts,
            editWidgets=editWidgets,
            editGetCallbacks=editGetCallbacks,
            editSetCallbacks=editSetCallbacks)
        #                                       doubleCallback=self.loadGLEs)
        self.predictionMatrix.grid(row=0, column=0, sticky='nsew')

        row += 1

        tipTexts = [
            'Remove the predictions for the selected residues',
            'Run the DANGLE method to predict dihedral angles and secondary structure',
            'Delete the DANGLE results stored under the current run number',
            'Store the angle predictions and bounds in a new CCPN dihedral angle restraint list',
            'Store the secondary structure predictions in the CCPN project'
        ]

        texts = [
            'Clear\nSelected', 'Run Prediction!', 'Delete\nCurrent Run',
            'Commit\nRestraints', 'Commit\nSecondary Structure'
        ]
        commands = [
            self.clearSelected, self.runDangle, self.deleteRun,
            self.storeDihedralConstraints, self.storeSecondaryStructure
        ]
        self.buttonList = createDismissHelpButtonList(
            self,
            texts=texts,
            commands=commands,  # dismiss_text='Quit',
            dismiss_cmd=self.dangleGui.quit,
            help_url=self.dangleGui.help_url,
            expands=True,
            tipTexts=tipTexts)
        self.buttonList.grid(row=row, column=0, columnspan=2, sticky='ew')
        self.buttonList.buttons[1].config(bg='#C0FFFF')

        self.updateProject(project)

        self.notify(dangleGui.registerNotify)

    def destroy(self):

        self.notify(self.dangleGui.unregisterNotify)
        Frame.destroy(self)

    def notify(self, notifyfunc):

        for func in ('__init__', 'delete'):
            notifyfunc(self.updateChainPulldown,
                       'ccp.molecule.MolSystem.Chain', func)

        for func in ('__init__', 'delete', 'setName'):
            notifyfunc(self.updateShiftListPulldown, 'ccp.nmr.Nmr.ShiftList',
                       func)

        for func in ('__init__', 'delete'):
            notifyfunc(self.updateConstrSetPulldown,
                       'ccp.nmr.NmrConstraint.NmrConstraintStore', func)

        for func in ('__init__', 'delete'):
            notifyfunc(self.updateEnsemblePulldown,
                       'ccp.molecule.MolStructure.StructureEnsemble', func)

    def updateProject(self, project):

        if project:
            self.project = project
            self.nmrProject = project.currentNmrProject or self.project.newNmrProject(
                name=project.name)
            self.updateShiftListPulldown()
            self.updateChainPulldown()
            self.updateDangleStorePulldown()
            self.updateConstrSetPulldown()
            self.updateEnsemblePulldown()
            self.updatePredictionMatrixAfter()

    def makeDangleInput(self, filename, chain, shiftList):

        if (not chain) or (not shiftList):
            return

        residues = chain.sortedResidues()

        seq = ''
        for residue in residues:
            if residue.molResidue.chemComp.code1Letter:
                seq += residue.molResidue.chemComp.code1Letter
            else:
                seq += 'X'

        res_0 = residues[0].seqId

        fopen = open(filename, 'w')
        fopen.write('<entry>\n')
        fopen.write('\t<res_0>%d</res_0>\n' % res_0)
        fopen.write('\t<seq_1>%s</seq_1>\n' % seq)
        fopen.write('\t<chain>%s</chain>\n' % chain.code)
        fopen.write('\t<cs_data>\n')
        fopen.write('\t\t<!-- res_id  res_name  atom_name  chemical_shift -->')

        numShift = 0

        for residue in residues:
            for atom in residue.atoms:
                atomSet = atom.getAtomSet()
                shifts = getAtomSetShifts(atomSet, shiftList=shiftList)
                if (len(shifts) == 0):
                    continue

                # to average ambiguous chemical shifts ???????????????????????????
                value = 0.
                for shift in shifts:
                    value += shift.value
                value = value / float(len(shifts))

                at_name = atom.name
                res_name = residue.ccpCode
                res_num = residue.seqId
                fopen.write('\n\t\t%5s\t%s\t%-4s\t%.3f' %
                            (res_num, res_name, at_name, value))

                numShift += 1

        fopen.write('\n\t</cs_data>\n')
        fopen.write('</entry>\n')
        fopen.close()

        return numShift

    def deleteRun(self):

        if self.dangleStore:
            msg = 'Really delete DANGLE run "%s"?' % self.dangleStore.name

            if showOkCancel('Confirm', msg, parent=self):
                self.dangleStore.delete()
                self.dangleStore = None
                self.dangleChain = None
                self.updatePredictionMatrix()
                self.updateDangleStorePulldown()

    def runDangle(self):

        chain = self.chain
        shiftList = self.shiftList

        if (not chain) or (not shiftList):
            showError('Cannot Run DANGLE',
                      'Please specify a chain and a shift list.',
                      parent=self)
            return

        # check if there is a DangleChain available
        self.checkDangleStore()
        dangleStore = self.dangleStore

        if not dangleStore:
            return

        dangleChain = dangleStore.findFirstDangleChain(chain=chain)
        if dangleChain:
            data = (chain.code, dangleChain.shiftList.serial)
            msg = 'Predictions for Chain %s using Shift List %d already exist.\nReplace data?' % data

            if not showYesNo('Replace Data', msg, parent=self):
                return

            else:
                self.dangleChain = dangleChain
                dangleChain.shiftList = shiftList

        else:
            self.dangleChain = dangleStore.newDangleChain(chain=chain,
                                                          shiftList=shiftList)

        #dangleStore.packageLocator.repositories[0].url.dataLocation = '/home/msc51/ccpn/NexusTestGI'
        #dangleStore.packageName = 'cambridge.dangle'

        repository = dangleStore.packageLocator.repositories[0]
        array = dangleStore.packageName.split('.')
        path = os.path.join(repository.url.dataLocation, *array)
        path = os.path.join(path, dangleStore.name,
                            chain.code)  # Dangle_dir/dangleStoreName/chainCode
        if not os.path.exists(path):
            os.makedirs(path)

        self.dangleDir = path

        inputFile = os.path.join(self.dangleDir, 'dangle_cs.inp')
        if os.path.isfile(inputFile):
            os.unlink(inputFile)

        outputFile = os.path.join(self.dangleDir, 'danglePred.txt')
        if os.path.isfile(outputFile):
            os.unlink(outputFile)

        numShift = self.makeDangleInput(inputFile, chain, shiftList)

        if not os.path.isfile(inputFile):
            msg = 'No DANGLE input has been generated.\nPlease check shift lists.'
            showError('File Does Not Exist', msg, parent=self)
            return
        if numShift == 0:
            msg = 'No shift data in input file.\nPerhaps shifts are not assigned.\nContinue prediction anyway?'
            if not showYesNo('Empty DANGLE input', msg, parent=self):
                return

        rejectThresh = self.rejectPulldown.getObject()

        # Use the Reference info from the main installation
        # location must be absolute because DANGLE could be run from anywhere
        location = os.path.dirname(dangleModule.__file__)

        progressBar = ProgressBar(self)
        self.update_idletasks()

        dangle = Dangle(location,
                        inputFile=inputFile,
                        outputDir=self.dangleDir,
                        reject=rejectThresh,
                        angleOnly=False,
                        progressBar=progressBar,
                        writePgm=False)

        #self.dangleDir = '/home/msc51/nexus/gItest/DanglePred/'
        #outputFile =  '/home/msc51/nexus/gItest/DanglePred/danglePred.txt'

        predictions = dangle.predictor.predictions
        gleScores = dangle.predictor.gleScores

        self.readPredictions(predictions, gleScores)
        self.updatePredictionMatrix()

    def readPredictions(self, predictions, gleScores):

        progressBar = ProgressBar(self, text='Reading DANGLE predictions')
        progressBar.total = len(predictions) - 2  # 2 header lines

        residues = self.dangleChain.chain.sortedResidues()
        getDangleResidue = self.dangleChain.findFirstDangleResidue
        newDangleResidue = self.dangleChain.newDangleResidue

        for residue in residues:
            seqId = residue.seqId
            prediction = predictions.get(seqId)

            if prediction is None:
                continue

            gleMatrix = gleScores[seqId]

            progressBar.increment()

            #resNum, resName = prediction[:2];

            numIsland = prediction[2]
            ss = prediction[10]
            angles = [min(179.9999, a) for a in prediction[3:10]]

            phi, phiUpper, phiLower, psi, psiUpper, psiLower, omega = angles

            # Normalise to max
            maxVal = max(gleMatrix)
            gleMatrix = [
                max(0, int(val / maxVal * 65535)) / 65535.0
                for val in gleMatrix
            ]

            dangleResidue = getDangleResidue(residue=residue)
            if not dangleResidue:
                dangleResidue = newDangleResidue(
                    phiPsiLikelihoodMatrix=gleMatrix, residue=residue)

            else:
                dangleResidue.phiPsiLikelihoodMatrix = gleMatrix

            dangleResidue.numIslands = numIsland
            dangleResidue.phiValue = phi
            dangleResidue.phiUpper = phiUpper
            dangleResidue.phiLower = phiLower
            dangleResidue.psiValue = psi
            dangleResidue.psiUpper = psiUpper
            dangleResidue.psiLower = psiLower
            dangleResidue.omegaValue = omega
            dangleResidue.secStrucCode = ss

        progressBar.destroy()

    def readPredictionFile(self, filename, chain):

        try:
            fopen = open(filename, 'r')
        except:
            showError('File Reading Error',
                      'DANGLE prediction file %s cannot be open.' % filename,
                      parent=self)
            return

        lines = fopen.readlines()
        progressBar = ProgressBar(self, text='Reading DANGLE predictions')
        progressBar.total = len(lines) - 2  # 2 header lines
        lines = lines[2:]

        for line in lines:
            progressBar.increment()
            if (line == '\n'):
                continue
            array = line.split()  # keep everything as string
            resNum = int(array[0])
            resName = array[1]
            numIsland = int(array[2])
            phi = array[3]
            phiUpper = array[4]
            phiLower = array[5]
            psi = array[6]
            psiUpper = array[7]
            psiLower = array[8]
            omega = array[9]
            ss = array[10]

            if (phi == 'None'):
                phi = None
            else:
                phi = float(phi)
            if (psi == 'None'):
                psi = None
            else:
                psi = float(psi)
            if (omega == 'None'):
                omega = None
            else:
                omega = float(omega)
                if omega == 180:
                    omega = 179.9
            if (phiUpper == 'None'):
                phiUpper = None
            else:
                phiUpper = float(phiUpper)
            if (phiLower == 'None'):
                phiLower = None
            else:
                phiLower = float(phiLower)
            if (psiUpper == 'None'):
                psiUpper = None
            else:
                psiUpper = float(psiUpper)
            if (psiLower == 'None'):
                psiLower = None
            else:
                psiLower = float(psiLower)
            if (ss == 'None'):
                ss = None

            path = os.path.join(self.dangleDir, 'Res_%d.pgm' % resNum)
            gleMatrix = self.readGLE(path)
            residue = chain.findFirstResidue(seqId=int(resNum))

            dangleResidue = self.dangleChain.findFirstDangleResidue(
                residue=residue)
            if not dangleResidue:
                dangleResidue = self.dangleChain.newDangleResidue(
                    phiPsiLikelihoodMatrix=gleMatrix, residue=residue)
            else:
                dangleResidue.phiPsiLikelihoodMatrix = gleMatrix

            dangleResidue.numIslands = numIsland
            dangleResidue.phiValue = phi
            dangleResidue.phiUpper = phiUpper
            dangleResidue.phiLower = phiLower
            dangleResidue.psiValue = psi
            dangleResidue.psiUpper = psiUpper
            dangleResidue.psiLower = psiLower
            dangleResidue.omegaValue = omega
            dangleResidue.secStrucCode = ss

            # Delete temp pgm files to save space once data is in CCPN
            os.unlink(path)

        fopen.close()
        progressBar.destroy()

    def readGLE(self, gleFile):

        if not os.path.isfile(gleFile):
            msg = 'No scorogram Res_%d.pgm\nin directory %s.' % (
                resNum, self.dangleDir)
            showError('File Reading Error', msg, parent=self)
            return None

        fopen = open(gleFile, 'r')
        lines = fopen.readlines()
        dims = lines[2].split()
        lines = lines[4:]
        fopen.close()

        # only read the top left corner of a 10X10 square bin
        # all readings in the same bin are identical
        binSize = 10
        matrix = []
        for j in range(36):
            x = j * binSize * binSize * 36
            for i in range(36):
                y = i * binSize
                v = int(lines[x + y].strip())
                matrix.append(v)

        maxVal = float(max(matrix))
        for i in range(len(matrix)):
            matrix[i] = matrix[i] / maxVal

        return matrix

    def getPhiPsiPredictions(self):

        #if self.dangleChain:
        # dResidues = self.dangleChain.dangleResidues

        dResidues = self.predictionMatrix.objectList

        phiData = []
        psiData = []
        for dResidue in dResidues:
            resNum = dResidue.residue.seqCode
            phi = dResidue.phiValue
            psi = dResidue.psiValue
            phiData.append((resNum, phi))
            psiData.append((resNum, psi))

        return (phiData, psiData)

    def clearSelected(self):

        for dangleResidue in self.predictionMatrix.currentObjects:
            dangleResidue.numIslands = None
            dangleResidue.phiValue = None
            dangleResidue.psiValue = None
            dangleResidue.omegaValue = None
            dangleResidue.phiUpper = None
            dangleResidue.phiLower = None
            dangleResidue.psiUpper = None
            dangleResidue.psiLower = None
            dangleResidue.secStrucCode = None

        self.updatePredictionMatrixAfter()

    def storeSecondaryStructure(self):

        if not self.dangleChain:
            return

        getSpinSystem = self.nmrProject.findFirstResonanceGroup
        newSpinSystem = self.nmrProject.newResonanceGroup

        n = 0
        for dangleResidue in self.dangleChain.dangleResidues:
            ssCode = dangleResidue.secStrucCode

            if not ssCode:
                continue

            residue = dangleResidue.residue
            if not residue:
                continue

            spinSystem = getSpinSystem(residue=residue)

            if not spinSystem:
                spinSystem = newSpinSystem(residue=residue,
                                           ccpCode=residue.ccpCode)

            spinSystem.secStrucCode = ssCode
            n += 1

        showInfo('Info',
                 'Stored secondary structure types for %d residues.' % n,
                 parent=self)

    def storeDihedralConstraints(self):

        if not self.dangleChain:
            return

        # make a new dihedralConstraintList
        head = self.constraintSet

        if not head:
            head = self.project.newNmrConstraintStore(
                nmrProject=self.nmrProject)
            self.constraintSet = head

        chain = self.dangleChain.chain
        shiftList = self.dangleChain.shiftList
        name = 'DANGLE Chain %s:%s ShiftList %d' % (
            chain.molSystem.code, chain.code, shiftList.serial)
        constraintList = head.newDihedralConstraintList(name=name,
                                                        measureListSerials=[
                                                            shiftList.serial,
                                                        ])

        # traverse the sequence and make appropriate constraint objects
        residues = chain.sortedResidues()
        for residue in residues:
            # Ensure we have atomSets etc
            getResidueMapping(residue)

        residueList = [(dr.residue.seqCode, dr.residue, dr)
                       for dr in self.dangleChain.dangleResidues]
        residueList.sort()

        cnt = 0

        for seqCode, residue, dangleResidue in residueList:

            phi = dangleResidue.phiValue
            psi = dangleResidue.psiValue

            if (phi is None) and (psi is None):
                continue

            # Use below functions because residues may not be sequentially numbered
            prevRes = getLinkedResidue(residue, 'prev')
            nextRes = getLinkedResidue(residue, 'next')
            if (prevRes is None) or (nextRes is None):
                continue

            C__1 = prevRes.findFirstAtom(name='C')  # C (i-1)
            N_0 = residue.findFirstAtom(name='N')  # N (i)
            CA_0 = residue.findFirstAtom(name='CA')  # CA(i)
            C_0 = residue.findFirstAtom(name='C')  # N (i)
            N_1 = nextRes.findFirstAtom(name='N')  # C (i+1)

            # get fixedResonances
            fixedResonances = []
            for atom in (C__1, N_0, CA_0, C_0, N_1):
                atomSet = atom.atomSet

                if atomSet.resonanceSets:
                    resonance = atomSet.findFirstResonanceSet(
                    ).findFirstResonance()

                else:
                    # make new resonance
                    if not atom.chemAtom:
                        print 'no chem atom'

                    ic = atom.chemAtom.elementSymbol
                    if (ic == 'C'):
                        ic = '13' + ic
                    elif (ic == 'N'):
                        ic = '15' + ic

                    resonance = self.nmrProject.newResonance(isotopeCode=ic)
                    assignAtomsToRes([
                        atomSet,
                    ], resonance)
                fixedResonances.append(getFixedResonance(head, resonance))

            # make dihedralConstraints
            phiResonances = (fixedResonances[0], fixedResonances[1],
                             fixedResonances[2], fixedResonances[3])
            phiConstraint = constraintList.newDihedralConstraint(
                resonances=phiResonances)

            psiResonances = (fixedResonances[1], fixedResonances[2],
                             fixedResonances[3], fixedResonances[4])
            psiConstraint = constraintList.newDihedralConstraint(
                resonances=psiResonances)

            # make constraint items

            if phi is not None:
                phiConstraint.newDihedralConstraintItem(
                    targetValue=phi,
                    upperLimit=dangleResidue.phiUpper,
                    lowerLimit=dangleResidue.phiLower)
                cnt += 1

            if psi is not None:
                psiConstraint.newDihedralConstraintItem(
                    targetValue=psi,
                    upperLimit=dangleResidue.psiUpper,
                    lowerLimit=dangleResidue.psiLower)
                cnt += 1

        showInfo('Success',
                 'DANGLE has generated %d dihedral restraints.' % cnt,
                 parent=self)

    def loadGLEs(self, dRes, row, col):

        residue = dRes.residue
        title = '%d %s' % (residue.seqCode, residue.ccpCode)

        self.fillGlePlot(self.plot, dRes.phiPsiLikelihoodMatrix, title)

        prevDangleRes = self.getDangleResidue(dRes, 'prev')
        if prevDangleRes:
            self.fillGlePlot(self.prevPlot,
                             prevDangleRes.phiPsiLikelihoodMatrix)
        else:
            self.fillGlePlot(self.prevPlot, [0] * 1296)  # blank

        nextDangleRes = self.getDangleResidue(dRes, 'next')
        if nextDangleRes:
            self.fillGlePlot(self.nextPlot,
                             nextDangleRes.phiPsiLikelihoodMatrix)
        else:
            self.fillGlePlot(self.nextPlot, [0] * 1296)  # blank

        self.updatePhiPsi(dRes.residue)

    def fillGlePlot(self, plot, gleMatrix, title=None):

        scaleCol = plot.scaleColorQuick

        if self.colorScheme == 'black':
            plot.nullColor = '#000000'
        else:
            plot.nullColor = '#FFFFFF'

        itemconf = plot.canvas.itemconfigure
        matrix = plot.matrix

        for j in range(36):
            for i in range(36):
                v = gleMatrix[j * 36 + i]
                #if (v < 0.005):
                #  color = plot.nullColor
                #else:
                color = self.getPlotColor(v)
                item = matrix[i][j]

                if plot.binWidth < 7:
                    itemconf(item, fill=color, outline=color)
                elif plot.binWidth < 12:
                    itemconf(item, fill=color, outline=scaleCol(color, 0.9))
                else:
                    itemconf(item, fill=color, outline=scaleCol(color, 0.8))

        if title:
            itemconf(plot.title, text=title)

    def getDangleResidue(self, dRes, direction):
        # return a DangleResidue object located offset-residue away from dRes in sequence

        # Use below function to guard against non-sequentially numbered residues
        # the below function follows bonds, but uses a cache for speed
        residue = getLinkedResidue(dRes.residue, direction)

        if residue and self.dangleChain:
            return self.dangleChain.findFirstDangleResidue(residue=residue)

    def showPrevious(self):

        if not self.dangleResidue:
            return

        prevDangleResidue = self.getDangleResidue(self.dangleResidue, 'prev')
        if not prevDangleResidue:
            return

        self.predictionMatrix.selectObject(prevDangleResidue)
        #self.dangleResidue = prevDangleResidue
        #self.loadGLEs(self.dangleResidue, None, None)
        #self.predictionMatrix.currentObject = self.dangleResidue
        #self.predictionMatrix.hilightObject(self.predictionMatrix.currentObject)

    def showNext(self):

        if not self.dangleResidue:
            return

        nextDangleResidue = self.getDangleResidue(self.dangleResidue, 'next')
        if not nextDangleResidue:
            return

        self.predictionMatrix.selectObject(nextDangleResidue)
        #self.dangleResidue = nextDangleResidue
        #self.loadGLEs(self.dangleResidue, None, None)
        #self.predictionMatrix.currentObject = self.dangleResidue
        #self.predictionMatrix.hilightObject(self.predictionMatrix.currentObject)

    def updatePhiPsi(self, residue):

        if self.ensemble:
            phiPsiAccept = []
            plotObjects = []
            colors = []

            cChain = self.ensemble.findFirstCoordChain(code=residue.chain.code)

            if cChain:
                cResidue = cChain.findFirstResidue(residue=residue)

                if cResidue:
                    for model in self.ensemble.models:
                        phiPsiAccept.append(self.getPhiPsi(cResidue, model))
                        plotObjects.append((cResidue, model))
                        colors.append(ENSEMBLE_COLOR)

            if self.colorScheme == 'rainbow':  # default grey circles
                self.plot.updateObjects(phiPsiAccList=phiPsiAccept,
                                        objectList=plotObjects)
            else:  # bright green circles
                self.plot.updateObjects(phiPsiAccList=phiPsiAccept,
                                        objectList=plotObjects,
                                        colors=colors)

    def getPhiPsi(self, residue, model=None):

        phi, psi = getResiduePhiPsi(residue, model=model)
        return (phi, psi, 1)

    def getPlotColor(self, i, maxInt=255):

        mode = self.colorScheme
        if mode == 'rainbow':
            if (i == 0):
                return '#%02x%02x%02x' % (255, 255, 255)  # white bg
            elif (i > 0.75):
                red = 1
                green = (1 - i) / 0.25
                blue = 0
            elif (i > 0.5):
                red = (i - 0.5) / 0.25
                green = 1
                blue = 0
            elif (i > 0.25):
                red = 0
                green = 1
                blue = (0.5 - i) / 0.25
            else:
                red = 0
                green = i / 0.25
                blue = 1
            return '#%02x%02x%02x' % (red * maxInt, green * maxInt,
                                      blue * maxInt)
        """
    elif mode == 'black':
      if i > 0.5:
        red   = i
        green = 1 - i
        blue  = 1 - i
      else:
        v = 0.1 + (0.9 * i)
        red   = v
        green = v
        blue  = v
        
    elif mode == 'white':
      if i > 0.5:
        red   = i
        green = 1 - i
        blue  = 1 - i
      else:
        v = 1.0 - (0.9 * i)
        red   = v
        green = v
        blue  = v

    return '#%02x%02x%02x' % (red*maxInt, green*maxInt, blue*maxInt)
    """

        # default : red to black

        if (i == 0):
            return '#%02x%02x%02x' % (255, 255, 255)  # white bg

        return '#%02x%02x%02x' % (((1 - i) * 255), 0, 0)

    def updatePredictionMatrixAfter(self, index=None, text=None):

        if self.chain and self.shiftList and self.dangleStore:
            self.dangleChain = self.dangleStore.findFirstDangleChain(
                chain=self.chain, shiftList=self.shiftList)
        else:
            self.dangleChain = None

        self.after_idle(self.updatePredictionMatrix)

        #if showYesNo('Not Found','No data for Chain %s in Dangle Run %s.\nMake prediction for this chain?' % (self.chain.code, text), parent=self):
        #  self.runDangle()

    def updatePredictionMatrix(self):

        shiftList = self.shiftList
        objectList = []
        textMatrix = []
        colorMatrix = []

        if self.dangleChain:
            residueList = [(dr.residue.seqCode, dr.residue, dr)
                           for dr in self.dangleChain.dangleResidues]
            residueList.sort()
        else:
            # Chow blank table
            residueList = []

        for seqCode, residue, dRes in residueList:
            objectList.append(dRes)

            phi = dRes.phiValue
            psi = dRes.psiValue
            ss = dRes.secStrucCode

            atomNames = []
            for atomName in BACKBONE_ATOMS:
                atom = residue.findFirstAtom(name=atomName)
                if not atom:
                    continue

                atomSet = atom.atomSet

                if atomSet:
                    shifts = getAtomSetShifts(atomSet, shiftList=shiftList)
                    if shifts:
                        atomNames.append(atomName)

            atomNames.sort()
            atomNames = ' '.join(atomNames)

            textMatrix.append((seqCode, residue.ccpCode, dRes.numIslands, ss,
                               phi, psi, dRes.phiUpper, dRes.phiLower,
                               dRes.psiUpper, dRes.psiLower, atomNames))

            if (phi is None) and (psi is None):
                colorMatrix.append(INACTIVE_COLORS)

            elif dRes.numIslands >= 5:
                colorMatrix.append(BAD_COLORS)

            else:
                colorMatrix.append(GOOD_COLORS)

        self.predictionMatrix.update(textMatrix=textMatrix,
                                     objectList=objectList,
                                     colorMatrix=colorMatrix)

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

        self.dangleResidue = dRes
        self.row = row
        self.col = col
        self.loadGLEs(dRes, row, col)

    def setFloatEntry(self, event):

        index = self.col - 4  # index of attribute to set in the EDIT_ATTRS list
        value = self.floatEntry.get()

        if value is not None:
            setattr(self.dangleResidue, EDIT_ATTRS[index], value)
            self.updatePredictionMatrixAfter()

    def getFloatEntry(self, dangleResidue):

        if dangleResidue:
            index = self.col - 4  # index of attribute to set in the EDIT_ATTRS list
            self.floatEntry.set(getattr(dangleResidue, EDIT_ATTRS[index]))

    def changeChain(self, chain):

        if chain is not self.chain:
            self.chain = chain
            self.updateEnsemblePulldown(
            )  # Ensembles are filtered by chains molSystem
            self.updatePredictionMatrixAfter()

    def changeShiftList(self, shiftList):

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

    def changeEnsemble(self, ensemble):

        self.ensemble = ensemble

    def changeConstraintSet(self, constraintSet):

        if constraintSet is not self.constraintSet:
            self.constraintSet = constraintSet

    def changeDangleStore(self, dangleStore):

        if self.dangleStore is not dangleStore:
            self.dangleStore = dangleStore

            if dangleStore:
                self.dangleChain = dangleStore.findFirstDangleChain()
                self.chain = self.dangleChain.chain
                self.shiftList = self.dangleChain.shiftList
            else:
                self.dangleChain = None

            self.updateChainPulldown()
            self.updateShiftListPulldown()
            self.updateEnsemblePulldown(
            )  # Ensembles are filtered by chains molSystem
            self.updatePredictionMatrixAfter()

    def checkDangleStore(self):

        if not self.dangleStore:

            N = len(self.project.dangleStores) + 1
            name = askString('Request',
                             'Dangle Run Name:',
                             'Run%d' % N,
                             parent=self)
            if not name:
                return None

            for character in whitespace:
                if character in name:
                    showWarning('Failure',
                                'Name cannot contain whitespace',
                                parent=self)
                    return None

            if self.project.findFirstDangleStore(name=name):
                showWarning('Failure', 'Name already used', parent=self)
                return None

            self.dangleStore = self.project.newDangleStore(name=name)
            self.updateDangleStorePulldown()

    def updateChainPulldown(self, obj=None):

        index = 0
        names = []
        chains = []
        chain = self.chain

        for molSystem in self.project.molSystems:
            msCode = molSystem.code

            for chainA in molSystem.chains:
                residues = chainA.residues

                if not residues:
                    continue

                for residue in residues:
                    # Must have at least one protein residue
                    if residue.molType == 'protein':
                        names.append('%s:%s' % (msCode, chainA.code))
                        chains.append(chainA)
                        break

        if chains:
            if chain not in chains:
                chain = chains[0]

            index = chains.index(chain)

        else:
            chain = None

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

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

    def updateShiftListPulldown(self, obj=None):

        index = 0
        names = []
        shiftLists = getShiftLists(self.nmrProject)

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

            index = shiftLists.index(self.shiftList)
            names = ['%s:%d' % (sl.name, sl.serial) for sl in shiftLists]

        else:
            self.shiftList = None

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

    def updateDangleStorePulldown(self):

        names = [
            '<New>',
        ]
        dangleStores = [
            None,
        ]

        for dangleStore in self.project.sortedDangleStores():
            names.append(dangleStore.name)
            dangleStores.append(dangleStore)

        if self.dangleStore not in dangleStores:
            self.dangleStore = dangleStores[-1]

        index = dangleStores.index(self.dangleStore)

        self.dangleStorePulldown.setup(names, dangleStores, index)

    def updateEnsemblePulldown(self, obj=None):

        index = 0
        names = [
            '<None>',
        ]
        ensembles = [
            None,
        ]

        if self.chain:
            molSystem = self.chain.molSystem

            for ensemble in molSystem.sortedStructureEnsembles():
                names.append('%s:%d' % (molSystem.code, ensemble.ensembleId))
                ensembles.append(ensemble)

            if self.ensemble not in ensembles:
                self.ensemble = ensembles[0]

            index = ensembles.index(self.ensemble)

        self.ensemblePulldown.setup(names, ensembles, index)

    def updateConstrSetPulldown(self, obj=None):

        names = [
            '<New>',
        ]
        constraintSets = [
            None,
        ]

        # Use below later, once API speed/loading is improved
        # for constraintSet in self.nmrProject.sortedNmrConstraintStores():

        for constraintSet in self.project.sortedNmrConstraintStores():
            names.append('%d' % constraintSet.serial)
            constraintSets.append(constraintSet)

        if self.constraintSet not in constraintSets:
            self.constraintSet = constraintSets[0]

        index = constraintSets.index(self.constraintSet)

        self.constrSetPulldown.setup(names, constraintSets, index)

    def try1(self):

        if not self.project:
            return

        ccpCodes = [
            'Ala', 'Cys', 'Asp', 'Glu', 'Phe', 'Gly', 'His', 'Ile', 'Lys',
            'Leu', 'Met', 'Asn', 'Gln', 'Arg', 'Ser', 'Thr', 'Val', 'Trp',
            'Tyr', 'Pro'
        ]

        atomNames = ['HA', 'CA', 'CB', 'C', 'N']

        molType = 'protein'

        for ccpCode in ccpCodes:
            for atomName in atomNames:

                chemAtomNmrRef = getChemAtomNmrRef(self.project, atomName,
                                                   ccpCode, molType)
                mean = chemAtomNmrRef.meanValue
                sd = chemAtomNmrRef.stdDev

                print '%5s%5s   %.3f   %.3f' % (ccpCode, atomName, mean, sd)
示例#18
0
class SecStructurePredictPopup(BasePopup):
    """
  **Predict Protein Secondary Structure**
  
  This popup window is designed to allow the prediction of secondary structure
  for a protein chain given chemical shifts, using the (external) program D2D.

  The Options to select are the Chain and the Shift List, for which the
  prediction is then made.

  The Secondary Structure Predictions table lists the residues in the chain.
  For each residue the residue number, residue type and current secondary
  structure set for that residue is given.  The remaining columns are for
  the predictions made by D2D, and of course are only filled in once D2D
  is run.  The predicted secondary structure is listed first, followed by
  the probability of that residue being Helix, Beta, Coil or PPII (the
  predicted secondary structure will be specified by the maximum of these).
  
  To run the prediction click on the "Run D2D Prediction!" button.  This
  does not store this information in the project.  To do that you have to
  click on the "Commit Predicted Secondary Structure" button.

  **Caveats & Tips**

  The predicted secondary structure cell is coloured red if the prediction
  is unreliable.  Unreliable predictions are not stored with the "Commit"
  button but all reliable ones are.  If you need to edit the secondary
  structure for a residue then use the Secondary Structure Chart:

  .. _Secondary Structure Chart: SecStructureGraphPopup.html

  **References**

  The D2D programme:

  http://www-vendruscolo.ch.cam.ac.uk/d2D/index.php

  *C. Camilloni, A. De Simone, W. Vranken and M. Vendruscolo.
  Determination of Secondary Structure Populations in Disordered States of Proteins using NMR Chemical Shifts.
  Biochemistry 2012, 51: 2224-2231
  """
    def __init__(self, parent, *args, **kw):

        self.chain = None
        self.shiftList = None
        self.predictionDict = {}

        BasePopup.__init__(self,
                           parent=parent,
                           title='Structure : Predict Secondary Structure')

    def body(self, guiFrame):

        self.geometry('700x500')

        guiFrame.expandGrid(1, 0)

        row = 0

        # TOP LEFT FRAME

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

        label = Label(frame, text='Chain')
        label.grid(row=0, column=0, sticky='w')
        self.chainPulldown = PulldownList(
            frame,
            callback=self.changeChain,
            tipText='Choose the molecular system chain to make predictions for'
        )
        self.chainPulldown.grid(row=0, column=1, sticky='w')

        label = Label(frame, text='Shift List')
        label.grid(row=0, column=2, sticky='w')
        self.shiftListPulldown = PulldownList(
            frame,
            callback=self.changeShiftList,
            tipText='Select the shift list to take input chemical shifts from')
        self.shiftListPulldown.grid(row=0, column=3, sticky='w')

        row += 1

        # BOTTOM LEFT FRAME

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

        tipTexts = ('Residue number in chain', 'Residue type code',
                    'Current stored secondary structure code',
                    'Predicted secondary structure code') + SEC_STRUC_TIPS

        headingList = ('Res\nNum', 'Res\nType', 'Current\nSS',
                       'Predicted\nSS') + SEC_STRUC_KEYS

        n = len(headingList)
        editWidgets = n * [None]
        editGetCallbacks = n * [None]
        editSetCallbacks = n * [None]

        self.predictionMatrix = ScrolledMatrix(
            frame,
            headingList=headingList,
            tipTexts=tipTexts,
            editWidgets=editWidgets,
            editGetCallbacks=editGetCallbacks,
            editSetCallbacks=editSetCallbacks)
        self.predictionMatrix.grid(row=0, column=0, sticky='nsew')

        row += 1

        tipTexts = [
            'Run the D2D method to predict secondary structure',
            'Store the secondary structure predictions in the CCPN project'
        ]

        texts = [
            'Run D2D Prediction!', 'Commit Predicted\nSecondary Structure'
        ]
        commands = [self.runD2D, self.storeSecondaryStructure]
        self.buttonList = createDismissHelpButtonList(guiFrame,
                                                      texts=texts,
                                                      commands=commands,
                                                      help_url=self.help_url,
                                                      expands=True,
                                                      tipTexts=tipTexts)
        self.buttonList.grid(row=row, column=0, columnspan=2, sticky='ew')

        self.update()

        self.notify(self.registerNotify)

    def destroy(self):

        self.notify(self.unregisterNotify)
        BasePopup.destroy(self)

    def notify(self, notifyfunc):

        for func in ('__init__', 'delete'):
            notifyfunc(self.updateChainPulldown,
                       'ccp.molecule.MolSystem.Chain', func)

        for func in ('__init__', 'delete', 'setName'):
            notifyfunc(self.updateShiftListPulldown, 'ccp.nmr.Nmr.ShiftList',
                       func)

        for func in ('setSecStrucCode', ):
            notifyfunc(self.updatePredictionMatrixAfter,
                       'ccp.nmr.Nmr.ResonanceGroup', func)

    def update(self):

        self.updateShiftListPulldown()
        self.updateChainPulldown()
        self.updatePredictionMatrixAfter()

    def runD2D(self):

        chain = self.chain
        shiftList = self.shiftList

        if (not chain) or (not shiftList):
            showError('Cannot Run D2D',
                      'Please specify a chain and a shift list.',
                      parent=self)
            return

        self.predictionDict[chain] = runD2D(chain, shiftList)

        self.updatePredictionMatrix()

    def storeSecondaryStructure(self):

        if not self.chain:
            return

        getSpinSystem = self.nmrProject.findFirstResonanceGroup
        newSpinSystem = self.nmrProject.newResonanceGroup

        predDict = self.predictionDict.get(self.chain, {})

        n = 0
        for residue in predDict:
            (ssCode, isReliable, probabilityDict) = predDict[residue]

            if isReliable:
                spinSystem = getSpinSystem(residue=residue)

                if not spinSystem:
                    spinSystem = newSpinSystem(residue=residue,
                                               ccpCode=residue.ccpCode)

                spinSystem.secStrucCode = ssCode
                n += 1

        showInfo('Info',
                 'Stored secondary structure types for %d residues.' % n,
                 parent=self)

    def updatePredictionMatrixAfter(self, index=None, text=None):

        self.after_idle(self.updatePredictionMatrix)

    def updatePredictionMatrix(self):

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

        n = len(SEC_STRUC_KEYS)
        chain = self.chain
        if chain:
            predDict = self.predictionDict.get(chain, {})

            getSpinSystem = self.nmrProject.findFirstResonanceGroup
            for residue in chain.sortedResidues():
                spinSystem = getSpinSystem(residue=residue)
                currentSsCode = spinSystem and spinSystem.secStrucCode

                data = [residue.seqCode, residue.ccpCode, currentSsCode]
                colors = 3 * [None]
                if residue in predDict:
                    (ssCode, isReliable, probabilityDict) = predDict[residue]
                    data.append(ssCode)
                    if isReliable:
                        colors.append(None)
                    else:
                        colors.append('#FF3333')
                    for key in SEC_STRUC_KEYS:
                        data.append(probabilityDict[key])
                    colors.extend(n * [None])
                else:
                    data.extend((n + 1) * [None])
                    colors.extend((n + 1) * [None])

                textMatrix.append(data)
                objectList.append(residue)
                colorMatrix.append(colors)

        self.predictionMatrix.update(textMatrix=textMatrix,
                                     objectList=objectList,
                                     colorMatrix=colorMatrix)

    def changeChain(self, chain):

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

    def changeShiftList(self, shiftList):

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

    def updateChainPulldown(self, obj=None):

        index = 0
        names = []
        chains = []
        chain = self.chain

        for molSystem in self.project.molSystems:
            msCode = molSystem.code

            for chainA in molSystem.chains:
                residues = chainA.residues

                if not residues:
                    continue

                for residue in residues:
                    # Must have at least one protein residue
                    if residue.molType == 'protein':
                        names.append('%s:%s' % (msCode, chainA.code))
                        chains.append(chainA)
                        break

        if chains:
            if chain not in chains:
                chain = chains[0]

            index = chains.index(chain)

        else:
            chain = None

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

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

    def updateShiftListPulldown(self, obj=None):

        index = 0
        names = []
        shiftLists = getShiftLists(self.nmrProject)

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

            index = shiftLists.index(self.shiftList)
            names = ['%s:%d' % (sl.name, sl.serial) for sl in shiftLists]

        else:
            self.shiftList = None

        self.shiftListPulldown.setup(names, shiftLists, index)
示例#19
0
class SelectionListPopup(TemporaryBasePopup):
 
  def __init__(self, parent, selectionList, title = 'Select', text = 'Select', topText = None, dismissText = None, selected = None, selectionDict = None, urlFile = None, dismissButton = True, modal = False):
  
    self.selectionList = selectionList
    self.selectionDict = selectionDict
    
    self.text = text
    
    self.dismissButton = dismissButton
    
    if dismissButton:
      if dismissText:
        self.dismissText = dismissText
      else:
        self.dismissText = 'dismiss'
      
    self.topText = topText
    self.isSelected = None

    if not selected:
      self.selectedIndex = 0
    else:
      self.selectedIndex = self.selectionList.index(selected)
      
    if urlFile:
      self.help_url = joinPath(getHelpUrlDir(),urlFile + '.html')
    else:
      self.help_url = None
          
    TemporaryBasePopup.__init__(self,parent = parent, title = title, modal = modal, transient=True)
 
  def body(self, master):
    
    #
    # Popup window
    #

    row = 0
    
    if self.topText:
      label = Label(master, text= self.topText)
      label.grid(row=row, column=0, columnspan = 2, sticky=Tkinter.EW)
    
      row = row + 1

    label = Label(master, text= self.text)
    label.grid(row=row, column=0, sticky=Tkinter.EW)

    self.menu = PulldownList(master, texts = self.selectionList, index = self.selectedIndex)
    self.menu.grid(row=row, column=1, sticky=Tkinter.E, ipadx = 20)
 
    row = row + 1
    texts = [ 'OK' ]
    commands = [ self.ok ]   # This calls 'ok' in BasePopup, this then calls 'apply' in here
    
    if self.dismissButton:
      buttons = createDismissHelpButtonList(master, texts=texts, commands=commands, dismiss_text = self.dismissText, help_url=self.help_url)
    else:
      buttons = createHelpButtonList(master, texts=texts, commands=commands, help_url=self.help_url)

    buttons.grid(row=row, column=0, columnspan = 3)
   

  def apply(self):
        
    self.isSelected = self.menu.getText()
    
    if self.selectionDict:
      self.selection = self.selectionDict[self.isSelected]
    else:
      self.selection = self.isSelected

    return True