"""
Module Documentation here
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (https://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 https://ccpn.ac.uk/software/licensing/")
__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: Luca Mureddu $"
__dateModified__ = "$dateModified: 2022-04-05 12:14:15 +0100 (Tue, April 05, 2022) $"
__version__ = "$Revision: 3.1.0 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: CCPN $"
__date__ = "$Date: 2017-04-07 10:28:41 +0000 (Fri, April 07, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================
from typing import List, Tuple, Sequence
from copy import deepcopy
from functools import partial
import numpy as np
from PyQt5 import QtWidgets, QtCore, QtGui
from ccpn.core.Peak import Peak
from ccpn.core.PeakList import PeakList
from ccpn.core.lib.Notifiers import Notifier
from ccpn.core.lib.ContextManagers import undoStackBlocking, undoBlock, \
notificationBlanking, undoBlockWithoutSideBar
from ccpn.ui.gui.guiSettings import getColours, CCPNGLWIDGET_HEXHIGHLIGHT, CCPNGLWIDGET_HEXFOREGROUND
from ccpn.util.Logging import getLogger
from ccpn.util.Constants import AXIS_MATCHATOMTYPE, AXIS_FULLATOMNAME, DOUBLEAXIS_FULLATOMNAME
from ccpn.util.decorators import logCommand
from ccpn.util.Colour import colorSchemeTable
from ccpn.ui.gui.guiSettings import GUISTRIP_PIVOT, ZPlaneNavigationModes
from ccpn.ui.gui.widgets.Frame import Frame
from ccpn.ui.gui.widgets.Widget import Widget
from ccpn.ui.gui.widgets.DropBase import DropBase
from ccpn.ui.gui.widgets import MessageDialog
from ccpn.ui.gui.lib.GuiNotifier import GuiNotifier
from ccpn.ui.gui.lib.OpenGL.CcpnOpenGLDefs import AXISXUNITS, AXISYUNITS, \
SYMBOLTYPES, ANNOTATIONTYPES, SYMBOLSIZE, SYMBOLTHICKNESS, AXISASPECTRATIOS, AXISASPECTRATIOMODE, \
BOTTOMAXIS, RIGHTAXIS, ALIASENABLED, ALIASSHADE, ALIASLABELSENABLED, CONTOURTHICKNESS, \
PEAKLABELSENABLED, MULTIPLETLABELSENABLED, SPECTRUM_STACKEDMATRIXOFFSET
from ccpn.util.Constants import AXISUNIT_PPM, AXISUNIT_HZ, AXISUNIT_POINT
STRIPLABEL_ISPLUS = 'stripLabel_isPlus'
STRIP_MINIMUMWIDTH = 100
STRIP_MINIMUMHEIGHT = 150
DefaultMenu = 'DefaultMenu'
PeakMenu = 'PeakMenu'
IntegralMenu = 'IntegralMenu'
MultipletMenu = 'MultipletMenu'
AxisMenu = 'AxisMenu'
PhasingMenu = 'PhasingMenu'
[docs]class GuiStrip(Frame):
# inherits NotifierBase
optionsChanged = QtCore.pyqtSignal(dict)
stripResized = QtCore.pyqtSignal(tuple)
# MAXPEAKLABELTYPES = 6
# MAXPEAKSYMBOLTYPES = 4
def __init__(self, spectrumDisplay):
"""
Basic graphics strip class; used in StripNd and Strip1d
:param spectrumDisplay: spectrumDisplay instance
This module inherits attributes from the Strip wrapper class:
Use clone() method to make a copy
"""
# For now, cannot set spectrumDisplay attribute as it is owned by the wrapper class
# self.spectrumDisplay = spectrumDisplay
self.mainWindow = self.spectrumDisplay.mainWindow
self.application = self.mainWindow.application
self.current = self.application.current
super().__init__(parent=spectrumDisplay.stripFrame, setLayout=True, showBorder=False,
spacing=(0, 0), acceptDrops=True #, hPolicy='expanding', vPolicy='expanding' ##'minimal'
)
self.setMinimumWidth(STRIP_MINIMUMWIDTH)
self.setMinimumHeight(STRIP_MINIMUMHEIGHT)
# stripArrangement = getattr(self.spectrumDisplay, 'stripArrangement', None)
# if stripArrangement == 'X':
# headerGrid = (0, 0)
# openGLGrid = (0, 1)
# stripToolBarGrid = (0, 2)
# else:
# headerGrid = (0, 0)
# openGLGrid = (1, 0)
# stripToolBarGrid = (2, 0)
headerGrid = (0, 0)
headerSpan = (1, 5)
openGLGrid = (1, 0)
openGlSpan = (10, 5)
stripToolBarGrid = (11, 0)
stripToolBarSpan = (1, 5)
if spectrumDisplay.is1D:
from ccpn.ui.gui.widgets.GLWidgets import Gui1dWidget as CcpnGLWidget
else:
from ccpn.ui.gui.widgets.GLWidgets import GuiNdWidget as CcpnGLWidget
self._CcpnGLWidget = CcpnGLWidget(strip=self, mainWindow=self.mainWindow)
self.getLayout().addWidget(self._CcpnGLWidget, *openGLGrid, *openGlSpan)
self._CcpnGLWidget.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
self.stripLabel = None
self.header = None #StripHeader(parent=self, mainWindow=self.mainWindow, strip=self,
# grid=headerGrid, gridSpan=headerSpan, setLayout=True, spacing=(0, 0))
# set the ID label in the new widget
self._CcpnGLWidget.setStripID('.'.join(self.pid.split('.')))
# self._CcpnGLWidget.setStripID('')
# Widgets for toolbar; items will be added by GuiStripNd (e.g. the Z/A-plane boxes)
# and GuiStrip1d; will be hidden for 2D's by GuiSpectrumView
self._stripToolBarWidget = Widget(parent=self, setLayout=True,
grid=stripToolBarGrid, gridSpan=stripToolBarSpan)
self._stripToolBarWidget.getLayout().setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.viewStripMenu = None
self.storedZooms = []
# self.beingUpdated = False
self.planeAxisBars = ()
# need to keep track of mouse position because Qt shortcuts don't provide
# the widget or the position of where the cursor is
self.axisPositionDict = {} # axisCode --> position
self._contextMenuMode = DefaultMenu
self._contextMenus = {DefaultMenu : None,
PeakMenu : None,
PhasingMenu : None,
MultipletMenu: None,
IntegralMenu : None,
AxisMenu : None
}
self.navigateToPeakMenu = None #set from context menu and in CcpnOpenGL rightClick
self.navigateToCursorMenu = None #set from context menu and in CcpnOpenGL rightClick
self._isPhasingOn = False
self._preferences = self.application.preferences.general
# set symbolLabelling to the default from preferences or strip to the left
settings = spectrumDisplay._getSettingsDict()
if len(spectrumDisplay.strips) > 1:
_firstStrip = spectrumDisplay.strips[0]
# copy the values from the first strip
self.symbolLabelling = min(_firstStrip.symbolLabelling, self.spectrumDisplay.MAXPEAKLABELTYPES - 1)
self.symbolType = min(_firstStrip.symbolType, self.spectrumDisplay.MAXPEAKSYMBOLTYPES - 1)
self.symbolSize = _firstStrip.symbolSize
self.symbolThickness = _firstStrip.symbolThickness
self.aliasEnabled = _firstStrip.aliasEnabled
self.aliasShade = _firstStrip.aliasShade
self.aliasLabelsEnabled = _firstStrip.aliasLabelsEnabled
self.contourThickness = _firstStrip.contourThickness
self.peakLabelsEnabled = _firstStrip.peakLabelsEnabled
self.multipletLabelsEnabled = _firstStrip.multipletLabelsEnabled
self.gridVisible = _firstStrip.gridVisible
self.crosshairVisible = _firstStrip.crosshairVisible
self.doubleCrosshairVisible = _firstStrip.doubleCrosshairVisible
self.sideBandsVisible = _firstStrip.sideBandsVisible
self.showSpectraOnPhasing = _firstStrip.showSpectraOnPhasing
self._spectrumBordersVisible = _firstStrip._spectrumBordersVisible
if spectrumDisplay.stripArrangement == 'Y':
if self.spectrumDisplay.lastAxisOnly:
self.setAxesVisible(False, True)
else:
self.setAxesVisible(True, True)
elif spectrumDisplay.stripArrangement == 'X':
if self.spectrumDisplay.lastAxisOnly:
self.setAxesVisible(True, False)
else:
self.setAxesVisible(True, True)
# set the axis units from the current settings
# self.xUnits = _firstStrip.xUnits
# self.yUnits = _firstStrip.yUnits
# self._CcpnGLWidget._useLockedAspect = spectrumDisplay.strips[0]._CcpnGLWidget._useLockedAspect
else:
# get the values from the preferences
self.gridVisible = self._preferences.showGrid
self.crosshairVisible = self._preferences.showCrosshair
self.doubleCrosshairVisible = self._preferences.showDoubleCrosshair
self.sideBandsVisible = self._preferences.showSideBands
self.showSpectraOnPhasing = self._preferences.showSpectraOnPhasing
self._spectrumBordersVisible = self._preferences.showSpectrumBorder
# get the values from the settings (check in case the number of states has changed)
self.symbolLabelling = min(settings[ANNOTATIONTYPES], self.spectrumDisplay.MAXPEAKLABELTYPES - 1)
self.symbolType = min(settings[SYMBOLTYPES], self.spectrumDisplay.MAXPEAKSYMBOLTYPES - 1)
self.symbolSize = settings[SYMBOLSIZE]
self.symbolThickness = settings[SYMBOLTHICKNESS]
self.contourThickness = settings[CONTOURTHICKNESS]
self.aliasEnabled = settings[ALIASENABLED]
self.aliasShade = settings[ALIASSHADE]
self.aliasLabelsEnabled = settings[ALIASLABELSENABLED]
self.peakLabelsEnabled = settings[PEAKLABELSENABLED]
self.multipletLabelsEnabled = settings[MULTIPLETLABELSENABLED]
self.spectrumDisplay._setFloatingAxes(xUnits=settings[AXISXUNITS],
yUnits=settings[AXISYUNITS],
aspectRatioMode=settings[AXISASPECTRATIOMODE],
aspectRatios=settings[AXISASPECTRATIOS])
self.setAxesVisible(True, True)
# set the axis units from the current settings
# self.xUnits = settings[AXISXUNITS]
# self.yUnits = settings[AXISYUNITS]
self._CcpnGLWidget._aspectRatioMode = settings[AXISASPECTRATIOMODE]
self._CcpnGLWidget._aspectRatios = deepcopy(settings[AXISASPECTRATIOS])
self._CcpnGLWidget._applyXLimit = self._preferences.zoomXLimitApply
self._CcpnGLWidget._applyYLimit = self._preferences.zoomYLimitApply
self._storedPhasingData = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
self.showActivePhaseTrace = True
self.pivotLine = None
self._lastClickedObjects = None
self._newPosition = None
self._hTraceActive = False
self._vTraceActive = False
self._newConsoleDirection = None
self._noiseThresholdLinesActive = False
# initialise the notifiers
self.setStripNotifiers()
# test aliasing notifiers
# self._currentVisibleAliasingRange = {}
# self._currentAliasingRange = {}
# respond to values changed in the containing spectrumDisplay settings widget
self.spectrumDisplay._spectrumDisplaySettings.symbolsChanged.connect(self._symbolsChangedInSettings)
[docs] def resizeEvent(self, ev):
super().resizeEvent(ev)
# call subclass _resize event
self._resize()
self.stripResized.emit((self.width(), self.height()))
def _resize(self):
"""Resize event to handle resizing of frames that overlay the OpenGL frame
"""
# MUST BE SUBCLASSED
raise NotImplementedError("Code error: function not implemented")
def _selectCallback(self, widgets):
# print('>>>select', widget1, widget2)
# if the first widget is clicked then toggle the planeToolbar buttons
if widgets[3].isVisible():
widgets[3].hide()
widgets[1].show()
else:
widgets[1].hide()
widgets[3].show()
self._resize()
def _enterCallback(self, widget1, widget2):
# print('>>>_enterCallback', widget1, widget2)
pass
def _leaveCallback(self, widget1, widget2):
# print('>>>_leaveCallback', widget1, widget2)
# widget2.hide()
widget1.show()
[docs] def setStripNotifiers(self):
"""Set the notifiers for the strip.
"""
# GWV 20181127: moved to GuiMainWindow
# GWV 20181127: moved to GuiMainWindow
# notifier for highlighting the strip
# self._stripNotifier = Notifier(self.current, [Notifier.CURRENT], 'strip', self._highlightCurrentStrip)
# Notifier for updating the peaks
self.setNotifier(self.project, [Notifier.CREATE, Notifier.DELETE, Notifier.CHANGE],
'Peak', self._updateDisplayedPeaks, onceOnly=True)
self.setNotifier(self.project, [Notifier.CREATE, Notifier.DELETE, Notifier.RENAME],
'NmrAtom', self._updateDisplayedNmrAtoms, onceOnly=True)
# Notifier for updating the integrals
self.setNotifier(self.project, [Notifier.CREATE, Notifier.DELETE, Notifier.CHANGE],
'Integral', self._updateDisplayedIntegrals, onceOnly=True)
# Notifier for updating the multiplets
self.setNotifier(self.project, [Notifier.CREATE, Notifier.DELETE, Notifier.CHANGE],
'Multiplet', self._updateDisplayedMultiplets, onceOnly=True)
# Notifier for change of stripLabel
self.setNotifier(self.project, [Notifier.RENAME], 'Spectrum', self._updateSpectrumLabels)
# # Notifier for change of stripLabel
# self.setNotifier(self.project, [Notifier.RENAME], 'NmrResidue', self._updateStripLabel)
# For now, all dropEvents are not strip specific, use spectrumDisplay's handling
self.setGuiNotifier(self, [GuiNotifier.DROPEVENT], [DropBase.URLS, DropBase.PIDS],
self.spectrumDisplay._processDroppedItems)
[docs] def viewRange(self):
return self._CcpnGLWidget.viewRange()
@property
def gridVisible(self):
"""True if grid is visible.
"""
return self._CcpnGLWidget._gridVisible
@gridVisible.setter
def gridVisible(self, visible):
"""set the grid visibility
"""
if hasattr(self, 'gridAction'):
self.gridAction.setChecked(visible)
self._CcpnGLWidget._gridVisible = visible
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
# GWV 07/01/2022: removed
# @property
# def xUnits(self):
# """Current xUnits
# """
# return self._CcpnGLWidget._xUnits
#
# @xUnits.setter
# def xUnits(self, units):
# """set the xUnits
# """
# self._CcpnGLWidget._xUnits = units
#
# # spawn a redraw of the GL windows
# self._CcpnGLWidget.GLSignals.emitPaintEvent()
#
# @property
# def yUnits(self):
# """Current yUnits
# """
# return self._CcpnGLWidget._yUnits
#
# @yUnits.setter
# def yUnits(self, units):
# """set the yUnits
# """
# self._CcpnGLWidget._yUnits = units
#
# # spawn a redraw of the GL windows
# self._CcpnGLWidget.GLSignals.emitPaintEvent()
@property
def sideBandsVisible(self):
"""True if sideBands are visible.
"""
return self._CcpnGLWidget._sideBandsVisible
@sideBandsVisible.setter
def sideBandsVisible(self, visible):
"""set the sideBands visibility
"""
if hasattr(self, 'sideBandsAction'):
self.sideBandsAction.setChecked(visible)
self._CcpnGLWidget._sideBandsVisible = visible
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
@property
def spectrumBordersVisible(self):
"""True if spectrumBorders are visible.
"""
return self._CcpnGLWidget._spectrumBordersVisible
@spectrumBordersVisible.setter
def spectrumBordersVisible(self, visible):
"""set the spectrumBorders visibility
"""
if hasattr(self, 'spectrumBordersAction'):
self.spectrumBordersAction.setChecked(visible)
self._CcpnGLWidget._spectrumBordersVisible = visible
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
[docs] def toggleGrid(self):
"""Toggles whether grid is visible in the strip.
"""
self.gridVisible = not self._CcpnGLWidget._gridVisible
[docs] def toggleSideBands(self):
"""Toggles whether sideBands are visible in the strip.
"""
self.sideBandsVisible = not self._CcpnGLWidget._sideBandsVisible
@property
def crosshairVisible(self):
"""True if crosshair is visible.
"""
return self._CcpnGLWidget._crosshairVisible
@crosshairVisible.setter
def crosshairVisible(self, visible):
"""set the crosshairVisible visibility
"""
if hasattr(self, 'crosshairAction'):
self.crosshairAction.setChecked(visible)
self._CcpnGLWidget._crosshairVisible = visible
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
def _toggleCrosshair(self):
"""Toggles whether crosshair is visible.
"""
self.crosshairVisible = not self._CcpnGLWidget._crosshairVisible
def _showCrosshair(self):
"""Displays crosshair in strip.
"""
self.crosshairVisible = True
def _hideCrosshair(self):
"""Hides crosshair in strip.
"""
self.crosshairVisible = False
def _crosshairCode(self, axisCode):
"""Determines what axisCodes are compatible as far as drawing crosshair is concerned
TBD: the naive approach below should be improved
"""
return axisCode #if axisCode[0].isupper() else axisCode
@property
def doubleCrosshairVisible(self):
"""True if doubleCrosshair is visible.
"""
return self._CcpnGLWidget._doubleCrosshairVisible
@doubleCrosshairVisible.setter
def doubleCrosshairVisible(self, visible):
"""set the doubleCrosshairVisible visibility
"""
if hasattr(self, 'doubleCrosshairAction'):
self.doubleCrosshairAction.setChecked(visible)
self._CcpnGLWidget._doubleCrosshairVisible = visible
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
def _toggleDoubleCrosshair(self):
"""Toggles whether doubleCrosshair is visible.
"""
self.doubleCrosshairVisible = not self._CcpnGLWidget._doubleCrosshairVisible
# GWV; commented 24/12/21
# @property
# def pythonConsole(self):
# return self.mainWindow.pythonConsole
def _showPeakOnPLTable(self):
current = self.application.current
peaks = current.peaks
clickedPeaks = self._lastClickedObjects
if not (peaks or clickedPeaks):
return
if len(peaks) == 1:
peak = peaks[-1]
peakTableModule = self.application.showPeakTable(peakList=peak.peakList)
[docs] def setStackingMode(self, value):
pass
[docs] def getStackingMode(self):
pass
def _updateStripLabel(self, callbackDict):
"""Update the striplabel if it represented a NmrResidue that has changed its id.
"""
# self.header.processNotifier(callbackDict)
pass
[docs] def createMark(self):
"""Sets the marks at current position
"""
self.spectrumDisplay.mainWindow.createMark()
[docs] def clearMarks(self):
"""Sets the marks at current position
"""
self.spectrumDisplay.mainWindow.clearMarks()
[docs] def estimateNoise(self):
"""Estimate noise in the current region
"""
from ccpn.ui.gui.popups.EstimateNoisePopup import EstimateNoisePopup
popup = EstimateNoisePopup(parent=self.mainWindow, mainWindow=self.mainWindow, strip=self,
orderedSpectrumViews=self.getSpectrumViews())
popup.exec_()
popup._cleanupWidget()
[docs] def toggleNoiseThresholdLines(self):
pass
[docs] def makeStripPlot(self, includePeakLists=True, includeNmrChains=True, includeSpectrumTable=False):
"""Make a strip plot in the current spectrumDisplay
"""
from ccpn.ui.gui.popups.StripPlotPopup import StripPlotPopup
popup = StripPlotPopup(parent=self.mainWindow, mainWindow=self.mainWindow, spectrumDisplay=self.spectrumDisplay,
includePeakLists=includePeakLists, includeNmrChains=includeNmrChains, includeSpectrumTable=includeSpectrumTable)
popup.exec_()
popup._cleanupWidget()
[docs] def calibrateFromPeaks(self):
if self.current.peaks and len(self.current.peaks) > 1:
if not (self._lastClickedObjects and isinstance(self._lastClickedObjects, Sequence)):
MessageDialog.showMessage('Calibrate error', 'Select a single peak as the peak to calibrate to.')
return
else:
if len(self._lastClickedObjects) > 1:
MessageDialog.showMessage('Too Many Peaks', 'Select a single peak as the peak to calibrate to.')
return
# make sure that selected peaks are unique in each spectrum
spectrumCount = {}
for peak in self.current.peaks:
if peak.peakList.spectrum in spectrumCount:
MessageDialog.showMessage('Too Many Peaks', 'Only select one peak in each spectrum')
break
else:
spectrumCount[peak.peakList.spectrum] = peak
else:
# popup to calibrate from selected peaks in this display
from ccpn.ui.gui.popups.CalibrateSpectraFromPeaksPopup import CalibrateSpectraFromPeaksPopupNd, CalibrateSpectraFromPeaksPopup1d
if self.spectrumDisplay.is1D:
popup = CalibrateSpectraFromPeaksPopup1d(parent=self.mainWindow, mainWindow=self.mainWindow,
strip=self, spectrumCount=spectrumCount)
else:
popup = CalibrateSpectraFromPeaksPopupNd(parent=self.mainWindow, mainWindow=self.mainWindow,
strip=self, spectrumCount=spectrumCount)
popup.exec_()
else:
MessageDialog.showMessage('Not Enough Peaks', 'Select more than one peak, only one per spectrum')
[docs] def close(self):
self.deleteAllNotifiers()
super().close()
def _updateSpectrumLabels(self, data):
"""Callback when spectra have changed
"""
self._CcpnGLWidget._processSpectrumNotifier(data)
def _updateDisplayedPeaks(self, data):
"""Callback when peaks have changed
"""
self._CcpnGLWidget._processPeakNotifier(data)
def _updateDisplayedNmrAtoms(self, data):
"""Callback when nmrAtoms have changed
"""
self._CcpnGLWidget._processNmrAtomNotifier(data)
def _updateDisplayedMultiplets(self, data):
"""Callback when multiplets have changed
"""
self._CcpnGLWidget._processMultipletNotifier(data)
[docs] def refreshDevicePixelRatio(self):
"""Set the devicePixel ratio in the GL window
"""
self._CcpnGLWidget.refreshDevicePixelRatio()
[docs] def refresh(self):
"""Refresh the display for strip and redraw contours
"""
self._CcpnGLWidget._updateVisibleSpectrumViews()
# redraw the contours
from ccpn.ui.gui.lib.OpenGL.CcpnOpenGL import GLNotifier
GLSignals = GLNotifier(parent=self)
for specNum, thisSpecView in enumerate(self.spectrumViews):
thisSpecView.buildContours = True
GLSignals.emitPaintEvent()
def _checkMenuItems(self):
"""Update the menu check boxes from the strip
Subclass if options needed, e.g. stackSpectra item
"""
pass
def _createMenuItemForNavigate(self, currentStrip, navigateAxes, navigatePos, showPos, strip, menuFunc, label, includeAxisCodes=True):
from ccpn.ui.gui.lib.StripLib import navigateToPositionInStrip
if includeAxisCodes:
item = ', '.join([cc + ":" + str(x if isinstance(x, str) else round(x, 3)) for x, cc in zip(showPos, strip.axisCodes)])
else:
item = ', '.join([str(x if isinstance(x, str) else round(x, 3)) for x in showPos])
text = '%s (%s)' % (strip.pid, item)
toolTip = 'Show cursor in strip %s at %s position (%s)' % (str(strip.id), label, item)
# if len(list(set(strip.axisCodes) & set(currentStrip.axisCodes))) > 0:
menuFunc.addItem(text=text,
callback=partial(navigateToPositionInStrip, strip=strip,
positions=navigatePos,
axisCodes=navigateAxes, ),
toolTip=toolTip)
# else:
# print('skipping axisCodes %s %s' % (strip.axisCodes, currentStrip.axisCodes))
def _createCommonMenuItem(self, currentStrip, includeAxisCodes, label, menuFunc, perm, position, strip):
showPos = []
navigatePos = []
navigateAxes = []
for jj, ii in enumerate(perm):
if ii is not None:
showPos.append(position[ii])
navigatePos.append(position[ii])
navigateAxes.append(strip.axisCodes[jj])
else:
showPos.append(' - ')
self._createMenuItemForNavigate(currentStrip, navigateAxes, navigatePos, showPos, strip, menuFunc, label,
includeAxisCodes=includeAxisCodes)
def _addItemsToNavigateMenu(self, position, axisCodes, label, menuFunc, includeAxisCodes=True):
"""Adds item to navigate to section of context menu.
"""
from ccpn.core.lib.AxisCodeLib import getAxisCodeMatchIndices
from itertools import product
if not menuFunc:
return
menuFunc.clear()
currentStrip = self
if len(self.current.project.spectrumDisplays) > 0:
menuFunc.setEnabled(True)
# matchingItemAdded = False
for spectrumDisplay in self.current.project.spectrumDisplays:
for strip in spectrumDisplay.strips:
# add the opposite diagonals for matching axisCodes - always at the top of the list
if strip == currentStrip:
indices = getAxisCodeMatchIndices(strip.axisCodes, axisCodes, allMatches=False)
allIndices = getAxisCodeMatchIndices(strip.axisCodes, axisCodes, allMatches=True)
permutationList1 = [jj for jj in product(*(ii if ii else (None,) for ii in allIndices)) if len(set(jj)) == len(strip.axisCodes)]
for perm in permutationList1:
# skip any that match the original indexing
if any(ii != jj for ii, jj in zip(perm, indices)):
self._createCommonMenuItem(currentStrip, includeAxisCodes, label, menuFunc, perm, position, strip)
menuFunc.addSeparator()
# try:
# # flip the first two axes, easy to do it here
# flipAxisCodes = [strip.axisCodes[1], strip.axisCodes[0]] + list(strip.axisCodes[2:])
#
# # get a list of all isotope code matches for each axis code in 'strip' matched to the flipped axes
# perm = getAxisCodeMatchIndices(flipAxisCodes, axisCodes, allMatches=False)
#
# self._createCommonMenuItem(currentStrip, includeAxisCodes, label, menuFunc, perm, position, strip)
# menuFunc.addSeparator()
# # matchingItemAdded = True
#
# except Exception as es:
# # just skip if an error (but there shouldn't be any here)
# pass
# if not matchingItemAdded:
# print('>>> skipping menuitem')
# menuFunc.addItem(text='Skip matching isotopeCodes')
# menuFunc.addSeparator()
for spectrumDisplay in self.current.project.spectrumDisplays:
for strip in spectrumDisplay.strips:
if strip != currentStrip:
# get a list of all isotope code matches for each axis code in 'strip'
indices = getAxisCodeMatchIndices(strip.axisCodes, axisCodes, allMatches=True)
# generate a permutation list of the axis codes that have unique indices
# permutation list is list of tuples
# each element is list of indices to fetch from currentStrip and map to strip
# permutationList1 = [jj for jj in product(*(ii if ii else (None,) for ii in indices)) if len(set(jj)) == len(strip.axisCodes)]
permutationList1 = [jj for jj in product(*(ii if ii else (None,) for ii in indices))] # if len(set(jj)) == len(strip.axisCodes)]
# print('>>>', strip.pid, indices)
for perm in permutationList1:
perm2 = [pp if pp is not None else -(cc + 1) for cc, pp in enumerate(perm)]
# print('>>> ', perm, perm2)
if len(set(perm2)) == len(perm2): # ignore None's
self._createCommonMenuItem(currentStrip, includeAxisCodes, label, menuFunc, perm, position, strip)
# menuFunc.addItem(text=' - ')
permutationList2 = [jj for jj in product(*(ii if ii else (None,) for ii in indices)) if len(set(jj)) == len(jj)]
if not permutationList2:
perm = list(getAxisCodeMatchIndices(strip.axisCodes, axisCodes, allMatches=False))
from collections import Counter
from itertools import product
maxIndexList = Counter(perm).most_common(1)
if maxIndexList:
index, maxCount = maxIndexList[0]
if index is not None:
# iterate through all permutations of index/None
combiList = [list(i) for i in product([None, index], repeat=maxCount)]
indices = [ii for ii in range(len(perm)) if perm[ii] == index]
# add all permutations except first (all unset)
for combi in combiList[1:]:
for ind, val in zip(indices, combi):
perm[ind] = val
self._createCommonMenuItem(currentStrip, includeAxisCodes, label, menuFunc, perm, position, strip)
menuFunc.addSeparator()
else:
menuFunc.setEnabled(False)
def _addItemsToNavigateToPeakMenu(self, peaks):
"""Adds item to navigate to peak position from context menu.
"""
if peaks and self._navigateToPeakMenuSelected:
self._addItemsToNavigateMenu(peaks[0].position, peaks[0].axisCodes, 'Peak', self._navigateToPeakMenuSelected, includeAxisCodes=True)
def _addItemsToNavigateToCursorPosMenu(self):
"""Copied from old viewbox. This function apparently take the current cursorPosition
and uses to pan a selected display from the list of spectrumViews or the current cursor position.
"""
if self.navigateCursorMenu:
position = [self.current.mouseMovedDict[AXIS_FULLATOMNAME][ax]
if ax in self.current.mouseMovedDict[AXIS_FULLATOMNAME] else None
for ax in self.axisCodes]
if None in position:
return
self._addItemsToNavigateMenu(position, self.axisCodes, 'Cursor', self.navigateCursorMenu, includeAxisCodes=True)
[docs] def markAxisIndices(self, indices=None):
"""Mark the X/Y/XY axisCodes by index
"""
position = [self.current.mouseMovedDict[AXIS_FULLATOMNAME][ax] for ax in self.axisCodes]
if indices is None:
indices = tuple(range(len(self.axisCodes)))
pos = [position[ii] for ii in indices]
axes = [self.axisCodes[ii] for ii in indices]
self._createMarkAtPosition(positions=pos, axisCodes=axes)
def _addItemsToMenu(self, position, axisCodes, label, menuFunc):
"""Adds item to mark peak position from context menu.
"""
from functools import partial
if hasattr(self, 'markIn%sMenu' % label):
menuFunc.clear()
currentStrip = self
if currentStrip:
if len(self.current.project.spectrumDisplays) > 1:
menuFunc.setEnabled(True)
for spectrumDisplay in self.current.project.spectrumDisplays:
for strip in spectrumDisplay.strips:
if strip != currentStrip:
toolTip = 'Show cursor in strip %s at %s position %s' % (str(strip.id), label, str([round(x, 3) for x in position]))
if len(list(set(strip.axisCodes) & set(currentStrip.axisCodes))) <= 4:
menuFunc.addItem(text=strip.pid,
callback=partial(self._createMarkAtPosition,
positions=position,
axisCodes=axisCodes),
toolTip=toolTip)
menuFunc.addSeparator()
else:
menuFunc.setEnabled(False)
def _addItemsToMarkInPeakMenu(self, peaks):
"""Adds item to mark peak position from context menu.
"""
if peaks and hasattr(self, 'markInPeakMenu'):
self._addItemsToMenu(peaks[0].position, peaks[0].axisCodes, 'Peak', self.markInPeakMenu)
def _addItemsToMarkInCursorPosMenu(self):
"""Copied from old viewbox. This function apparently take the current cursorPosition
and uses to pan a selected display from the list of spectrumViews or the current cursor position.
"""
if hasattr(self, 'markInCursorMenu'):
self._addItemsToMenu(self.current.cursorPosition, self.axisCodes, 'Cursor', self.markInCursorMenu)
def _markSelectedPeaks(self, axisIndex=None):
"""Mark the positions of all selected peaks
"""
with undoBlockWithoutSideBar():
for peak in self.current.peaks:
self._createObjectMark(peak, axisIndex)
def _markSelectedMultiplets(self, axisIndex=None):
"""Mark the positions of all selected multiplets
"""
with undoBlockWithoutSideBar():
for multiplet in self.current.multiplets:
self._createObjectMark(multiplet, axisIndex)
def _addItemsToCopyAxisFromMenusMainView(self):
"""Setup the menu for the main view
"""
# self._addItemsToCopyAxisFromMenus([self.copyAllAxisFromMenu, self.copyXAxisFromMenu, self.copyYAxisFromMenu],
# ['All', 'X', 'Y'])
self._addItemsToCopyAxisFromMenus(((self.copyAllAxisFromMenu, 'All'),
(self.copyXAxisFromMenu, 'X'),
(self.copyYAxisFromMenu, 'Y')))
def _addItemsToCopyAxisFromMenusAxes(self, viewPort, thisMenu, is1D):
"""Setup the menu for the axis views
"""
from ccpn.ui.gui.lib.GuiStripContextMenus import _addCopyMenuItems
copyAttribs, matchAttribs = _addCopyMenuItems(self, viewPort, thisMenu, is1D)
self._addItemsToCopyAxisFromMenus(copyAttribs)
for nm, ax in matchAttribs:
self._addItemsToCopyAxisCodesFromMenus(ax, nm)
def _addItemsToCopyAxisFromMenus(self, copyAttribs): #, axisNames, axisIdList):
"""Copied from old viewbox. This function apparently take the current cursorPosition
and uses to pan a selected display from the list of spectrumViews or the current cursor position.
"""
# TODO needs clear documentation
from functools import partial
axisNames = tuple(nm[0] for nm in copyAttribs)
axisIdList = tuple(nm[1] for nm in copyAttribs)
for axisName, axisId in zip(axisNames, axisIdList):
if axisName:
axisName.clear()
currentStrip = self.current.strip
position = self.current.cursorPosition
count = 0
if currentStrip:
for spectrumDisplay in self.current.project.spectrumDisplays:
for strip in spectrumDisplay.strips:
if strip != currentStrip:
toolTip = 'Copy %s axis range from strip %s' % (str(axisId), str(strip.id))
if len(list(set(strip.axisCodes) & set(currentStrip.axisCodes))) <= 4:
axisName.addItem(text=strip.pid,
callback=partial(self._copyAxisFromStrip,
axisId=axisId, fromStrip=strip, ),
toolTip=toolTip)
count += 1
axisName.addSeparator()
axisName.setEnabled(True if count else False)
def _addItemsToMarkAxesMenuAxesView(self, viewPort, thisMenu):
"""Setup the menu for the main view for marking axis codes
"""
indices = {BOTTOMAXIS: (0,), RIGHTAXIS: (1,)}
if viewPort in indices.keys():
self._addItemsToMarkAxesMenuMainView(thisMenu, indices[viewPort])
def _addItemsToMarkAxesMenuMainView(self, axisMenu=None, indices=None):
"""Setup the menu for the main view for marking axis codes
"""
axisName = axisMenu if axisMenu else self.markAxesMenu
position = [self.current.mouseMovedDict[AXIS_FULLATOMNAME][ax]
if ax in self.current.mouseMovedDict[AXIS_FULLATOMNAME] else None
for ax in self.axisCodes]
if None in position:
return
row = 0
if indices is None:
# get the indices to add to the menu
indices = tuple(range(len(self.axisCodes)))
pos = [position[ii] for ii in indices]
axes = [self.axisCodes[ii] for ii in indices]
toolTip = 'Mark all axis codes'
axisName.addItem(text='Mark All AxisCodes',
callback=partial(self._createMarkAtPosition, positions=pos, axisCodes=axes, ),
toolTip=toolTip)
row += 1
for ind in indices:
pos = [position[ind], ]
axes = [self.axisCodes[ind], ]
toolTip = 'Mark %s axis code' % str(self.axisCodes[ind])
axisName.addItem(text='Mark %s' % str(self.axisCodes[ind]),
callback=partial(self._createMarkAtPosition, positions=pos, axisCodes=axes, ),
toolTip=toolTip)
row += 1
if row:
axisName.addSeparator()
# def _addItemsToMarkAxesMenuXAxisView(self):
# """Setup the menu for the main view for marking axis codes
# """
# axisName = self.markAxesMenu
#
# def _addItemsToMarkAxesMenuYAxisView(self):
# """Setup the menu for the main view for marking axis codes
# """
# axisName = self.markAxesMenu
def _addItemsToMatchAxisCodesFromMenusMainView(self):
"""Setup the menu for the main view
"""
self._addItemsToCopyAxisCodesFromMenus(0, self.matchXAxisCodeToMenu)
self._addItemsToCopyAxisCodesFromMenus(1, self.matchYAxisCodeToMenu)
# def _addItemsToMatchAxisCodesFromMenusAxes(self):
# """Setup the menu for the axis views
# """
# self._addItemsToCopyAxisCodesFromMenus(0, [self.matchXAxisCodeToMenu2, self.matchYAxisCodeToMenu2])
# self._addItemsToCopyAxisCodesFromMenus(1, [self.matchXAxisCodeToMenu2, self.matchYAxisCodeToMenu2])
def _addItemsToCopyAxisCodesFromMenus(self, axisIndex, axisName): #, axisList):
"""Copied from old viewbox. This function apparently take the current cursorPosition
and uses to pan a selected display from the list of spectrumViews or the current cursor position.
"""
# TODO needs clear documentation
from functools import partial
from ccpn.core.lib.AxisCodeLib import getAxisCodeMatchIndices
# axisList = (self.matchXAxisCodeToMenu2, self.matchYAxisCodeToMenu2)
# if axisIndex not in range(len(axisList)):
# return
# axisName = axisList[axisIndex]
axisCode = self.axisCodes[axisIndex]
if axisName:
axisName.clear()
currentStrip = self.current.strip
position = self.current.cursorPosition
count = 0
if currentStrip:
for spectrumDisplay in self.current.project.spectrumDisplays:
addSeparator = False
for strip in spectrumDisplay.strips:
if strip != currentStrip:
indices = getAxisCodeMatchIndices(strip.axisCodes, (axisCode,))
for ii, ind in enumerate(indices):
if ind is not None:
toolTip = 'Copy %s axis range from strip %s' % (str(strip.axisCodes[ii]), str(strip.id))
if len(list(set(strip.axisCodes) & set(currentStrip.axisCodes))) <= 4:
axisName.addItem(text='%s from %s' % (str(strip.axisCodes[ii]), str(strip.pid)),
callback=partial(self._copyAxisCodeFromStrip,
axisIndex=axisIndex, fromStrip=strip, fromAxisId=ii),
toolTip=toolTip)
count += 1
addSeparator = True
if addSeparator:
axisName.addSeparator()
axisName.setEnabled(True if count else False)
# def _enableNdAxisMenuItems(self, axisName, axisMenu):
#
# from ccpn.ui.gui.lib.OpenGL.CcpnOpenGLDefs import BOTTOMAXIS, RIGHTAXIS, AXISCORNER
#
# axisMenuItems = (self.copyAllAxisFromMenu2, self.copyXAxisFromMenu2, self.copyYAxisFromMenu2,
# self.matchXAxisCodeToMenu2, self.matchYAxisCodeToMenu2)
# enabledList = {BOTTOMAXIS: (False, True, False, True, False),
# RIGHTAXIS : (False, False, True, False, True),
# AXISCORNER: (True, True, True, True, True)
# }
# if axisName in enabledList:
# axisSelect = enabledList[axisName]
# for menuItem, select in zip(axisMenuItems, axisSelect):
# # only disable if already enabled
# if menuItem.isEnabled():
# menuItem.setEnabled(select)
# else:
# getLogger().warning('Error selecting menu item')
# def _enable1dAxisMenuItems(self, axisName):
#
# from ccpn.ui.gui.lib.OpenGL.CcpnOpenGLDefs import BOTTOMAXIS, RIGHTAXIS, AXISCORNER
#
# axisMenuItems = (self.copyAllAxisFromMenu2, self.copyXAxisFromMenu2, self.copyYAxisFromMenu2)
# enabledList = {BOTTOMAXIS: (False, True, False),
# RIGHTAXIS : (False, False, True),
# AXISCORNER: (True, True, True)
# }
# if axisName in enabledList:
# axisSelect = enabledList[axisName]
# for menuItem, select in zip(axisMenuItems, axisSelect):
# # only disable if already enabled
# if menuItem.isEnabled():
# menuItem.setEnabled(select)
# else:
# getLogger().warning('Error selecting menu item')
def _updateDisplayedIntegrals(self, data):
"""Callback when integrals have changed.
"""
self._CcpnGLWidget._processIntegralNotifier(data)
def _highlightStrip(self, flag):
"""(un)highLight the strip depending on flag
CCPNINTERNAL: used in GuiMainWindow
"""
self._CcpnGLWidget.highlightCurrentStrip(flag)
if self.stripLabel:
self.stripLabel.setLabelColour(CCPNGLWIDGET_HEXHIGHLIGHT if flag else CCPNGLWIDGET_HEXFOREGROUND)
self.stripLabel.setHighlighted(flag)
def _attachZPlaneWidgets(self):
"""Attach the ZPlane widgets for the current strip into the spectrumDisplay axis frame
"""
spec = self.spectrumDisplay
if spec.is1D or len(spec.axisCodes) <= 2:
return
if spec.zPlaneNavigationMode == ZPlaneNavigationModes.PERSPECTRUMDISPLAY.label:
# only need to change if showing the spectrumDisplay planeToolBar
spec.zPlaneFrame.attachZPlaneWidgets(self)
def _removeZPlaneWidgets(self):
"""Remove the ZPlane widgets for the curent strip from the spectrumDisplay axis frame
"""
spec = self.spectrumDisplay
if spec.is1D or len(spec.axisCodes) <= 2:
return
if spec.zPlaneFrame and spec.zPlaneNavigationMode == ZPlaneNavigationModes.PERSPECTRUMDISPLAY.label:
spec.zPlaneFrame.removeZPlaneWidgets()
def _newPhasingTrace(self):
self._CcpnGLWidget.newTrace()
def _setPhasingPivot(self):
phasingFrame = self.spectrumDisplay.phasingFrame
direction = phasingFrame.getDirection()
# position = self.current.cursorPosition[0] if direction == 0 else self.current.cursorPosition[1]
# position = self.current.positions[0] if direction == 0 else self.current.positions[1]
position = None #GWV; not sure what it should be
mouseMovedDict = self.current.mouseMovedDict
if direction == 0:
for mm in mouseMovedDict[AXIS_MATCHATOMTYPE].keys():
if mm[0] == self.axisCodes[0][0]:
position = mouseMovedDict[AXIS_MATCHATOMTYPE][mm]
else:
for mm in mouseMovedDict[AXIS_MATCHATOMTYPE].keys():
if mm[0] == self.axisCodes[1][0]:
position = mouseMovedDict[AXIS_MATCHATOMTYPE][mm]
phasingFrame.pivotEntry.set(position)
self._updatePivot()
[docs] def removePhasingTraces(self):
self._CcpnGLWidget.clearStaticTraces()
def _updatePivot(self):
# this is called if pivot entry at bottom of display is updated and then "return" key used
# update the static traces from the phasing console
# redraw should update the display
self._CcpnGLWidget.rescaleStaticTraces()
[docs] def setTraceScale(self, traceScale):
for spectrumView in self.spectrumViews:
spectrumView.traceScale = traceScale
@property
def contextMenuMode(self):
return self._contextMenuMode
@contextMenuMode.getter
def contextMenuMode(self):
return self._contextMenuMode
@contextMenuMode.setter
def contextMenuMode(self, mode):
self._contextMenuMode = mode
[docs] def turnOnPhasing(self):
phasingFrame = self.spectrumDisplay.phasingFrame
# self.hPhasingPivot.setVisible(True)
# self.vPhasingPivot.setVisible(True)
# change menu
self._isPhasingOn = True
self.viewStripMenu = self._phasingMenu
if self.spectrumDisplay.is1D:
self._hTraceActive = True
self._vTraceActive = False
self._newConsoleDirection = 0
else:
# TODO:ED remember trace direction
self._hTraceActive = self.spectrumDisplay.hTraceAction # self.hTraceAction.isChecked()
self._vTraceActive = self.spectrumDisplay.vTraceAction # self.vTraceAction.isChecked()
# set to the first active or the remembered phasingDirection
self._newConsoleDirection = phasingFrame.getDirection()
if self._hTraceActive:
self._newConsoleDirection = 0
phasingFrame.directionList.setIndex(0)
elif self._vTraceActive:
self._newConsoleDirection = 1
phasingFrame.directionList.setIndex(1)
# for spectrumView in self.spectrumViews:
# spectrumView._turnOnPhasing()
# # make sure that all traces are clear
# from ccpn.util.CcpnOpenGL import GLNotifier
# GLSignals = GLNotifier(parent=self)
# if self.spectrumDisplay.is1D:
# GLSignals.emitEvent(triggers=[GLNotifier.GLADD1DPHASING], display=self.spectrumDisplay)
# else:
# GLSignals.emitEvent(triggers=[GLNotifier.GLCLEARPHASING], display=self.spectrumDisplay)
vals = self.spectrumDisplay.phasingFrame.getValues(self._newConsoleDirection)
self.spectrumDisplay.phasingFrame.slider0.setValue(vals[0])
self.spectrumDisplay.phasingFrame.slider1.setValue(vals[1])
self.spectrumDisplay.phasingFrame.pivotEntry.set(vals[2])
# TODO:ED remember direction
self._newPosition = phasingFrame.pivotEntry.get()
self.pivotLine = self._CcpnGLWidget.addInfiniteLine(colour='highlight', movable=True, lineStyle='dashed', lineWidth=2.0)
if not self.pivotLine:
getLogger().warning('no infiniteLine')
return
if self._newConsoleDirection == 0:
self.pivotLine.orientation = ('v')
# self.hTraceAction.setChecked(True)
# self.vTraceAction.setChecked(False)
if not self.spectrumDisplay.is1D:
self.hTraceAction.setChecked(True)
self.vTraceAction.setChecked(False)
self._CcpnGLWidget.updateHTrace = True
self._CcpnGLWidget.updateVTrace = False
else:
self.pivotLine.orientation = ('h')
# self.hTraceAction.setChecked(False)
# self.vTraceAction.setChecked(True)
if not self.spectrumDisplay.is1D:
self.hTraceAction.setChecked(False)
self.vTraceAction.setChecked(True)
self._CcpnGLWidget.updateHTrace = False
self._CcpnGLWidget.updateVTrace = True
# connect to the value in the GLwidget
self.pivotLine.valuesChanged.connect(self._newPositionLineCallback)
self.pivotLine.setValue(self._newPosition)
phasingFrame.pivotEntry.valueChanged.connect(self._newPositionPivotCallback)
# # make sure that all traces are clear
# from ccpn.ui.gui.lib.OpenGL.CcpnOpenGL import GLNotifier
#
# GLSignals = GLNotifier(parent=self)
if self.spectrumDisplay.is1D:
self._CcpnGLWidget.GLSignals.emitEvent(triggers=[self._CcpnGLWidget.GLSignals.GLADD1DPHASING], display=self.spectrumDisplay)
else:
self._CcpnGLWidget.GLSignals.emitEvent(triggers=[self._CcpnGLWidget.GLSignals.GLCLEARPHASING], display=self.spectrumDisplay)
def _newPositionLineCallback(self):
if not self.isDeleted:
phasingFrame = self.spectrumDisplay.phasingFrame
self._newPosition = self.pivotLine.values # [0]
# disables feedback from the spinbox as event is spawned from the GLwidget
phasingFrame.setPivotValue(self._newPosition)
spectrumDisplay = self.spectrumDisplay
for strip in spectrumDisplay.strips:
if strip != self:
# set the pivotPosition in the other strips
strip._updatePivotLine(self._newPosition)
def _updatePivotLine(self, newPosition):
"""Respond to changes in the other strips
"""
if not self.isDeleted and self.pivotLine:
self._newPosition = newPosition
# don't emit a signal when changing - stops feedback loop
self.pivotLine.setValue(newPosition, emitValuesChanged=False)
def _newPositionPivotCallback(self, value):
"""Respond to change in value in the spinBox
"""
self._newPosition = value
self.pivotLine.setValue(value)
[docs] def turnOffPhasing(self):
phasingFrame = self.spectrumDisplay.phasingFrame
# self.hPhasingPivot.setVisible(False)
# self.vPhasingPivot.setVisible(False)
# change menu
self._isPhasingOn = False
# for spectrumView in self.spectrumViews:
# spectrumView._turnOffPhasing()
# make sure that all traces are clear
self._CcpnGLWidget.GLSignals.emitEvent(triggers=[self._CcpnGLWidget.GLSignals.GLCLEARPHASING], display=self.spectrumDisplay)
self._CcpnGLWidget.removeInfiniteLine(self.pivotLine)
self.pivotLine.valuesChanged.disconnect(self._newPositionLineCallback)
phasingFrame.pivotEntry.valueChanged.disconnect(self._newPositionPivotCallback)
if self.spectrumDisplay.is1D:
self._CcpnGLWidget.updateHTrace = False
self._CcpnGLWidget.updateVTrace = False
else:
# TODO:ED remember trace direction
self.hTraceAction.setChecked(False) #self._hTraceActive)
self.vTraceAction.setChecked(False) #self._vTraceActive)
self._CcpnGLWidget.updateHTrace = False #self._hTraceActive
self._CcpnGLWidget.updateVTrace = False #self._vTraceActive
def _changedPhasingDirection(self):
phasingFrame = self.spectrumDisplay.phasingFrame
direction = phasingFrame.getDirection()
if not phasingFrame.isVisible():
return
if direction == 0:
self.pivotLine.orientation = ('v')
self.hTraceAction.setChecked(True)
self.vTraceAction.setChecked(False)
self._CcpnGLWidget.updateHTrace = True
self._CcpnGLWidget.updateVTrace = False
else:
self.pivotLine.orientation = ('h')
self.hTraceAction.setChecked(False)
self.vTraceAction.setChecked(True)
self._CcpnGLWidget.updateHTrace = False
self._CcpnGLWidget.updateVTrace = True
vals = phasingFrame.getValues(direction)
# phasingFrame.slider0.setValue(self.spectrumDisplay._storedPhasingData[direction][0])
# phasingFrame.slider1.setValue(self.spectrumDisplay._storedPhasingData[direction][1])
# phasingFrame.pivotEntry.set(self.spectrumDisplay._storedPhasingData[direction][2])
phasingFrame.slider0.setValue(vals[0])
phasingFrame.slider1.setValue(vals[1])
phasingFrame.pivotEntry.set(vals[2])
self._CcpnGLWidget.clearStaticTraces()
# for spectrumView in self.spectrumViews:
# spectrumView._changedPhasingDirection()
def _updatePhasing(self):
if self.spectrumDisplay.phasingFrame.isVisible():
colour = getColours()[GUISTRIP_PIVOT]
self._CcpnGLWidget.setInfiniteLineColour(self.pivotLine, colour)
self._CcpnGLWidget.rescaleStaticTraces()
def _toggleShowActivePhaseTrace(self):
"""Toggles whether the active phasing trace is visible.
"""
self.showActivePhaseTrace = not self.showActivePhaseTrace
self._CcpnGLWidget.showActivePhaseTrace = self.showActivePhaseTrace
def _toggleShowSpectraOnPhasing(self):
"""Toggles whether spectraOnPhasing is visible.
"""
self.showSpectraOnPhasing = not self.showSpectraOnPhasing
self._CcpnGLWidget.showSpectraOnPhasing = self.showSpectraOnPhasing
def _showSpectraOnPhasing(self):
"""Displays spectraOnPhasing in strip.
"""
self.showSpectraOnPhasing = True
self._CcpnGLWidget.showSpectraOnPhasing = True
def _hideSpectraOnPhasing(self):
"""Hides spectraOnPhasing in strip.
"""
self.showSpectraOnPhasing = False
self._CcpnGLWidget.showSpectraOnPhasing = False
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# symbolLabelling
def _setSymbolLabelling(self):
if self.spectrumViews:
for sV in self.spectrumViews:
for peakListView in sV.peakListViews:
# peakListView.buildSymbols = True
peakListView.buildLabels = True
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
@property
def symbolLabelling(self):
"""Get the symbol labelling for the strip
"""
return self._CcpnGLWidget._symbolLabelling
@symbolLabelling.setter
def symbolLabelling(self, value):
"""Set the symbol labelling for the strip
"""
if not isinstance(value, int):
raise TypeError('Error: symbolLabelling not an int')
oldValue = self._CcpnGLWidget._symbolLabelling
self._CcpnGLWidget._symbolLabelling = value if (value in range(self.spectrumDisplay.MAXPEAKLABELTYPES)) else 0
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
[docs] def cycleSymbolLabelling(self):
"""Toggles whether peak labelling is minimal is visible in the strip.
"""
self.symbolLabelling += 1
[docs] def setSymbolLabelling(self, value):
"""Toggles whether peak labelling is minimal is visible in the strip.
"""
self.symbolLabelling = value
def _emitSymbolChanged(self):
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals._emitSymbolsChanged(source=None, strip=self,
symbolDict={SYMBOLTYPES : self.symbolType,
ANNOTATIONTYPES : self.symbolLabelling,
SYMBOLSIZE : self.symbolSize,
SYMBOLTHICKNESS : self.symbolThickness,
CONTOURTHICKNESS : self.contourThickness,
ALIASENABLED : self.aliasEnabled,
ALIASSHADE : self.aliasShade,
ALIASLABELSENABLED : self.aliasLabelsEnabled,
PEAKLABELSENABLED : self.peakLabelsEnabled,
MULTIPLETLABELSENABLED: self.multipletLabelsEnabled,
})
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# symbolTypes
def _setSymbolType(self):
if self.spectrumViews:
for sV in self.spectrumViews:
for peakListView in sV.peakListViews:
peakListView.buildSymbols = True
peakListView.buildLabels = True
for multipletListView in sV.multipletListViews:
multipletListView.buildSymbols = True
multipletListView.buildLabels = True
# spawn a redraw of the GL windows
self._CcpnGLWidget.GLSignals.emitPaintEvent()
@property
def symbolType(self):
"""Get the symbol type for the strip
"""
return self._CcpnGLWidget._symbolType
@symbolType.setter
def symbolType(self, value):
"""Set the symbol type for the strip
"""
if not isinstance(value, int):
raise TypeError('Error: symbolType not an int')
oldValue = self._CcpnGLWidget._symbolType
self._CcpnGLWidget._symbolType = value if (value in range(self.spectrumDisplay.MAXPEAKSYMBOLTYPES)) else 0
if value != oldValue:
self._setSymbolType()
if self.spectrumViews:
self._emitSymbolChanged()
[docs] def cyclePeakSymbols(self):
"""Cycle through peak symbol types.
"""
self.symbolType += 1
[docs] def setPeakSymbols(self, value):
"""set the peak symbol type.
"""
self.symbolType = value
def _setSymbolsPaintEvent(self):
# prompt the GLwidgets to update
self._CcpnGLWidget.GLSignals.emitEvent(triggers=[self._CcpnGLWidget.GLSignals.GLRESCALE,
self._CcpnGLWidget.GLSignals.GLALLPEAKS,
self._CcpnGLWidget.GLSignals.GLALLMULTIPLETS,
])
def _setContoursPaintEvent(self):
# prompt the GLwidgets to update
self._CcpnGLWidget.GLSignals.emitEvent(triggers=[self._CcpnGLWidget.GLSignals.GLALLCONTOURS,
])
def _symbolsChangedInSettings(self, aDict):
"""Respond to changes in the symbol values in the settings widget
"""
_symbolType = aDict[SYMBOLTYPES]
_annotationsType = aDict[ANNOTATIONTYPES]
_symbolSize = aDict[SYMBOLSIZE]
_symbolThickness = aDict[SYMBOLTHICKNESS]
_aliasEnabled = aDict[ALIASENABLED]
_aliasShade = aDict[ALIASSHADE]
_aliasLabelsEnabled = aDict[ALIASLABELSENABLED]
_peakLabelsEnabled = aDict[PEAKLABELSENABLED]
_multipletLabelsEnabled = aDict[MULTIPLETLABELSENABLED]
_contourThickness = aDict[CONTOURTHICKNESS]
if self.isDeleted:
return
with self.spectrumDisplay._spectrumDisplaySettings.blockWidgetSignals():
# update the current settings from the dict
if _symbolType != self.symbolType:
self.setPeakSymbols(_symbolType)
elif _annotationsType != self.symbolLabelling:
self.setSymbolLabelling(_annotationsType)
elif _symbolSize != self.symbolSize:
self.symbolSize = _symbolSize
self._setSymbolsPaintEvent()
elif _symbolThickness != self.symbolThickness:
self.symbolThickness = _symbolThickness
self._setSymbolsPaintEvent()
elif _aliasEnabled != self.aliasEnabled:
self.aliasEnabled = _aliasEnabled
self._setSymbolsPaintEvent()
elif _aliasShade != self.aliasShade:
self.aliasShade = _aliasShade
self._setSymbolsPaintEvent()
elif _aliasLabelsEnabled != self.aliasLabelsEnabled:
self.aliasLabelsEnabled = _aliasLabelsEnabled
self._setSymbolsPaintEvent()
elif _contourThickness != self.contourThickness:
self.contourThickness = _contourThickness
self._setContoursPaintEvent()
elif _peakLabelsEnabled != self.peakLabelsEnabled:
self.peakLabelsEnabled = _peakLabelsEnabled
self._setSymbolsPaintEvent()
elif _multipletLabelsEnabled != self.multipletLabelsEnabled:
self.multipletLabelsEnabled = _multipletLabelsEnabled
self._setSymbolsPaintEvent()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# symbolSize
@property
def symbolSize(self):
"""Get the symbol size for the strip
"""
return self._CcpnGLWidget._symbolSize
@symbolSize.setter
def symbolSize(self, value):
"""Set the symbol size for the strip
"""
if not isinstance(value, (int, float)):
raise TypeError('Error: symbolSize not an (int, float)')
value = int(value)
oldValue = self._CcpnGLWidget._symbolSize
self._CcpnGLWidget._symbolSize = value if (value and value >= 0) else oldValue
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# symbolThickness
@property
def symbolThickness(self):
"""Get the symbol thickness for the strip
"""
return self._CcpnGLWidget._symbolThickness
@symbolThickness.setter
def symbolThickness(self, value):
"""Set the symbol thickness for the strip
"""
if not isinstance(value, (int, float)):
raise TypeError('Error: symbolThickness not an (int, float)')
value = int(value)
oldValue = self._CcpnGLWidget._symbolThickness
self._CcpnGLWidget._symbolThickness = value if (value and value >= 0) else oldValue
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# contourThickness
@property
def contourThickness(self):
"""Get the contour thickness for the strip
"""
return self._CcpnGLWidget._contourThickness
@contourThickness.setter
def contourThickness(self, value):
"""Set the contour thickness for the strip
"""
if not isinstance(value, (int, float)):
raise TypeError('Error: contourThickness not an (int, float)')
value = int(value)
oldValue = self._CcpnGLWidget._contourThickness
self._CcpnGLWidget._contourThickness = value if (value and value >= 0) else oldValue
if value != oldValue:
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# aliasEnabled
@property
def aliasEnabled(self):
"""Get aliasEnabled for the strip
"""
return self._CcpnGLWidget._aliasEnabled
@aliasEnabled.setter
def aliasEnabled(self, value):
"""Set aliasEnabled for the strip
"""
if not isinstance(value, bool):
raise TypeError('Error: aliasEnabled not a bool')
oldValue = self._CcpnGLWidget._aliasEnabled
self._CcpnGLWidget._aliasEnabled = value
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# aliasShade
@property
def aliasShade(self):
"""Get aliasShade for the strip
"""
return self._CcpnGLWidget._aliasShade
@aliasShade.setter
def aliasShade(self, value):
"""Set aliasShade for the strip
"""
if not isinstance(value, (int, float)):
raise TypeError('Error: aliasShade not an (int, float)')
oldValue = self._CcpnGLWidget._aliasShade
self._CcpnGLWidget._aliasShade = value if (value and value >= 0) else oldValue
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# aliasLabelsEnabled
@property
def aliasLabelsEnabled(self):
"""Get aliasLabelsEnabled for the strip
"""
return self._CcpnGLWidget._aliasLabelsEnabled
@aliasLabelsEnabled.setter
def aliasLabelsEnabled(self, value):
"""Set aliasLabelsEnabled for the strip
"""
if not isinstance(value, bool):
raise TypeError('Error: aliasLabelsEnabled not a bool')
oldValue = self._CcpnGLWidget._aliasLabelsEnabled
self._CcpnGLWidget._aliasLabelsEnabled = value
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# peakLabelsEnabled
@property
def peakLabelsEnabled(self):
"""Get peakLabelsEnabled for the strip
"""
return self._CcpnGLWidget._peakLabelsEnabled
@peakLabelsEnabled.setter
def peakLabelsEnabled(self, value):
"""Set peakLabelsEnabled for the strip
"""
if not isinstance(value, bool):
raise TypeError('Error: peakLabelsEnabled not a bool')
oldValue = self._CcpnGLWidget._peakLabelsEnabled
self._CcpnGLWidget._peakLabelsEnabled = value
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# multipletLabelsEnabled
@property
def multipletLabelsEnabled(self):
"""Get multipletLabelsEnabled for the strip
"""
return self._CcpnGLWidget._multipletLabelsEnabled
@multipletLabelsEnabled.setter
def multipletLabelsEnabled(self, value):
"""Set multipletLabelsEnabled for the strip
"""
if not isinstance(value, bool):
raise TypeError('Error: multipletLabelsEnabled not a bool')
oldValue = self._CcpnGLWidget._multipletLabelsEnabled
self._CcpnGLWidget._multipletLabelsEnabled = value
if value != oldValue:
self._setSymbolLabelling()
if self.spectrumViews:
self._emitSymbolChanged()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[docs] def updateAxisRatios(self):
# notify strips to update fixed/locked state
try:
# update settings - not very nice, using the settings signal for the minute :|
self.spectrumDisplay._spectrumDisplaySettings.updateFromDefaults()
except Exception as es:
print(str(es))
[docs] def setFixedAspectRatios(self, ratios):
# update the ratios for the fixed mode
self._CcpnGLWidget._lockedAspectRatios = ratios.copy()
[docs] def setAspectRatioMode(self, mode):
# update the aspect ratio mode
self._CcpnGLWidget._aspectRatioMode = mode
#-----------------------------------------------------------------------------------------
# marks
#-----------------------------------------------------------------------------------------
def _createMarkAtPosition(self, positions, axisCodes):
try:
_prefsGeneral = self.application.preferences.general
defaultColour = _prefsGeneral.defaultMarksColour
if not defaultColour.startswith('#'):
colourList = colorSchemeTable[defaultColour] if defaultColour in colorSchemeTable else ['#FF0000']
_prefsGeneral._defaultMarksCount = _prefsGeneral._defaultMarksCount % len(colourList)
defaultColour = colourList[_prefsGeneral._defaultMarksCount]
_prefsGeneral._defaultMarksCount += 1
except:
defaultColour = '#FF0000'
self.mainWindow.newMark(defaultColour, positions, axisCodes)
def _copyAxisFromStrip(self, axisId, fromStrip):
try:
axisRange = fromStrip.viewRange()
if axisId == 'X':
# copy X axis from strip
self.zoomX(*axisRange[0])
elif axisId == 'Y':
# copy Y axis from strip
self.zoomY(*axisRange[1])
elif axisId == 'All':
# copy both axes from strip
self.zoom(axisRange[0], axisRange[1])
except Exception as es:
getLogger().warning('Error copying axis %s from strip %s' % (str(axisId), str(fromStrip)))
raise (es)
def _copyAxisCodeFromStrip(self, axisIndex, fromStrip, fromAxisId):
try:
axisRange = fromStrip.orderedAxes[fromAxisId].region
if axisIndex == 0:
# copy X axis from strip
self.zoomX(*axisRange)
elif axisIndex == 1:
# copy Y axis from strip
self.zoomY(*axisRange)
except Exception as es:
getLogger().warning('Error copying axis %s from strip %s' % (str(fromStrip.axisCodes[fromAxisId]), str(fromStrip)))
raise (es)
def _createMarkAtCursorPosition(self, axisIndex=None):
try:
if self.isDeleted or self._flaggedForDelete:
return
try:
_prefsGeneral = self.application.preferences.general
defaultColour = _prefsGeneral.defaultMarksColour
if not defaultColour.startswith('#'):
colourList = colorSchemeTable[defaultColour] if defaultColour in colorSchemeTable else ['#FF0000']
_prefsGeneral._defaultMarksCount = _prefsGeneral._defaultMarksCount % len(colourList)
defaultColour = colourList[_prefsGeneral._defaultMarksCount]
_prefsGeneral._defaultMarksCount += 1
except:
defaultColour = '#FF0000'
# defaultColour = self._preferences.defaultMarksColour
mouseDict = self.current.mouseMovedDict[AXIS_FULLATOMNAME]
positions = [mouseDict[ax] for ax in self.axisCodes if ax in mouseDict]
axisCodes = [ax for ax in self.axisCodes if ax in mouseDict]
if axisIndex is not None:
if (0 <= axisIndex < len(positions)):
positions = (positions[axisIndex],)
axisCodes = (axisCodes[axisIndex],)
self.mainWindow.newMark(defaultColour, positions, axisCodes)
else:
self.mainWindow.newMark(defaultColour, positions, axisCodes)
# add the marks for the double cursor - needs to be enabled in preferences
if self.doubleCrosshairVisible and self._CcpnGLWidget._matchingIsotopeCodes:
mouseDict = self.current.mouseMovedDict[DOUBLEAXIS_FULLATOMNAME]
positions = [mouseDict[ax] for ax in self.axisCodes[:2] if ax in mouseDict]
axisCodes = [ax for ax in self.axisCodes[:2] if ax in mouseDict]
if axisIndex is not None:
if (0 <= axisIndex < 2):
# get the reflected axisCode and position
doubleIndex = 1 - axisIndex
positions = (positions[doubleIndex],)
axisCodes = (axisCodes[doubleIndex],)
self.mainWindow.newMark(defaultColour, positions, axisCodes)
else:
self.mainWindow.newMark(defaultColour, positions, axisCodes)
# need new mark method of the form newMark(colour=colour, axisCode=position)
except Exception as es:
getLogger().warning('Error setting mark at current cursor position')
raise (es)
[docs] def getObjectsUnderMouse(self):
"""Get the selected objects currently under the mouse
"""
return self._CcpnGLWidget.getObjectsUnderMouse()
# GWV 24/12/21: not used and method does not return anything
# def _showMousePosition(self, pos: QtCore.QPointF):
# """Displays mouse position for both axes by axis code.
# """
# if self.isDeleted:
# return
#
# # position = self.viewBox.mapSceneToView(pos)
# try:
# # this only calls a single _wrapper function
# if self.spectrumDisplay.is1D:
# fmt = "%s: %.3f\n%s: %.4g"
# else:
# fmt = "%s: %.2f\n%s: %.2f"
# except:
# fmt = "%s: %.3f %s: %.4g"
[docs] def autoRange(self):
self._CcpnGLWidget.autoRange()
[docs] def zoom(self, xRegion: Tuple[float, float], yRegion: Tuple[float, float]):
"""Zooms strip to the specified region.
"""
self._CcpnGLWidget.zoom(xRegion, yRegion)
[docs] def zoomX(self, x1: float, x2: float):
"""
Zooms x axis of strip to the specified region
"""
self._CcpnGLWidget.zoomX(x1, x2)
[docs] def zoomY(self, y1: float, y2: float):
"""Zooms y axis of strip to the specified region
"""
self._CcpnGLWidget.zoomY(y1, y2)
# def showZoomPopup(self):
# """
# Creates and displays a popup for zooming to a region in the strip.
# """
# zoomPopup = QtWidgets.QDialog()
#
# Label(zoomPopup, text='x1', grid=(0, 0))
# x1LineEdit = FloatLineEdit(zoomPopup, grid=(0, 1))
# Label(zoomPopup, text='x2', grid=(0, 2))
# x2LineEdit = FloatLineEdit(zoomPopup, grid=(0, 3))
# Label(zoomPopup, text='y1', grid=(1, 0))
# y1LineEdit = FloatLineEdit(zoomPopup, grid=(1, 1))
# Label(zoomPopup, text='y2', grid=(1, 2))
# y2LineEdit = FloatLineEdit(zoomPopup, grid=(1, 3))
#
# def _zoomTo():
# x1 = x1LineEdit.get()
# y1 = y1LineEdit.get()
# x2 = x2LineEdit.get()
# y2 = y2LineEdit.get()
# if None in (x1, y1, x2, y2):
# getLogger().warning('Zoom: must specify region completely')
# return
# self.zoomToRegion(xRegion=(x1, x2), yRegion=(y1, y2))
# zoomPopup.close()
#
# Button(zoomPopup, text='OK', callback=_zoomTo, grid=(2, 0), gridSpan=(1, 2))
# Button(zoomPopup, text='Cancel', callback=zoomPopup.close, grid=(2, 2), gridSpan=(1, 2))
#
# zoomPopup.exec_()
# TODO. Set limit range properly for each case: 1D/nD, flipped axis
# def setZoomLimits(self, xLimits, yLimits, factor=5):
# '''
#
# :param xLimits: List [min, max], e.g ppm [0,15]
# :param yLimits: List [min, max] eg. intensities [-300,2500]
# :param factor:
# :return: Limits the viewBox from zooming in too deeply(crashing the program) to zooming out too far.
# '''
# ratio = (abs(xLimits[0] - xLimits[1])/abs(yLimits[0] - yLimits[1]))/factor
# if max(yLimits)>max(xLimits):
# self.viewBox.setLimits(xMin=-abs(min(xLimits)) * factor,
# xMax=max(xLimits) * factor,
# yMin=-abs(min(yLimits)) * factor,
# yMax=max(yLimits) * factor,
# minXRange=((max(xLimits) - min(xLimits))/max(xLimits)) * ratio,
# maxXRange=max(xLimits) * factor,
# minYRange=(((max(yLimits) - min(yLimits))/max(yLimits))),
# maxYRange=max(yLimits) * factor
# )
# else:
# self.viewBox.setLimits(xMin=-abs(min(xLimits)) * factor,
# xMax=max(xLimits) * factor,
# yMin=-abs(min(yLimits)) * factor,
# yMax=max(yLimits) * factor,
# minXRange=((max(xLimits) - min(xLimits))/max(xLimits)),
# maxXRange=max(xLimits) * factor,
# minYRange=(((max(yLimits) - min(yLimits))/max(yLimits)))*ratio,
# maxYRange=max(yLimits) * factor
# )
# def removeZoomLimits(self):
# self.viewBox.setLimits(xMin=None,
# xMax=None,
# yMin=None,
# yMax=None,
# # Zoom Limits
# minXRange=None,
# maxXRange=None,
# minYRange=None,
# maxYRange=None
# )
def _resetAllZoom(self):
"""
Zooms x/y axes to maximum of data.
"""
self._CcpnGLWidget.resetAllZoom()
def _resetYZoom(self):
"""
Zooms y axis to maximum of data.
"""
self._CcpnGLWidget.resetYZoom()
def _resetXZoom(self):
"""
Zooms x axis to maximum value of data.
"""
self._CcpnGLWidget.resetXZoom()
def _storeZoom(self):
"""Adds current region to the zoom stack for the strip.
"""
self._CcpnGLWidget.storeZoom()
@property
def zoomState(self):
if self._CcpnGLWidget is not None:
zoom = self._CcpnGLWidget.zoomState
return zoom
return []
[docs] def restoreZoomFromState(self, zoomState):
"""
Restore zoom from a saved state
:param zoomState: list of Axis coordinate Left, Right, Bottom, Top
"""
if zoomState is not None:
if len(zoomState) == 4:
# self._restoreZoom(zoomState=zoomState)
axisL, axisR, axisB, axisT = zoomState[0], zoomState[1], zoomState[2], zoomState[3]
self._CcpnGLWidget.setXRegion(axisL, axisR)
self._CcpnGLWidget.setYRegion(axisT, axisB)
def _restoreZoom(self, zoomState=None):
"""Restores last saved region to the zoom stack for the strip.
"""
self._CcpnGLWidget.restoreZoom(zoomState)
def _previousZoom(self):
"""Changes to the previous zoom for the strip.
"""
self._CcpnGLWidget.previousZoom()
def _nextZoom(self):
"""Changes to the next zoom for the strip.
"""
self._CcpnGLWidget.nextZoom()
def _setZoomPopup(self):
from ccpn.ui.gui.popups.ZoomPopup import ZoomPopup
popup = ZoomPopup(parent=self.mainWindow, mainWindow=self.mainWindow)
popup.exec_()
[docs] @logCommand(get='self')
def resetZoom(self):
self._CcpnGLWidget.resetZoom()
def _zoomIn(self):
"""Zoom in to the strip.
"""
self._CcpnGLWidget.zoomIn()
def _zoomOut(self):
"""Zoom out of the strip.
"""
self._CcpnGLWidget.zoomOut()
def _panSpectrum(self, direction: str = 'up'):
"""Pan the spectrum with the cursor keys
"""
self._CcpnGLWidget._panSpectrum(direction)
def _movePeaks(self, direction: str = 'up'):
"""Move the peaks with the cursors
"""
self._CcpnGLWidget._movePeaks(direction)
def _resetRemoveStripAction(self):
"""Update interface when a strip is created or deleted.
NB notifier is executed after deletion is final but before the wrapper is updated.
len() > 1 check is correct also for delete
"""
pass # GWV: poor solution self.spectrumDisplay._resetRemoveStripAction()
[docs] def setRightAxisVisible(self, axisVisible=False):
"""Set the visibility of the right axis
"""
self._CcpnGLWidget.setRightAxisVisible(axisVisible=axisVisible)
[docs] def setBottomAxisVisible(self, axisVisible=False):
"""Set the visibility of the bottom axis
"""
self._CcpnGLWidget.setBottomAxisVisible(axisVisible=axisVisible)
[docs] def getAxesVisible(self):
"""Get the visibility of strip axes
"""
return self._CcpnGLWidget.getAxesVisible()
[docs] def setAxesVisible(self, rightAxisVisible=True, bottomAxisVisible=False):
"""Set the visibility of strip axes
"""
self._CcpnGLWidget.setAxesVisible(rightAxisVisible=rightAxisVisible,
bottomAxisVisible=bottomAxisVisible)
[docs] def getRightAxisWidth(self):
"""return the width of the right axis margin
"""
return self._CcpnGLWidget.AXIS_MARGINRIGHT
[docs] def getBottomAxisHeight(self):
"""return the height of the bottom axis margin
"""
return self._CcpnGLWidget.AXIS_MARGINBOTTOM
def _moveToNextSpectrumView(self):
if not self.spectrumDisplay.isGrouped:
# cycle through the spectrumViews
spectrumViews = self.getSpectrumViews()
countSpvs = len(spectrumViews)
if countSpvs > 0:
visibleSpectrumViews = [sv for sv in spectrumViews if sv.isDisplayed]
if len(visibleSpectrumViews) > 0:
currentIndex = spectrumViews.index(visibleSpectrumViews[-1])
if countSpvs > currentIndex + 1:
for visibleSpectrumView in visibleSpectrumViews:
visibleSpectrumView.setVisible(False)
spectrumViews[currentIndex + 1].setVisible(True)
elif countSpvs == currentIndex + 1: #starts again from the first
for visibleSpectrumView in visibleSpectrumViews:
visibleSpectrumView.setVisible(False)
spectrumViews[0].setVisible(True)
else:
spectrumViews[-1].setVisible(True) #starts the loop again if none is selected
else:
MessageDialog.showWarning('Unable to select spectrum', 'Select a SpectrumDisplay with active spectra first')
else:
# cycle through the spectrumGroups
spectrumViews = self.getSpectrumViews()
actions = self.spectrumDisplay.spectrumGroupToolBar.actions()
if not actions:
return
visibleGroups = [(act, self.project.getByPid(act.objectName())) for act in actions if act.isChecked()]
countSpvs = len(actions)
if visibleGroups:
# get the last group in the toolbar buttons
lastAct, lastObj = visibleGroups[-1]
nextInd = (actions.index(lastAct) + 1) % len(actions)
nextAct, nextObj = actions[nextInd], self.project.getByPid(actions[nextInd].objectName())
# uncheck/check the toolbar buttons
for action, obj in visibleGroups:
action.setChecked(False)
nextAct.setChecked(True)
if nextObj:
# set the associated spectrumViews as visible
for specView in spectrumViews:
specView.setVisible(specView.spectrum in nextObj.spectra)
elif actions:
# nothing visible so set the first toolbar button
currentGroup = self.project.getByPid(actions[0].objectName())
if currentGroup:
for specView in spectrumViews:
specView.setVisible(specView.spectrum in currentGroup.spectra)
actions[0].setChecked(True)
def _moveToPreviousSpectrumView(self):
if not self.spectrumDisplay.isGrouped:
spectrumViews = self.getSpectrumViews()
countSpvs = len(spectrumViews)
if countSpvs > 0:
visibleSpectrumViews = [sv for sv in spectrumViews if sv.isDisplayed]
if len(visibleSpectrumViews) > 0:
currentIndex = spectrumViews.index(visibleSpectrumViews[0])
# if countSpvs > currentIndex + 1:
for visibleSpectrumView in visibleSpectrumViews:
visibleSpectrumView.setVisible(False)
spectrumViews[currentIndex - 1].setVisible(True)
else:
spectrumViews[-1].setVisible(True) # starts the loop again if none is selected
else:
MessageDialog.showWarning('Unable to select spectrum', 'Select a SpectrumDisplay with active spectra first')
else:
# cycle through the spectrumGroups
spectrumViews = self.getSpectrumViews()
actions = self.spectrumDisplay.spectrumGroupToolBar.actions()
if not actions:
return
visibleGroups = [(act, self.project.getByPid(act.objectName())) for act in actions if act.isChecked()]
countSpvs = len(actions)
if visibleGroups:
# get the first group in the toolbar buttons
lastAct, lastObj = visibleGroups[0]
nextInd = (actions.index(lastAct) - 1) % len(actions)
nextAct, nextObj = actions[nextInd], self.project.getByPid(actions[nextInd].objectName())
# uncheck/check the toolbar buttons
for action, obj in visibleGroups:
action.setChecked(False)
nextAct.setChecked(True)
if nextObj:
# set the associated spectrumViews as visible
for specView in spectrumViews:
specView.setVisible(specView.spectrum in nextObj.spectra)
elif actions:
# nothing visible so set the last toolbar button
currentGroup = self.project.getByPid(actions[-1].objectName())
if currentGroup:
for specView in spectrumViews:
specView.setVisible(specView.spectrum in currentGroup.spectra)
actions[-1].setChecked(True)
def _showAllSpectrumViews(self, value: bool = True):
# turn on/off all spectrumViews
spectrumViews = self.getSpectrumViews()
for sp in spectrumViews:
sp.setVisible(value)
if self.spectrumDisplay.isGrouped:
# turn on/off all toolbar buttons
actions = self.spectrumDisplay.spectrumGroupToolBar.actions()
for action in actions:
action.setChecked(value)
# GWV 07/01/2022: removed
# @property
# def visibleSpectra(self):
# """List of spectra currently visible in the strip. Ordered as in the spectrumDisplay
# """
# return self.spectrumDisplay.visibleSpectra
def _invertSelectedSpectra(self):
if not self.spectrumDisplay.isGrouped:
spectrumViews = self.getSpectrumViews()
countSpvs = len(spectrumViews)
if countSpvs > 0:
visibleSpectrumViews = [sv.isDisplayed for sv in spectrumViews]
if any(visibleSpectrumViews):
for sv in spectrumViews: sv.setVisible(not sv.isDisplayed)
else:
self._showAllSpectrumViews(True)
else:
actions = self.spectrumDisplay.spectrumGroupToolBar.actions()
spectra = set()
for action in actions:
# toggle the visibility of the toolbar buttons
newVisible = not action.isChecked()
action.setChecked(newVisible)
obj = self.project.getByPid(action.objectName())
if newVisible and obj:
for spec in obj.spectra:
spectra.add(spec)
# set the visibility of the spectrumViews
spectrumViews = self.getSpectrumViews()
for specView in spectrumViews:
specView.setVisible(specView.spectrum in spectra)
[docs] def report(self):
"""Generate a drawing object that can be added to reports
:return reportlab drawing object:
"""
if self._CcpnGLWidget:
# from ccpn.ui.gui.lib.OpenGL.CcpnOpenGLExport import GLExporter
glReport = self._CcpnGLWidget.exportToSVG()
if glReport:
return glReport.report()
# def axisRegionChanged(self, axis):
# """Notifier function: Update strips etc. for when axis position or width changes.
# """
# if self.isDeleted:
# return
#
# self._setPlaneAxisWidgets(axis=axis)
#
# # # can't remember why this is here
# # self.beingUpdated = False
[docs] @logCommand(get='self')
def moveTo(self, newIndex: int):
"""Move strip to index newIndex in orderedStrips.
"""
currentIndex = self._wrappedData.index
if currentIndex == newIndex:
return
# get the current order
stripCount = self.spectrumDisplay.stripCount
if newIndex >= stripCount:
# Put strip at the right, which means newIndex should be stripCount - 1
if newIndex > stripCount:
# warning
raise TypeError("Attempt to copy strip to position %s in display with only %s strips"
% (newIndex, stripCount))
newIndex = stripCount - 1
# with undoBlockWithoutSideBar():
with undoStackBlocking() as _: # Do not add to undo/redo stack
with undoStackBlocking() as addUndoItem:
# needs to be first as it uses currentOrdering
addUndoItem(undo=partial(self._moveToStripLayout, newIndex, currentIndex))
self._wrappedData.moveTo(newIndex)
# reorder the strips in the layout
self._moveToStripLayout(currentIndex, newIndex)
# add undo item to reorder the strips in the layout
with undoStackBlocking() as addUndoItem:
addUndoItem(redo=partial(self._moveToStripLayout, currentIndex, newIndex))
def _moveToStripLayout(self, currentIndex, newIndex):
# management of Qt layout
# TBD: need to soup up below with extra loop when have tiles
spectrumDisplay = self.spectrumDisplay
layout = spectrumDisplay.stripFrame.layout()
if not layout: # should always exist but play safe:
return
# remove old widgets - this needs to done otherwise the layout swap destroys all children, and remember minimum widths
_oldWidgets = []
minSizes = []
while layout.count():
wid = layout.takeAt(0).widget()
_oldWidgets.append(wid)
minSizes.append(wid.minimumSize())
# get the new strip order
_widgets = list(spectrumDisplay.orderedStrips)
if len(_widgets) != len(spectrumDisplay.strips):
raise RuntimeError('bad ordered stripCount')
# remember necessary layout info and create a new layout - ensures clean for new widgets
margins = layout.getContentsMargins()
space = layout.spacing()
QtWidgets.QWidget().setLayout(layout)
layout = QtWidgets.QGridLayout()
spectrumDisplay.stripFrame.setLayout(layout)
layout.setContentsMargins(*margins)
layout.setSpacing(space)
# need to switch the tile positions for the moved strips
# reinsert strips in new order - reset minimum widths
if spectrumDisplay.stripArrangement == 'Y':
# horizontal strip layout
for m, widgStrip in enumerate(_widgets):
tilePosition = widgStrip.tilePosition
if True: # tilePosition is None:
layout.addWidget(widgStrip, 0, m)
widgStrip.tilePosition = (0, m)
# else:
# layout.addWidget(widgStrip, tilePosition[0], tilePosition[1])
widgStrip.setMinimumWidth(minSizes[m].width())
elif spectrumDisplay.stripArrangement == 'X':
# vertical strip layout
for m, widgStrip in enumerate(_widgets):
tilePosition = widgStrip.tilePosition
if True: # tilePosition is None:
layout.addWidget(widgStrip, m, 0)
widgStrip.tilePosition = (0, m)
# else:
# layout.addWidget(widgStrip, tilePosition[1], tilePosition[0])
widgStrip.setMinimumHeight(minSizes[m].height())
elif spectrumDisplay.stripArrangement == 'T':
# NOTE:ED - Tiled plots not fully implemented yet
getLogger().warning('Tiled plots not implemented for spectrumDisplay: %s' % str(spectrumDisplay.pid))
else:
getLogger().warning('Strip direction is not defined for spectrumDisplay: %s' % str(spectrumDisplay.pid))
# rebuild the axes for strips
spectrumDisplay.showAxes(stretchValue=True, widths=False)
[docs] def navigateToPosition(self, positions:List[float],
axisCodes:List[str] = None,
widths:List[float] = None):
"""Navigate to positions, optionally setting widths of this Strip
"""
from ccpn.ui.gui.lib.StripLib import navigateToPositionInStrip
navigateToPositionInStrip(self, positions, axisCodes, widths)
[docs] def navigateToPeak(self, peak, widths:List[float] = None):
"""Navigate to peak.position, optionally setting widths of this Strip
"""
if peak:
self.navigateToPosition(peak.position, peak.axisCodes, widths=widths)
else:
MessageDialog.showMessage('No Peak', 'Select a peak first')
def _raiseContextMenu(self, event: QtGui.QMouseEvent):
"""
Raise the context menu
"""
position = event.screenPos()
self.viewStripMenu.exec_(QtCore.QPoint(int(position.x()),
int(position.y())))
self.contextMenuPosition = self.current.cursorPosition
def _updateVisibility(self):
"""Update visibility list in the OpenGL
"""
self._CcpnGLWidget.updateVisibleSpectrumViews()
[docs] def firstVisibleSpectrum(self):
"""return the first visible spectrum in the strip, or the first if none are visible.
"""
return self._CcpnGLWidget._firstVisible
def _toggleStackPhaseFromShortCut(self):
"""Not implemented, to be overwritten by subclasses
"""
pass
[docs] def mainViewSize(self):
"""Return the width/height for the mainView of the OpenGL widget
"""
return self._CcpnGLWidget.mainViewSize()
#-----------------------------------------------------------------------------------------
# Peak-related stuff
#-----------------------------------------------------------------------------------------
[docs] @logCommand(get='self')
def createPeak(self, ppmPositions: List[float]) -> Tuple[Tuple[Peak, ...], Tuple[PeakList, ...]]:
"""Create peak at position for all spectra currently displayed in strip.
"""
result = []
peakLists = []
with undoBlockWithoutSideBar():
# create the axisDict for this spectrum
axisDict = {axis: ppm for axis, ppm in zip(self.axisCodes, ppmPositions)}
height = axisDict.get('intensity', None) # needed for 1D
axisDict.pop('intensity', None) # need to be removed otherwise it cannot pick 1D
# loop through the visible spectra
for spectrumView in (v for v in self.spectrumViews if v.isDisplayed):
spectrum = spectrumView.spectrum
# get the list of visible peakLists
validPeakListViews = [pp for pp in spectrumView.peakListViews if pp.isDisplayed]
if not validPeakListViews:
continue
for thisPeakListView in validPeakListViews:
peakList = thisPeakListView.peakList
# pick the peak in this peakList
pk = spectrum.createPeak(peakList, height=height, **axisDict)
if pk:
result.append(pk)
peakLists.append(peakList)
# set the current peaks
self.current.peaks = result
return tuple(result), tuple(peakLists)
[docs] @logCommand(get='self')
def pickPeaks(self, regions: List[Tuple[float,float]]) -> list:
"""Peak-pick in regions for all spectra currently displayed in the strip.
:param regions: a list of (minVal,maxVal) tuples in display order
:return a list of Peak instances
"""
from ccpn.core.lib.SpectrumLib import _pickPeaksByRegion
_displayedSpectra = self._displayedSpectra
if len(_displayedSpectra) == 0:
getLogger().warning('%s pickPeaks: no visible spectra' % self)
return []
result = []
with undoBlockWithoutSideBar():
# loop through the visible spectra
for _displayedSpectrum in _displayedSpectra:
spectrum = _displayedSpectrum.spectrum
spectrumView = _displayedSpectrum.spectrumView
_checkOutside = _displayedSpectrum.checkForRegionsOutsideLimits(regions)
_skip = any(_checkOutside)
if _skip and not self._CcpnGLWidget._stackingMode:
getLogger().warning('Strip.pickPeaks: skipping %s; outside region %r' % (spectrum, regions))
continue
# get the list of visible peakLists
validPeakListViews = [pp for pp in spectrumView.peakListViews if pp.isDisplayed]
if not validPeakListViews:
continue
# get parameters to apply to peak picker
_sliceTuples = _displayedSpectrum.getSliceTuples(regions)
positiveThreshold = spectrum.positiveContourBase if spectrum.includePositiveContours else None
negativeThreshold = spectrum.negativeContourBase if spectrum.includeNegativeContours else None
if spectrum.dimensionCount == 1:
xOffset, yOffset = self._CcpnGLWidget._spectrumSettings[spectrumView].get(SPECTRUM_STACKEDMATRIXOFFSET)
_intensityLimits = np.array(regions[1]) - yOffset
_xArray = np.array(regions[0]) - xOffset
_sliceTuples = _displayedSpectrum.getSliceTuples([_xArray])
spectrum.peakPicker._intensityLimits = _intensityLimits #needed to make sure it peaks only inside the selected box.
positiveThreshold, negativeThreshold = None, None # get automatically
for thisPeakListView in validPeakListViews:
peakList = thisPeakListView.peakList
# pick the peaks in this peakList
newPeaks = _pickPeaksByRegion(spectrum = spectrum,
sliceTuples=_sliceTuples,
peakList=peakList,
positiveThreshold=positiveThreshold,
negativeThreshold=negativeThreshold,
)
if newPeaks is not None and len(newPeaks) > 0:
result.extend(newPeaks)
self.current.peaks = result
return result
#-----------------------------------------------------------------------------------------
# strip Axis-related stuff
#-----------------------------------------------------------------------------------------
[docs] def getAxisPosition(self, axisIndex):
return self._CcpnGLWidget.getAxisPosition(axisIndex)
[docs] def setAxisPosition(self, axisIndex, position, rescale=True, update=True):
"""Set the axis position of the strip
if rescale is False, the symbols, etc., must explicitly be refreshed
"""
self._CcpnGLWidget.setAxisPosition(axisIndex, position, rescale=rescale, update=update)
[docs] def getAxisWidth(self, axisIndex):
return self._CcpnGLWidget.getAxisWidth(axisIndex)
[docs] def setAxisWidth(self, axisIndex, width, rescale=True, update=True):
"""Set the axis width of the strip, centred on the axis position
if rescale is False, the symbols, etc., must explicitly be refreshed
"""
self._CcpnGLWidget.setAxisWidth(axisIndex, width, rescale=rescale, update=update)
[docs] def getAxisRegion(self, axisIndex):
"""Return the region currently displayed in the strip as tuple(min, max) for given axis.
axisIndex is the screen axis; X is 0, Y is 1
"""
return self._CcpnGLWidget.getAxisRegion(axisIndex)
[docs] def setAxisRegion(self, axisIndex, width, rescale=True, update=True):
"""Set the axis region for the strip.
if rescale is False, the symbols, etc., must explicitly be refreshed
"""
self._CcpnGLWidget.setAxisRegion(axisIndex, width, rescale=rescale, update=update)
[docs] def getAxisRegions(self) -> Tuple[Tuple, ...]:
"""Return a tuple if tuples for the regions ((min, max), ...)
Visible direction of axes is not preserved
"""
regions = []
for axis, position, width in zip(self.orderedAxes, self.positions, self.widths):
regions.append((position - width / 2.0, position + width / 2.0))
return tuple(regions)
def _setAxisPositionAndWidth(self, stripAxisIndex: int, position:float, width:float = None,
refresh=True):
"""Change the position of axis defined by stripAxisIndex
:param stripAxisIndex: an index, defining an Z, A, ... plane; i.e. >= 2
:param position: the new position (in axis units; i.e. ppm, Hz, points)
:param width: (optional) the width of the plane
:param refresh: call openGL refresh
"""
if stripAxisIndex < 0 or stripAxisIndex >= self.spectrumDisplay.dimensionCount:
raise ValueError('%s._setAxisPositionAndWidth: invalid stripAxisIndex "%s"' %
(self.__class__.__name__, stripAxisIndex))
_axis = self.orderedAxes[stripAxisIndex]
if len(self._displayedSpectra) == 0:
return
# unfortunately, we need a spectrum with right dimensionality to do axis unit conversions
# (for now). Take the first eligible one
found = False
sv = None
for sv in self.spectrumViews:
if sv.spectrum.dimensionCount == self.spectrumDisplay.dimensionCount:
found = True
break
if not found or sv is None:
raise RuntimeError('%s._setPositionAndWidth: no appropriate spectrum found for this display to do conversions' %
self.__class__.__name__
)
_specDim = sv.spectrumDimensions[stripAxisIndex]
_axis._incrementByUnit = self._minAxisIncrementByUnit[stripAxisIndex]
_axis._minLimitByUnit = self._minAxisLimitsByUnit[stripAxisIndex]
_axis._maxLimitByUnit = self._maxAxisLimitsByUnit[stripAxisIndex]
position = max(_axis._minLimitByUnit, position)
position = min(_axis._maxLimitByUnit, position)
# for now: Axis.position and Axis.width are maintained in ppm; so conversion
# depending on Axis.unit is required.
if _axis.unit == AXISUNIT_PPM:
_axis.position = position
_axis._positionByUnit = position
if width is not None:
_axis.width = width
_axis._widthByUnit = width
elif _axis.unit == AXISUNIT_POINT:
# change to ppm
_axis.position = _specDim.pointToPpm(position)
_axis._positionByUnit = position
if width is not None:
_axis.width = width * _specDim.ppmPerPoint
_axis._widthByUnit = width
elif _axis.unit == AXISUNIT_HZ:
# change to ppm by scaling by spectrometerFrequencies
_axis.position = position / _specDim.spectrometerFrequency
_axis._positionByUnit = position
if width is not None:
_axis.width = width / _specDim.spectrometerFrequency
_axis._widthByUnit = width
else:
getLogger().debug(f'Axis {_axis.unit} not found')
return
self._updatePlaneToolBarWidgets(stripAxisIndex)
if refresh:
self.refresh()
def _initAxesValues(self, spectrumView):
"""Initialiase the strip.axes using a spectrumView instance
CCPNINTERNAL: used from _newSpectrumDisplay
"""
from ccpn.util.Constants import AXISUNIT_NUMBER, AXISUNIT_POINT, AXISUNIT_PPM
spectrum = spectrumView.spectrum
axes = self.orderedAxes
if spectrum.dimensionCount == 1:
# 1D spectrum
ppmLimits, valueLimits = spectrum.get1Dlimits()
axes[0].region = ppmLimits
axes[0]._positionByUnit = axes[0].position
axes[0]._widthByUnit = axes[0].width
axes[1].region = valueLimits
axes[1].unit = AXISUNIT_NUMBER
else:
# nD
for _axis, _specDim, dimIndex in zip(axes,
spectrumView.spectrumDimensions,
spectrumView.dimensionIndices
):
if _axis._index < 2:
# The X,Y axis of the strip
if spectrum.isTimeDomains[dimIndex] or spectrum.isSampledDomains[dimIndex]:
_axis.unit = AXISUNIT_POINT
self._setAxisPositionAndWidth(_axis._index,
position = float(_specDim.pointCount/2)+0.5,
width = float(_specDim.pointCount),
refresh = False
)
else:
_axis.unit = AXISUNIT_PPM
limits = _specDim.aliasingLimits
self._setAxisPositionAndWidth(_axis._index,
position = 0.5*(limits[0] + limits[1]), # The centre
width = max(limits) - min(limits),
refresh = False
)
else:
# A strip Z,A,... "plane-axis"
if spectrum.isTimeDomains[dimIndex] or spectrum.isSampledDomains[dimIndex]:
_axis.unit = AXISUNIT_POINT
self._setAxisPositionAndWidth(_axis._index,
position = 1.0,
width = 1.0,
refresh = False
)
else:
_axis.unit = AXISUNIT_PPM
limits = _specDim.spectrumLimits
self._setAxisPositionAndWidth(_axis._index,
position = 0.5*(limits[0] + limits[1]), # The centre
width = _specDim.ppmPerPoint,
refresh = False
)
# init the GL
self._CcpnGLWidget.initialiseAxes(strip=self)
#-----------------------------------------------------------------------------------------
# Subclassed in nD
#-----------------------------------------------------------------------------------------
def _updatePlaneAxes(self):
"""A Convenience method to update plane-axis values.
It uses the _changePlane() method; also updates the plane widgets
"""
# Only implemented for nD
pass
def _changePlane(self, stripAxisIndex: int, planeIncrement:int, planeCount = None,
refresh:bool = True
):
"""Change the position of plane-axis defined by stripAxisIndex by increment (in points)
:param stripAxisIndex: an index, defining an Z, A, ... plane; i.e. >= 2
:param planeIncrement: an integer defining number of planes to increment.
The actual ppm increment (for axis in ppm units) will be
the minimum ppm increment along stripAxisIndex.
:param planeCount: the number of planes to display
:param refresh: optionally refresh strip after setting values
"""
# Only implemented for nD
pass
#=========================================================================================
# Notifiers:
#=========================================================================================
def _updateDisplayedMarks(data):
"""Callback when marks have changed - Create, Change, Delete; defined above.
"""
from ccpn.ui.gui.lib.OpenGL.CcpnOpenGL import GLNotifier
GLSignals = GLNotifier(parent=None)
GLSignals.emitEvent(triggers=[GLNotifier.GLMARKS])
def _updateSelectedPeaks(data):
"""Callback when peaks have changed.
"""
from ccpn.ui.gui.lib.OpenGL.CcpnOpenGL import GLNotifier
GLSignals = GLNotifier(parent=None)
GLSignals.emitEvent(triggers=[GLNotifier.GLHIGHLIGHTPEAKS], targets=data[Notifier.OBJECT].peaks)
def _updateSelectedIntegrals(data):
"""Callback when integrals have changed.
"""
from ccpn.ui.gui.lib.OpenGL.CcpnOpenGL import GLNotifier
GLSignals = GLNotifier(parent=None)
GLSignals.emitEvent(triggers=[GLNotifier.GLHIGHLIGHTINTEGRALS], targets=data[Notifier.OBJECT].integrals)
def _updateSelectedMultiplets(data):
"""Callback when multiplets have changed.
"""
from ccpn.ui.gui.lib.OpenGL.CcpnOpenGL import GLNotifier
GLSignals = GLNotifier(parent=None)
GLSignals.emitEvent(triggers=[GLNotifier.GLHIGHLIGHTMULTIPLETS], targets=data[Notifier.OBJECT].multiplets)
# def _axisRegionChanged(cDict):
# """Notifier function: Update strips etc. for when axis position or width changes.
# """
# axis = cDict[Notifier.OBJECT]
# strip = axis.strip
#
# position = axis.position
# width = axis.width
# region = (position - width / 2., position + width / 2.)
#
# index = strip.axisOrder.index(axis.code)
# if not strip.beingUpdated:
#
# strip.beingUpdated = True
#
# try:
# if index == 0:
# # X axis
# padding = strip.application.preferences.general.stripRegionPadding
# strip.viewBox.setXRange(*region, padding=padding)
# elif index == 1:
# # Y axis
# padding = strip.application.preferences.general.stripRegionPadding
# strip.viewBox.setYRange(*region, padding=padding)
# else:
#
# if len(strip.axisOrder) > 2:
# n = index - 2
# if n >= 0:
#
# if strip.planeAxisBars and n < len(strip.planeAxisBars):
# # strip.planeAxisBars[n].setPosition(ppmPosition, ppmWidth)
# strip.planeAxisBars[n].updatePosition()
#
# # planeLabel = strip.planeToolbar.planeLabels[n]
# # planeSize = planeLabel.singleStep()
# # planeLabel.setValue(position)
# # strip.planeToolbar.planeCounts[n].setValue(width / planeSize)
#
# finally:
# strip.beingUpdated = False
# NB The following two notifiers could be replaced by wrapper notifiers on
# Mark, 'change'. But it would be rather more clumsy, so leave it as it is.
# def _rulerCreated(project: Project, apiRuler: ApiRuler):
# """Notifier function for creating rulers"""
# for strip in project.strips:
# strip.plotWidget._addRulerLine(apiRuler)
# def _rulerDeleted(project: Project, apiRuler: ApiRuler):
# """Notifier function for deleting rulers"""
# for strip in project.strips:
# strip.plotWidget._removeRulerLine(apiRuler)