Peak & Peak Lists

Introduction

In the CCPN data model there are a few classes related to peaks found in spectra.

 

Setup

The following examples assume that you have loaded the demonstration project, so that we can look at pre-existing peaks etc. If you have not already done so, make sure that you load such a CCPN project. This can be done as follows, remembering to change the location of the project directory to that it is appropriate to your system:

from memops.general.Io import loadProject

rootProject = loadProject('/home/user/myProjDirName')

Next we will find an HSQC experiment and an associated spectrum to work with:

# There may be a pause on issuing this command

# while the NMR data is loaded from disk

experiment = rootProject.currentNmrProject.findFirstExperiment(name='HSQC')

spectrum = experiment.findFirstDataSource()

PeakList

Given a spectrum, creating a PeakList is simple:

peakList = spectrum.newPeakList()

print peakList.peaks

This is of course an empty peak list because we have not made any Peak objects for it. And if you wanted to delete it you just do:

peakList.delete()

That deletes not only the peak list but all the peaks (and other contained objects like  peakDims, peakDimContribs, etc.) contained inside the PeakList object.

Sometimes one wants to copy a PeakList from one spectrum to another or duplicate a PeakList inside one spectrum (so one can then start working on the PeakList while preserving the original version).  This is not a totally trivial exercise (because there is a whole slew of objects that need copying over) but there is a utility function that makes the job easy:

print spectrum.peakLists

peakList = spectrum.findFirstPeakList()

from ccpnmr.analysis.core.PeakBasic import copyPeakListNew

copyPeakListNew(peakList, spectrum)

print spectrum.peakLists

which creates a copy of PeakList in the DataSource object (spectrum).

To loop through peaks in a peakList one does one of the following. Note that peakList.peaks is an unordered set and so will give you the peaks in random order. peakList.sortedPeaks gives a list of the peaks in order of the key (here the serial attribute)

for peak in peakList.peaks:

  print peak.serial

for peak in peakList.sortedPeaks():

 print peak.serial

Peak

To create a new peak in a peakList one does:

peak = peakList.newPeak()

This automatically creates the peak dimension objects (PeakDims) of the peak, however the new peak dimensions will carry no positional information:

print "number of peakDims = %d" % len(peak.peakDims)

for peakDim in peak.peakDims:

 print peakDim.dim, peakDim.position

To delete a peak one does the following, which automatically deletes all the PeakDims and PeakContribs (etc.) associated with the peak:

peak.delete()

To create a peak at a specific location, you would have to set the position of the PeakDims and specify which of the DataDimRefs (the dimension referencing values from the spectrum) to work with; so that a point position can be converted into PPM. This is sligntly complicated, so in most instances you would use the utility function pickPeak() to place a peak:

from ccpnmr.analysis.core.PeakBasic import pickPeak

position = (7.321, 132.87)

# doFit must be False unless we are working within Analysis

peak = pickPeak(peakList, position, unit='ppm', doFit=False)

print [peakDim.value for peakDim in peak.peakDims]

The list of all peakDims for a given peak in dimension order is given by using the "sorted" API call. Note how the peak dimension objects contain a record of their position and assignment label:

peak  = peakList.findFirstPeak()

peakDims = peak.sortedPeakDims()

for peakDim in peakDims:

 print peakDim.annotation, peakDim.value

If we were to issue peak.peakDims, rather than the "sorted" function we would not necessarily get the in dimensions back in order.

A peak can have PeakIntensities; each of these is a height or a volume.  They are a bit of a pain to construct because a PeakIntensity object must have a Method object which specifies what algorithm was used to determine the intensity value, and a Method belongs to a MethodStore.  So one yucky example of manually constructing such a PeakIntensity is:

methodStore = rootProject.findFirstMethodStore()

if not methodStore:

  methodStore = rootProject.newMethodStore(name="myMethodStore")

method = methodStore.findFirstMethod(task="Peak intensity", name="myPeakIntensityAlgorithm")

if not method:

  method = methodStore.newMethod(task="Peak intensity", name="myPeakIntensityAlgorithm")

peakIntensity = peak.newPeakIntensity(intensityType="height", value=1234.56, method=method)

print peakIntensity.value

Thankfully, there are some utility functions in Analysis which allow the height and volume to be calculated using the standard Analysis routines.  There is also an additional utility function which allows the intensity to be set as desired (so "manually", although it could come from some other algorithm).

from ccpnmr.analysis.core.PeakBasic import setupPeakHeight, setupPeakVolume, setManualPeakIntensity

# These calculate intensities from the real spectrum data

setupPeakHeight(peak)

setupPeakVolume(peak)

height = peak.findFirstPeakIntensity(intensityType='height')

print height.value

# This sets the intensity manually

setManualPeakIntensity(peak, value=1234.56, intensityType="height")

height = peak.findFirstPeakIntensity(intensityType='height')

print height.value

 

PeakDim

The position of a peak in given dimension is specified in the corresponding PeakDim.  By default it is not set.  The position can be given either in points or in the unit of the corresponding ExpDimRef object (so normally "ppm").

peakDim = peak.findFirstPeakDim(dim=1)

# Get position

print peakDim.position

print peakDim.value

# Set position

peakDim.position = 784.3  # points

peakDim.value = 8.72  # ppm

Now the peakDim position must be between 1.0 and 1.0 + peakDim.dataDim.numPoints.  If the peak is aliased and its true position is not in the "fundamental" region then a numAliasing value can be specified.

peakDim.numAliasing = 1

In this case the actual position is at peakDim.position +  peakDim.numAliasing*peakDim.dataDim.numPointsOrig

If you have the positions (possibly not all inside the fundamental region) for all peakDims of a peak specified in a list in dimension order then there is a utility function which lets you set the position all in one go (and so in particular will calculate the numAliasing value):

from ccpnmr.analysis.core.PeakBasic import movePeak

position = (701.17, 66.358)

movePeak(peak, position)

Each PeakDim has an optional annotation which is a string that is supposed to contain a description of the assignment status.  There is a utility function which will set the annotation based on the existing assignment (if any), this annotation is stored as an attribute on the PeakDim object for display purposes. However, this text annotation should not be relied upon when working with assignmemnts; instead the assignment objects (PeakDimContrib below) should be queried.

from ccpnmr.analysis.core.AssignmentBasic import makePeakDimAnnotation

makePeakDimAnnotation(peakDim)

print peakDim.annotation

If we clear the assignment to the peak dimension (assuming it had one) then the annotation attribute will not change:

from ccpnmr.analysis.core.AssignmentBasic import clearPeakDim

clearPeakDim(peakDim)

print peakDim.annotation

The annotation must be refreshed, according to the new (blank) assignment.

makePeakDimAnnotation(peakDim)

print peakDim.annotation

Special note: If you are writing scripts that are executed within the Analysis program, then the peakDim.annotation will be automatically updated if you change a peak assignment. This is because Analysis uses a system of notification calls to detect when something has changed and automatically attempts to keep the annotations consistent.

Assignment Contributions

Peaks are linked to Resonance objects in order to assign them. These resonances in turn may be linked to atoms or other intermediate assignment information. A PeakDimContrib is a contribution to the assignment found on a given peak dimension (PeakDim); and there may be more than one contribution to indicate an ambiguous assignment.  As far as the data model objects are concerned, the Resonance assignment contributions (PeakDimContribs) and the groupings of these (PeakContribs) are not difficult to create with the Python API. For example PeakContribs objects are made via a Peak and have a weight (default value 0.0), which determines their relative contribution:

peakContrib = peak.newPeakContrib(weight=1.0)

However, there are many checks and further API calls that usually need to be made when assigning Resonances to peaks. These include:

For these reasons and more it is usually best to leave setting of peak assignments to the high-level Analysis functions. This is covered more fully in the section on assignment.