Source code for ccpn.ui.gui.popups.CopyPeakListPopup

"""
Module Documentation here
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (http://www.ccpn.ac.uk) 2014 - 2022"
__credits__ = ("Ed Brooksbank, Joanna Fox, Victoria A Higman, Luca Mureddu, Eliza Płoskoń",
               "Timothy J Ragan, Brian O Smith, Gary S Thompson & Geerten W Vuister")
__licence__ = ("CCPN licence. See http://www.ccpn.ac.uk/v3-software/downloads/license")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
                 "CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
                 "J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$modifiedBy: Geerten Vuister $"
__dateModified__ = "$dateModified: 2022-02-01 15:30:08 +0000 (Tue, February 01, 2022) $"
__version__ = "$Revision: 3.0.4 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: CCPN $"
__date__ = "$Date: 2017-03-30 11:28:58 +0100 (Thu, March 30, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================

from ccpn.ui.gui.widgets.Label import Label
from ccpn.ui.gui.widgets.PulldownList import PulldownList
from ccpn.ui.gui.popups.Dialog import CcpnDialogMainWidget
from ccpn.util.Logging import getLogger
from ccpn.ui.gui.widgets.MessageDialog import showWarning
from ccpn.core.lib.ContextManagers import undoBlockWithoutSideBar, notificationEchoBlocking
from ccpn.ui.gui.widgets.RadioButtons import RadioButtons, RadioButtonsWithSubCheckBoxes
from ccpn.ui.gui.widgets.RadioButton import CheckBoxCheckedText, CheckBoxCallbacks, CheckBoxTexts, CheckBoxTipTexts
from collections import OrderedDict as od
from ccpn.ui.gui.widgets.MessageDialog import showWarning, _stoppableProgressBar, progressManager
import ccpn.ui.gui.widgets.CompoundWidgets as cw

_OnlyPositionAndAssignments = 'Copy position and assignments'
_IncludeAllPeakProperties   = 'Copy all existing properties'
_SnapToExtremum             = 'Snap to extremum'
_RefitPeaks                 = 'Refit peaks'
_RefitPeaksAtPosition       = 'Refit peaks at position'
_RecalculateVolume          = 'Recalculate volume'
_tipTextOnlyPos             = f'''Copy Peaks and include only the original position and assignments (if available).\nAdditionally, execute the selected operations'''
_tipTextIncludeAll          = f'''Copy Peaks and include all the original properties: \nPosition, Assignments, Heights, Linewidths, Volumes etc...'''
_tipTextSnapToExtremum      = 'Snap all new peaks to extremum. Default properties set in the General Preferences'
_tipTextRefitPeaks          = 'Refit all new peaks. Default properties set in the General Preferences'
_tipTextRefitPeaksAtPosition= 'Refit peaks and force to maintain the original position. Default properties set in the General Preferences'
_tipTextRecalculateVolume   = 'Recalculate volume for all peaks. Requires a Refit.'


[docs]class CopyPeakListPopup(CcpnDialogMainWidget): def __init__(self, parent=None, mainWindow=None, title='Copy PeakList', spectrumDisplay=None, selectItem=None, **kwds): super().__init__(parent, setLayout=True, size=(350, 250),minimumSize=(450, 250), windowTitle=title, **kwds) if mainWindow: self.mainWindow = mainWindow self.application = self.mainWindow.application self.project = self.mainWindow.project self.current = self.application.current else: self.mainWindow = None self.application = None self.project = None self.current = None self.spectrumDisplay = spectrumDisplay self.sourcePeakList = None self.targetSpectrum = None self.defaultPeakList = self._getDefaultPeakList() if selectItem is None else \ self.application.get(selectItem) self.setWidgets() self._populate() # enable the buttons self.setOkButton(callback=self._okClicked, tipText='Copy PeakList') self.setCloseButton(callback=self.reject, tipText='Close popup') self.setDefaultButton(CcpnDialogMainWidget.CLOSEBUTTON) self.__postInit__() self._extraActionDefs = { _SnapToExtremum: self._snapPeaksToExtremum, _RefitPeaks: self._refitPeaks, _RecalculateVolume: self._recalculateVolume, _RefitPeaksAtPosition: self._refitPeaks, }
[docs] def setWidgets(self): self.sourcePeakListPullDownCW = cw.PulldownListCompoundWidget(self.mainWidget, labelText='Source PeakList', grid=(0, 0), callback=self._populateTargetSpectraPullDown) self.sourcePeakListPullDown = self.sourcePeakListPullDownCW.pulldownList self.targetSpectraPullDownCW = cw.PulldownListCompoundWidget(self.mainWidget, labelText='Target Spectrum', grid=(1, 0)) self.targetSpectraPullDown = self.targetSpectraPullDownCW.pulldownList checkBoxTexts = [_SnapToExtremum, _RefitPeaks, _RefitPeaksAtPosition, _RecalculateVolume] checkBoxTipTexts = [_tipTextSnapToExtremum, _tipTextRefitPeaks, _tipTextRefitPeaksAtPosition, _tipTextRecalculateVolume] checkBoxesDict = od([ (_OnlyPositionAndAssignments, { CheckBoxTexts: checkBoxTexts, CheckBoxCheckedText: [_SnapToExtremum, _RefitPeaks, _RecalculateVolume], CheckBoxTipTexts: checkBoxTipTexts, CheckBoxCallbacks: [self._subSelectionCallback] * len(checkBoxTexts) } ), ]) self.copyOptionsRadioButtons = RadioButtonsWithSubCheckBoxes(self.mainWidget, texts=[_OnlyPositionAndAssignments, _IncludeAllPeakProperties], selectedInd=0, tipTexts=[_tipTextOnlyPos, _tipTextIncludeAll], checkBoxesDictionary=checkBoxesDict, grid=(2, 0), )
def _populate(self): self._populateSourcePeakListPullDown() self._populateTargetSpectraPullDown() def _okClicked(self): with undoBlockWithoutSideBar(): self.sourcePeakList = self.project.getByPid(self.sourcePeakListPullDown.getText()) self.targetSpectrum = self.project.getByPid(self.targetSpectraPullDown.getText()) self._copyPeakListToSpectrum() self.accept() def _executeAfterCopyPeaks(self, peakList): # execute further operations to the new peakList if required. ddValues = self.copyOptionsRadioButtons.get() extraActionsTexts = ddValues.get(_OnlyPositionAndAssignments, []) for action in extraActionsTexts: func = self._extraActionDefs.get(action) if func: func(peakList) def _copyPeakListToSpectrum(self): includeAllProperties = self.copyOptionsRadioButtons.getSelectedText() == _IncludeAllPeakProperties if self.sourcePeakList is not None: try: if self.targetSpectrum is not None: with progressManager(self, 'Copying Peaks. See terminal window for more info...'): newPeakList = self.sourcePeakList.copyTo(self.targetSpectrum, includeAllPeakProperties=includeAllProperties) self._executeAfterCopyPeaks(newPeakList) except Exception as es: getLogger().warning('Error copying peakList: %s' % str(es)) showWarning(str(self.windowTitle()), str(es)) def _populateSourcePeakListPullDown(self): """Populate the pulldown with the list of spectra in the project """ if not self.project: return if len(self.project.peakLists) == 0: raise RuntimeError('Project has no PeakList\'s') sourcePullDownData = [str(pl.pid) for pl in self.project.peakLists] self.sourcePeakListPullDown.setData(sourcePullDownData) if self.defaultPeakList is not None: self.sourcePeakListPullDown.select(self.defaultPeakList.pid) self.sourcePeakList = self.defaultPeakList # self._selectDefaultPeakList() def _populateTargetSpectraPullDown(self, *args): """Populate the pulldown with the list of spectra on the selected spectrumDisplay and select the first visible spectrum """ if not self.project: return sourcePeakList = self.application.get(args[0]) if len(args)>0 else self.sourcePeakList if sourcePeakList is None: visibleSpectra = spectra = self.project.spectra else: _dimCount = sourcePeakList.spectrum.dimensionCount visibleSpectra = spectra = [spec for spec in self.project.spectra if spec.dimensionCount <= _dimCount] if self.spectrumDisplay is not None: _tmp = self.spectrumDisplay.strips[0].getVisibleSpectra() visibleSpectra = [spec for spec in _tmp if spec.dimensionCount <= _dimCount] if spectra: targetPullDownData = [str(sp.pid) for sp in spectra] self.targetSpectraPullDown.setData(targetPullDownData) if visibleSpectra: self.targetSpectraPullDown.select(visibleSpectra[0].pid) def _getDefaultPeakList(self): """:return the default PeakList based on current settings, or None """ result = None if not self.current: return result if self.current.peak is not None: result = self.current.peak.peakList elif self.current.strip is not None and not self.current.strip.isDeleted: _spec = self.current.strip.spectra[0] result = _spec.peakLists[-1] elif len(self.project.peakLists)>0: result = self.project.peakLists[0] return result def _subSelectionCallback(self, checked): """ This routine is to ensure there are not mutually exclusive selections. Behaviour: allowed combinations: - _SnapToExtremum, _RefitPeaks, _RecalculateVolume - _SnapToExtremum, _RecalculateVolume - _RefitPeaks, _RecalculateVolume - _RefitPeaksAtPosition, _RecalculateVolume not allowed: - _RecalculateVolume alone - _RefitPeaksAtPosition excludes any of _RefitPeaks, _SnapToExtremum It is convoluted and a refactor might be needed for readability. But double check the intended behaviour is maintained! :param checked: bool :return: None """ clicked = self.sender().getText() radioButton = self.copyOptionsRadioButtons.getRadioButtonByText(_OnlyPositionAndAssignments) _include = radioButton.getSelectedCheckBoxes() _exclude = [] if clicked == _RefitPeaksAtPosition: if checked: _exclude += [_SnapToExtremum, _RefitPeaks] if clicked == _SnapToExtremum: _exclude += [_RefitPeaksAtPosition] if clicked == _RefitPeaks: _exclude += [_RefitPeaksAtPosition] if _RecalculateVolume in _include: if _RefitPeaks not in _include: if _RefitPeaksAtPosition not in _include: _include += [_RefitPeaks] newSelection = list(set([i for i in _include if i not in _exclude])) radioButton.setSelectedCheckBoxes(newSelection) def _refitPeaks(self, peakList, keepPosition=False): peaks = peakList.peaks fitMethod = self.application.preferences.general.peakFittingMethod getLogger().info('Refitting peaks') with undoBlockWithoutSideBar(): with notificationEchoBlocking(): for peak in peaks: peak.fit(fitMethod=fitMethod, keepPosition=keepPosition) def _refitPeaksAtPositions(self, peakList, keepPosition=True): self._refitPeaks(peakList, keepPosition=keepPosition) def _recalculateVolume(self, peakList): getLogger().info('Recalculating peak volumes.') with undoBlockWithoutSideBar(): with notificationEchoBlocking(): peakList.estimateVolumes() def _snapPeaksToExtremum(self, peakList): # get the default from the preferences minDropFactor = self.application.preferences.general.peakDropFactor searchBoxMode = self.application.preferences.general.searchBoxMode searchBoxDoFit = self.application.preferences.general.searchBoxDoFit fitMethod = self.application.preferences.general.peakFittingMethod peaks = peakList.peaks getLogger().info('Snapping Peaks To Extremum.') with undoBlockWithoutSideBar(): with notificationEchoBlocking(): peaks.sort(key=lambda x: x.position[0], reverse=False) # reorder peaks by position for peak in peaks: peak.snapToExtremum(halfBoxSearchWidth=4, halfBoxFitWidth=4, minDropFactor=minDropFactor, searchBoxMode=searchBoxMode, searchBoxDoFit=searchBoxDoFit, fitMethod=fitMethod)
if __name__ == '__main__': from ccpn.ui.gui.widgets.Application import TestApplication import ccpn.core.testing.WrapperTesting as WT app = TestApplication() thisWT = WT.WrapperTesting() thisWT.setUp() app.project = thisWT.project popup = CopyPeakListPopup() # too many errors for testing here... popup.show() popup.raise_() app.start() WT.WrapperTesting.tearDown(thisWT)