Macro to assign NmrAtoms during Backbone Pick & Assign steps

Here is a macro that will automatically assign your i and i-1 Ca/Cb/C atoms when you do the Pick & Assign step of a backbone assignment.

Simply do your Pick & Assign as usual (https://www.ccpn.ac.uk/manual/v3/PickAndAssign.html), but after you`ve done the `Pick and Assign Selected` for each NmrResidue, run this macro to assign your carbon NmrAtoms rather than using the NmrAtom Assigner. Makes for much less clicking, and if you have little overlap it should work really nicely and not need much in the way of manual corrections.

It`s probably easiest to link the macro with a shortcut so you can repeatedly run it quickly and easily (see https://www.ccpn.ac.uk/manual/v3/RunningMacros.html for more info).

Have a read through the information to check on requirements (e.g. you`ll have to set your experiment types).

Python
  1. """
  2. Macro to assign the Ca/Cb/C NmrAtoms when doing the Pick & Assign step of a
  3. backbone assignment.
  4.  
  5. This should work with any combination of HNCACB/HNCOCACB, HNCA/HNCOCA, HNCO/HNCACO spectra.
  6.  
  7. REQUIREMENTS:
  8. 1. Make sure your spectra have the correct Experiment Types associated with them (shortcut
  9. ET to set these).
  10. 2. The macro assumes that all 3D carbon AxisCodes are `C`. For HNCO/HNcaCO experiments you
  11. may find that these are `CO`. We recommend setting these to `C` by going to
  12. Spectrum Properties (double-click on the spectrum in the sidebar), then the Dimensions tab
  13. and here you can check/change the AxisCode.
  14. 3. Pick and Assign the peaks for an NmrResidue using the Pick and Assign module (PA), then
  15. run the macro before moving to the next residue. This is easiest if you associate the
  16. macro with a keyboard shortcut (you can do this with shortcut DU).
  17. 4. The Macro assumes that you always have the CO-based experiment (e.g. HNcoCACB, HNcoCA or HNCO)
  18. as well as the CA-based one (e.g. HNCACB, HNCA or HNcoCA) , i.e. it assigns the i-1 NmrResidues
  19. based on the peaks in the CO-based experiments rather than on peak intensities.
  20.  
  21. OPTIONS:
  22. - The macro currently uses a tolerance of 0.2 ppm. Peaks closer than this are assumed to belong to
  23. the same NmrAtom, i.e. if a peak in the HNCA is within 0.2 ppm of a peak in the HNcoCA, it is
  24. assumed that this is the i-1 and not the i peak. You can change this tolerance at the top of
  25. the Settings section.
  26.  
  27. NOTE:
  28. The macro assumes you have a relatively straight forward pattern of peaks. If you have
  29. picked lots of noise peaks you may not get correct behaviour (make sure you adjust your
  30. contour level before doing the `Pick & Assign Selected` step). You may also have to make manual
  31. corrections if there is peak overlap, e.g. between the i and i-1 atoms.
  32.  
  33. """
  34.  
  35. ############################## Settings #################################
  36.  
  37. tolerance = 0.2 # peaks closer than this value in ppm are assumed to belong to the same NmrAtom
  38. assignAxCde = `C` # Carbon AxisCode to be assigned, may need changing for HNCO/HNcoCA expts
  39. assignDim = 2 # Spectrum dimension to be assigned (0,1,2 for 3Ds)
  40. rootDim = 0 # One of the root dimensions which has already been assigned (0,1,2 for 3Ds)
  41. coSpectra = [`H[N[co[{CA|ca[C]}]]]`, `H[N[co[CA]]]`, `H[N[CO]]`]
  42. # Possible experiment types for `through-CO`/i-1 type spectra
  43. nonCoSpectra = [`H[N[{CA|ca[Cali]}]]`, `H[N[CA]]`, `H[N[ca[CO]]]`]
  44. # Possible experiment types for `through-CA`/i,i-1 type spectra
  45. gstCheckDict = {`CA-1`:{`shifts`:[], `peaks`:[]},
  46. `CB-1`:{`shifts`:[], `peaks`:[]},
  47. `CA0`:{`shifts`:[], `peaks`:[]},
  48. `CB0`:{`shifts`:[], `peaks`:[]}}
  49. # Data storage for Gly/Ser/Thr check and re-assignment if necessary
  50.  
  51.  
  52. ############################## Start of the code #################################
  53.  
  54. import sys
  55. from statistics import mean
  56. from ccpn.core.lib.ContextManagers import undoBlock
  57. from ccpn.ui.gui.widgets.MessageDialog import showWarning
  58.  
  59.  
  60. def assignNmrAtom(seqCode, atomName, offset):
  61. if offset == -1:
  62. newsc = ``.join((seqCode, `-1`))
  63. newnr = nc.fetchNmrResidue(sequenceCode=newsc, residueType=None)
  64. newna = newnr.fetchNmrAtom(name=atomName)
  65. elif offset == 0:
  66. newna = peakNmrRes.fetchNmrAtom(name=atomName)
  67. peak.assignDimension(axisCode=assignAxCde, value=newna)
  68.  
  69.  
  70. def storeDataForGSTCheck(peakShift, peak, atomType):
  71. gstCheckDict[atomType][`shifts`].append(peakShift)
  72. gstCheckDict[atomType][`peaks`].append(peak)
  73.  
  74.  
  75. def checkForGST(gstDict):
  76. cas1 = gstDict[`CA-1`][`shifts`]
  77. cbs1 = gstDict[`CB-1`][`shifts`]
  78. peaks1 = gstDict[`CA-1`][`peaks`] + gstDict[`CB-1`][`peaks`]
  79. identifyAndAssignGST(cas1, cbs1, peaks1)
  80. cas2 = gstDict[`CA0`][`shifts`]
  81. cbs2 = gstDict[`CB0`][`shifts`]
  82. peaks2 = gstDict[`CA0`][`peaks`] + gstDict[`CB0`][`peaks`]
  83. identifyAndAssignGST(cas2, cbs2, peaks2)
  84.  
  85.  
  86. def identifyAndAssignGST(cas, cbs, peaks):
  87. if len(cas) == 0 and len(cbs) != 0:
  88. if 50.0 > mean(cbs) > 40.0:
  89. for pk in peaks:
  90. nr = pk.assignmentsByDimensions[assignDim][0].nmrResidue
  91. na = nr.fetchNmrAtom(name=`CA`)
  92. pk.assignDimension(axisCode=assignAxCde, value=na)
  93. elif len(cbs) == 0 and len(cas) >= 2:
  94. for pk in peaks:
  95. if pk.ppmPositions[assignDim] > mean(cas):
  96. nr = pk.assignmentsByDimensions[assignDim][0].nmrResidue
  97. na = nr.fetchNmrAtom(name=`CB`)
  98. pk.assignDimension(axisCode=assignAxCde, value=na)
  99.  
  100.  
  101. if current.peak.assignmentsByDimensions[rootDim]:
  102. nc = current.peak.assignmentsByDimensions[rootDim][0].nmrResidue.nmrChain
  103. else:
  104. showWarning(`Missing Root Assignment`, `Please make sure all your peaks have `
  105. `their root NH NmrAtoms assigned`)
  106. sys.exit()
  107.  
  108. with undoBlock():
  109. for peak in current.peaks:
  110. peakSpectrum = peak.peakList.spectrum
  111. peakSpectrumName = peakSpectrum.name
  112. peakExptType = peakSpectrum.experimentType
  113. if peak.assignmentsByDimensions[rootDim]:
  114. peakNmrRes = peak.assignmentsByDimensions[rootDim][0].nmrResidue
  115. else:
  116. showWarning(`Missing Root Assignment`, `Please make sure all your peaks have `
  117. `their root NH NmrAtoms assigned`)
  118. sys.exit()
  119. peakSeqCode = peakNmrRes.sequenceCode
  120. peakShift = peak.ppmPositions[assignDim]
  121. # Assign CO-based i-1 spectra
  122. if peakExptType in coSpectra:
  123. if 80.0 >= peakShift >= 47.0:
  124. assignNmrAtom(peakSeqCode, atomName=`CA`, offset=-1)
  125. storeDataForGSTCheck(peakShift, peak, atomType=`CA-1`)
  126. elif peakShift < 47.0:
  127. assignNmrAtom(peakSeqCode, atomName=`CB`, offset=-1)
  128. storeDataForGSTCheck(peakShift, peak, atomType=`CB-1`)
  129. elif peakShift >= 160.0:
  130. assignNmrAtom(peakSeqCode, atomName=`C`, offset=-1)
  131. # Assign CA-based i/i-1 spectra
  132. elif peakExptType in nonCoSpectra:
  133. if 80.0 >= peakShift >= 47.0:
  134. for peak2 in current.peaks:
  135. if peak2.peakList.spectrum.experimentType in coSpectra:
  136. if abs(peakShift - peak2.ppmPositions[assignDim]) <= tolerance:
  137. assignNmrAtom(peakSeqCode, atomName=`CA`, offset=-1)
  138. storeDataForGSTCheck(peakShift, peak, atomType=`CA-1`)
  139. if not peak.assignmentsByDimensions[assignDim]:
  140. assignNmrAtom(peakSeqCode, atomName=`CA`, offset=0)
  141. storeDataForGSTCheck(peakShift, peak, atomType=`CA0`)
  142. elif peakShift < 47.0:
  143. for peak2 in current.peaks:
  144. if peak2.peakList.spectrum.experimentType in coSpectra:
  145. if abs(peakShift - peak2.ppmPositions[assignDim]) <= tolerance:
  146. assignNmrAtom(peakSeqCode, `CB`, offset=-1)
  147. storeDataForGSTCheck(peakShift, peak, atomType=`CB-1`)
  148. if not peak.assignmentsByDimensions[assignDim]:
  149. assignNmrAtom(peakSeqCode, atomName=`CB`, offset=0)
  150. storeDataForGSTCheck(peakShift, peak, atomType=`CB0`)
  151. elif peakShift >= 160.0:
  152. for peak2 in current.peaks:
  153. if peak2.peakList.spectrum.experimentType in coSpectra:
  154. if abs(peakShift - peak2.ppmPositions[assignDim]) <= tolerance:
  155. assignNmrAtom(peakSeqCode, `C`, offset=-1)
  156. if not peak.assignmentsByDimensions[assignDim]:
  157. assignNmrAtom(peakSeqCode, atomName=`C`, offset=0)
  158. elif peakExptType is None:
  159. showWarning(`Missing Experiment Type`, `Please make sure all `
  160. `your spectra have an Experiment Type `
  161. `associated with them (use shortcut ET `
  162. `to set these)`)
  163. sys.exit()
  164.  
  165. checkForGST(gstCheckDict)