Source code for ccpn.AnalysisAssign.modules.SequenceGraph

"""Module Documentation here

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

import typing
import numpy as np
from functools import partial
from PyQt5 import QtGui, QtWidgets, QtCore
from collections import OrderedDict
from itertools import product
from ccpn.util.OrderedSet import OrderedSet
from contextlib import contextmanager
from ccpn.core.lib.Pid import Pid
from ccpn.core.NmrAtom import NmrAtom
from ccpn.core.NmrResidue import NmrResidue
from ccpn.core.Peak import Peak
from ccpn.core.Spectrum import Spectrum
from ccpn.core.lib.AssignmentLib import getNmrResiduePrediction
from ccpn.core.lib.Notifiers import Notifier
from ccpn.core.lib.CallBack import CallBack
from ccpn.ui.gui.lib.StripLib import navigateToNmrResidueInDisplay, _getCurrentZoomRatio
from ccpn.ui.gui.lib.mouseEvents import makeDragEvent
from ccpn.ui.gui.widgets.Frame import Frame
from ccpn.ui.gui.widgets.Widget import Widget
# from ccpn.ui.gui.guiSettings import textFontSmall, textFontSmallBold, textFont
from ccpn.ui.gui.guiSettings import getColours, BORDERNOFOCUS, BORDERFOCUS
from ccpn.ui.gui.guiSettings import GUINMRATOM_NOTSELECTED, GUINMRATOM_SELECTED, \
    GUINMRRESIDUE, SEQUENCEGRAPHMODULE_LINE, SEQUENCEGRAPHMODULE_TEXT
from ccpn.ui.gui.modules.CcpnModule import CcpnModule
from ccpn.ui.gui.widgets.Menu import Menu
from ccpn.ui.gui.widgets.Icon import Icon
from ccpn.ui.gui.widgets.ToolBar import ToolBar
from ccpn.ui.gui.widgets.CompoundWidgets import CheckBoxCompoundWidget
from ccpn.ui.gui.widgets.PulldownListsForObjects import NmrChainPulldown, ChemicalShiftListPulldown
from ccpn.ui.gui.widgets.Spacer import Spacer
from ccpn.core.NmrChain import NmrChain
from ccpn.util.Common import makeIterableList, greekKey
from ccpn.util.Logging import getLogger
from ccpn.util import Colour
from ccpn.ui.gui.widgets.MessageDialog import showWarning, progressManager
from ccpn.ui.gui.widgets.Splitter import Splitter
from ccpn.ui.gui.widgets.Frame import Frame
from ccpn.ui.gui.widgets.SequenceWidget import SequenceWidget
from ccpn.ui.gui.widgets.Font import setWidgetFont, getFontHeight, SEQUENCEGRAPHFONT
from ccpn.ui.gui.widgets.SettingsWidgets import ModuleSettingsWidget, \
    ChainSelectionWidget, SpectrumDisplaySelectionWidget
from ccpn.core.lib.AssignmentLib import getAllSpinSystems
from ccpn.core.lib.ContextManagers import undoBlockWithoutSideBar
from ccpnc.clibrary import Clibrary


_getNmrIndex = Clibrary.getNmrResidueIndex

logger = getLogger()
ALL = '<Use all>'


#==========================================================================================
# GuiNmrAtom
#==========================================================================================

[docs]class GuiNmrAtom(QtWidgets.QGraphicsSimpleTextItem): """ A graphical object specifying the position and name of an atom when created by the Assigner. Can be linked to a Nmr Atom. """ def __init__(self, mainWindow, text, pos=None, nmrAtom=None): super().__init__(text) # self.setPlainText(text) br = self.boundingRect() self.setPos(pos[0] - br.x(), pos[1] - br.y()) self.mainWindow = mainWindow # self.application = mainWindow.application # self.project = mainWindow.application.project self.current = mainWindow.application.current self.nmrAtom = nmrAtom self.connectedAtoms = 0 self.connectedList = {} # maintain connectivity between guiNmrAtoms # so that lines do not overlap setWidgetFont(self, name=SEQUENCEGRAPHFONT) # self.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) # # # set the highlight colour for dragging to chain self.colours = getColours() if self.isSelected: self.setBrush(QtGui.QColor(self.colours[GUINMRATOM_SELECTED])) else: self.setBrush(QtGui.QColor(self.colours[GUINMRATOM_NOTSELECTED]))
[docs] def mouseDoubleClickEvent(self, event): """CCPN INTERNAL - re-implementation of double click event """ pass
[docs] def mousePressEvent(self, event): """CCPN INTERNAL - re-implementation of mouse press event """ if self.nmrAtom is not None: self.current.nmrAtom = self.nmrAtom self.current.nmrResidue = self.nmrAtom.nmrResidue event.accept()
def _raiseContextMenu(self, obj, pos): #, event: QtGui.QMouseEvent): """Creates and raises a context menu enabling items to be disconnected """ from ccpn.ui.gui.widgets.Menu import Menu from functools import partial # print('>>> deassign peak menu') # widg = event.widget() contextMenu = Menu('', self.mainWindow, isFloatWidget=True) contextMenu.addAction('deassign all Peaks', partial(self._deassignAllPeaksFromNmrAtom)) # cursor = QtGui.QCursor() contextMenu.move(pos.x(), pos.y() + 10) contextMenu.exec_()
[docs] def addConnectedList(self, connectedAtom): """maintain number of links between adjacent nmrAtoms. """ keyVal = connectedAtom if keyVal in self.connectedList: self.connectedList[keyVal] += 1 else: self.connectedList[keyVal] = 1
# def removeConnectedList(self, connectedAtom): # """maintain number of links between adjacent nmrAtoms. # """ # keyVal = connectedAtom # if keyVal in self.connectedList: # self.connectedList[keyVal] -= 1 # else: # raise RuntimeError('Connection does not exist')
[docs] def getConnectedList(self, connectedAtom): """Retrieve number of links between adjacent nmrAtoms. """ keyVal = connectedAtom if keyVal in self.connectedList: return self.connectedList[keyVal] else: return 0
[docs] def clearConnectedList(self): """Clear all connections for this guiNmrAtom but do not delete. """ for keyVal in self.connectedList: keyVal.connectedList[self] = 0 self.connectedList[keyVal] = 0
# def deleteConnectedList(self): # """Delete all connections for this guiNmrAtom. # """ # for keyVal in self.connectedList: # del keyVal.connectedList[self] # self.connectedList = {} #========================================================================================== # GuiNmrResidue #==========================================================================================
[docs]class GuiNmrResidue(QtWidgets.QGraphicsSimpleTextItem): """ Object linking residues displayed in Assigner and Nmr Residues. Contains functionality for drag and drop assignment in conjunction with the Sequence Module. """ def __init__(self, parent, nmrResidue, caAtom, lineSpacing): super().__init__(nmrResidue.id) # self.setPlainText(nmrResidue.id) # self.mainWindow = parent.mainWindow # self.application = parent.mainWindow.application # self.project = parent.mainWindow.project self.current = parent.mainWindow.application.current # self.setFont(self.mainWindow.application._fontSettings.textFontSmall) setWidgetFont(self, name=SEQUENCEGRAPHFONT, size='MEDIUM') self.colours = getColours() # self.setDefaultTextColor(QtGui.QColor(self.colours[GUINMRRESIDUE])) self.setBrush(QtGui.QColor(self.colours[GUINMRRESIDUE])) self.setPos(caAtom.x() - caAtom.boundingRect().width(), caAtom.y() + (2 * lineSpacing)) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable) self._parent = parent self.nmrResidue = nmrResidue # self.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) def _update(self): # self.setPlainText(self.nmrResidue.id) self.setText(self.nmrResidue.id) def _mouseMoveEvent(self, event): """create a drag item if left button pressed """ if (event.buttons() == QtCore.Qt.LeftButton) and (event.pos() - self._pressPos).manhattanLength() > QtWidgets.QApplication.startDragDistance(): nmrItem = self if nmrItem: # align to the top-left corner so you can see the drop to the sequence module makeDragEvent(event.widget(), {'pids': [nmrItem.nmrResidue.pid]}, [self.text()], self.text(), action=QtCore.Qt.MoveAction, alignCentre=False) def _mousePressEvent(self, event): self.current.nmrResidue = self.nmrResidue self.setSelected(True) self._pressPos = event.pos() def _mouseDoubleClickEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self._parent.showNmrResidue(self) event.accept() else: super().mouseDoubleClickEvent(event)
# def _raiseLineMenu(self, scene, event): # """Creates and raises a context menu enabling items to be disconnected # """ # from ccpn.ui.gui.widgets.Menu import Menu # from functools import partial # # cursor = QtGui.QCursor() # contextMenu = Menu('', event.widget(), isFloatWidget=True) # pressed = self.scene.mouseGrabberItem() # # if self.selectedLine: # thisLine = self.selectedLine # contextMenu.addAction('deassign nmrAtoms from Peak: %s' % str(thisLine._peak.id)) # contextMenu.addSeparator() # if thisLine._peak: # # # skip if nothing connected # if not thisLine._peak.assignedNmrAtoms: # return # # # add the nmrAtoms to the menu # for nmrAtomList in thisLine._peak.assignedNmrAtoms: # for nmrAtom in nmrAtomList: # if nmrAtom: # contextMenu.addAction(nmrAtom.id, partial(self._deassignPeak, thisLine._peak, nmrAtom)) #========================================================================================== # Assignment line #==========================================================================================
[docs]class AssignmentLine(QtWidgets.QGraphicsLineItem): """ Object to create lines between GuiNmrAtoms with specific style, width, colour and displacement. Displacement allows multiplet peak lines to be shown as adjacent lines between the same nmrAtom. """ def __init__(self, x1, y1, x2, y2, colour, width, parent=None, style=None, peak=None, guiAtom1: GuiNmrAtom = None, guiAtom2: GuiNmrAtom = None, displacement=None): super().__init__() # set the pen colour and style self.pen = QtGui.QPen() # check whether the colour is a gradient if colour and colour.startswith('#'): self.pen.setColor(QtGui.QColor(colour)) elif colour in Colour.colorSchemeTable: _colours = Colour.colorSchemeTable[colour] self.pen.setColor(QtGui.QColor(_colours[0])) self.pen.setCosmetic(True) self.pen.setWidth(width) self._width = width if style == 'dash': self.pen.setStyle(QtCore.Qt.DotLine) self.setPen(self.pen) self.setLine(x1, y1, x2, y2) self._parent = parent # store the peak and the guiNmrAtoms that the line connects self._peak = peak self.guiAtom1 = guiAtom1 self.guiAtom2 = guiAtom2 self.displacement = displacement # enable hovering so the current line can be set self.setAcceptedMouseButtons(QtCore.Qt.RightButton) self.setAcceptHoverEvents(True)
[docs] def updateEndPoints(self): """Update the endPoints of the line to point. Co-ordinates are relative to the group to which the graphicsItem belongs, in this case the guiNmrResidue group. GuiNmrResidue group is the top level relative to the scene. """ guiAtom1 = self.guiAtom1 guiAtom2 = self.guiAtom2 if guiAtom1 is None or guiAtom2 is None: return residue1 = guiAtom1.guiNmrResidueGroup residue2 = guiAtom2.guiNmrResidueGroup rx1 = residue1.x() ry1 = residue1.y() rx2 = residue2.x() ry2 = residue2.y() atom1Rect = guiAtom1.boundingRect() atom2Rect = guiAtom2.boundingRect() w1 = atom1Rect.width() * 2 h1 = atom1Rect.height() * 2 w2 = atom2Rect.width() * 2 h2 = atom2Rect.height() * 2 x1 = guiAtom1.x() - w1 // 4 # + rx1 y1 = guiAtom1.y() - h1 // 4 # + ry1 x2 = guiAtom2.x() + (rx2 - rx1) - w2 // 4 y2 = guiAtom2.y() + (ry2 - ry1) - h2 // 4 dx = x2 - x1 dy = y2 - y1 length = 2.0 * pow(dx * dx + dy * dy, 0.5) if abs(length) < 1e-6: return if self.displacement is not None: count = (guiAtom1.connectedList[guiAtom2] - 1) // 2 disp = self._width * 3 * (self.displacement - count) / length else: disp = 0.0 offsetX = dy * disp offsetY = -dx * disp kx1 = (w1 * dx) / length # shorten the lines along length ky1 = (h1 * dy) / length kx2 = (w2 * dx) / length ky2 = (h2 * dy) / length xOff1 = w1 / 2.0 # offset to centre of bounding box yOff1 = h1 / 2.0 xOff2 = w2 / 2.0 yOff2 = h2 / 2.0 x1 += xOff1 + kx1 + offsetX y1 += yOff1 + ky1 + offsetY x2 += xOff2 - kx2 + offsetX y2 += yOff2 - ky2 + offsetY self.setLine(x1, y1, x2, y2)
[docs] def paint(self, painter, option, widget): """Automatically update the end-points of the assignment lines to point to the correct guiNmrAtoms """ self.updateEndPoints() super().paint(painter, option, widget)
[docs] def hoverEnterEvent(self, event): self._parent.selectedLine = self
[docs] def hoverLeaveEvent(self, event): self._parent.selectedLine = None
[docs] def mousePressEvent(self, event): """Required to respond to mouse press events. """ pass
#========================================================================================== # GuiNmrResidueGroup #==========================================================================================
[docs]class GuiNmrResidueGroup(QtWidgets.QGraphicsItemGroup): """ Group item to group all nmrAtoms/connecting lines of nmrResidue """ def __init__(self, parent, nmrResidue, caAtom, pos, lineSpacing): super().__init__() self.mainWindow = parent.mainWindow self.application = self.mainWindow.application self.project = self.mainWindow.project self.current = self.mainWindow.application.current self.nmrResidue = nmrResidue self._parent = parent self.setPos(pos, 0.0) self.crossChainCount = None self.crossChainResidue = None self.connected = None self.nmrResidueLabel = GuiNmrResidue(parent, nmrResidue, caAtom, lineSpacing) self.addToGroup(self.nmrResidueLabel)
[docs] def mousePressEvent(self, event): self.nmrResidueLabel._mousePressEvent(event)
[docs] def mouseMoveEvent(self, event): self.nmrResidueLabel._mouseMoveEvent(event)
[docs] def mouseDoubleClickEvent(self, event): self.nmrResidueLabel._mouseDoubleClickEvent(event)
[docs]class GuiSelectionBoxes(QtWidgets.QGraphicsItemGroup): """ Group item to group all selection boxes """ def __init__(self, scene): super().__init__() self._scene = scene self.selectionBoxes = {} # self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
[docs] def addSelection(self, nmrResidue, guiRes, colour, width, style, spacing): self._addItem(nmrResidue, guiRes, colour, width, style, spacing, 'selected')
[docs] def addSelectionLeftBracket(self, nmrResidue, guiRes, colour, width, style, spacing): self._addItem(nmrResidue, guiRes, colour, width, style, spacing, 'left')
[docs] def addSelectionRightBracket(self, nmrResidue, guiRes, colour, width, style, spacing): self._addItem(nmrResidue, guiRes, colour, width, style, spacing, 'right')
def _addItem(self, nmrResidue, guiRes, colour, width, style, spacing, type): _name = nmrResidue.pid + type if _name in self.selectionBoxes: self._scene.removeItem(self.selectionBoxes[_name]) # add the new selection lines, and push to the back _newGroup = GuiSelection(guiRes, colour, width, style, spacing, type) _newGroup.setParentItem(guiRes) _newGroup.setZValue(-2) self.selectionBoxes[_name] = _newGroup
[docs] def clear(self): for item in self.selectionBoxes.values(): self._scene.removeItem(item) self.selectionBoxes = {}
[docs]class GuiSelection(QtWidgets.QGraphicsItemGroup): """ Item to hold the lines for a selection """ def __init__(self, guiRes, colour, width, style, spacing, type): super().__init__() self._colour = colour self._width = width self._style = style self._spacing = spacing # set the pen colour and style self.pen = QtGui.QPen() self.pen.setColor(QtGui.QColor(colour)) self.pen.setCosmetic(True) self.pen.setWidth(width) if style == 'dash': self.pen.setStyle(QtCore.Qt.DotLine) _scale = spacing * 2.9 _xOffset = spacing * 0.4 _yOffset = spacing * 0.45 if type == 'selected': # lines for a box # coords = ((0, 0), (1, 0), (1, 0), (1, 1), (1, 1), (0, 1), (0, 1), (0, 0)) # _scale = spacing * 2.8 # _xOffset = spacing * 0.35 # _yOffset = spacing * 0.4 # add a box around the selected nmrResidue label _xOffset = guiRes.nmrResidueLabel.pos().x() _yOffset = guiRes.nmrResidueLabel.pos().y() _rect = guiRes.nmrResidueLabel.boundingRect().adjusted(-10 + _xOffset, -10 + _yOffset, 10 + _xOffset, 10 + _yOffset) # _rect = guiRes.boundingRect().adjusted(-10, -10, 10, 10) _lineGroup = QtWidgets.QGraphicsItemGroup() self.addToGroup(_lineGroup) _line = QtWidgets.QGraphicsRectItem(_rect) _line.setPen(self.pen) _lineGroup.addToGroup(_line) return elif type in ['left', 'right']: if type == 'left': # lines for a left square bracket coords = ((0.125, 0), (0, 0), (0, 0), (0, 1), (0, 1), (0.125, 1)) else: # lines for a right square bracket coords = ((0.875, 0), (1, 0), (1, 0), (1, 1), (1, 1), (0.875, 1)) _lineGroup = QtWidgets.QGraphicsItemGroup() self.addToGroup(_lineGroup) # add the lines here for p0, p1 in zip(coords[::2], coords[1::2]): _line = QtWidgets.QGraphicsLineItem(p0[0] * _scale - _xOffset, -p0[1] * _scale + _yOffset, p1[0] * _scale - _xOffset, -p1[1] * _scale + _yOffset) _line.setPen(self.pen) _lineGroup.addToGroup(_line)
#========================================================================================== # NmrResidueList #==========================================================================================
[docs]class NmrResidueList(): """ A Class to hold the information about each gui object in the scene """ def __init__(self, mainWindow, settingsWidget, lineColour, textColour, atomSpacing, lineSpacing, lineWidth, lineConnectWidth, scene, module, defaultResidueAtoms, atomPositionDict): """Initialise the new object. """ self.mainWindow = mainWindow self.application = mainWindow.application self.project = mainWindow.project self.current = mainWindow.application.current self._scene = scene self._SGwidget = settingsWidget self._lineColour = lineColour self._textColour = textColour self._atomSpacing = atomSpacing self._lineSpacing = lineSpacing self._lineWidth = lineWidth self._lineConnectWidth = lineConnectWidth self._module = module self.nmrChain = None self._defaultResidueAtoms = defaultResidueAtoms self._atomPositionDict = atomPositionDict self.reset()
[docs] def reset(self): self.residueCount = 0 self.direction = None self.selectedStretch = [] self.selectedLine = None # change to an orderedDict so that more nmrChains can be seen in the future self.nmrChains = OrderedDict() # referenced by nmrChain # store all visible gui items self.guiNmrResidues = OrderedDict() # referenced by nmrResidue self.guiNmrAtoms = OrderedDict() # referenced by nmrAtom self.guiGhostNmrResidues = OrderedDict() # referenced by nmrResidue self.guiNmrAtomsFromNmrResidue = OrderedDict() # referenced by nmrResidue -> list(guiNmrAtoms) self.ghostList = {} self.connectingLines = {} # referenced by peak? self.assignmentLines = {} self.guiSelectionBoxes = GuiSelectionBoxes(self._scene) self._nmrPredictions = {} self.nmrChain = None # current active nmrChain
[docs] def size(self, nmrChainId): """return the number of elements in the list nmrChain. """ return len(self.nmrChains[nmrChainId]) if nmrChainId in self.nmrChains else None
#==========================================================================================
[docs] def getIndexNmrResidue(self, nmrResidue): """get the index in the nmrResidueList of the required nmrResidue. """ for itemId, nmrCh in self.nmrChains.items(): if nmrResidue in nmrCh: return nmrCh.index(nmrResidue)
# resList = [item[0] for item in self.allNmrResidues] # if nmrResidue in resList: # return resList.index(nmrResidue) # def deleteNmrResidue(self, nmrResidue): # """get the index in the nmrResidueList of the required nmrResidue. # """ # for itemId, nmrCh in self.nmrChains.items(): # if nmrResidue in nmrCh: # nmrCh.remove(nmrResidue) # print('>>>removing from nmrChains') # def deleteNmrResidueIndex(self, index): # """insert into the list as a tuple (obj, dict). # """ # return self.allNmrResidues.pop(index) # # def _appendNmrResiduePair(self, nmrResidue, guiAtoms): # """insert into the list as a tuple (obj, dict). # """ # self.allNmrResidues.append((nmrResidue, guiAtoms)) def _insertNmrResiduePair(self, nmrChainId, index, nmrResidue): """insert into the list as a tuple (obj, dict). """ if nmrChainId not in self.nmrChains: self.nmrChains[nmrChainId] = [nmrResidue] else: self.nmrChains[nmrChainId].insert(index, nmrResidue) # self.allNmrResidues.insert(index, (nmrResidue, guiAtoms)) # self.allNmrResidues[index] = (nmrResidue, guiAtoms) # def _getNmrResiduePair(self, index): # """insert into the list as a tuple. # """ # val = self.allNmrResidues[index] # return val[0], val[1] # # def _setNmrResiduePair(self, index, nmrResidue, guiAtoms): # """insert into the list as a tuple. # """ # self.allNmrResidues[index] = (nmrResidue, guiAtoms) # def _updateAllNmrResidueSize(self): # """Change the size of this list based on whether mainNmrResidues has changed # """ # if self.nmrChain: # mainNmrResidues = self.nmrChain.mainNmrResidues # if self.nmrChain not in self.allNmrResidues: # self.allNmrResidues[self.nmrChain] = [None] * len(mainNmrResidues) # # else: # resList = self.allNmrResidues[self.nmrChain] # lenAll = len(resList) # if lenAll == 0: # # create a new list # self.allNmrResidues[self.nmrChain] = [None] * len(mainNmrResidues) # # else: # # update the list size copying the original data into it # ii = _getNmrIndex(resList[0]) # newList = [None] * len(mainNmrResidues) # for res in self.allNmrResidues[self.nmrChain]: # index = _getNmrIndex(res) # if index and index < len(mainNmrResidues): # newList[_getNmrIndex(res)] = res #==========================================================================================
[docs] def addNmrResidue(self, nmrChainId, nmrResidue, index=0, _insertNmrRes=True, spacing=66, residueAtoms=None, showPredictions=True, showSideChain=False): """Add a new nmrResidue at the required position. """ self._addNmrResidue(nmrChainId, nmrResidue, nmrResidueIndex=index, _insertNmrRes=_insertNmrRes, spacing=spacing, residueAtoms=residueAtoms, showPredictions=showPredictions, showSideChain=showSideChain)
def _addNmrResidue(self, nmrChainId, nmrResidue, nmrResidueIndex=0, _insertNmrRes=True, spacing=66, residueAtoms=None, showPredictions=True, showSideChain=False): """Takes an Nmr Residue, and adds a residue to the sequence graph corresponding to the Nmr Residue at the required index. Nmr Residue name displayed beneath CA of residue drawn and residue type predictions displayed beneath Nmr Residue name """ # check whether the guiNmrResidue already exists, and skip if nmrResidue in self.guiNmrResidues: return guiAtoms = {} # mainNmrResidues = nmrResidue.nmrChain.mainNmrResidues self.atomSpacing = spacing nmrAtomNames = [nmrAtom.name for nmrAtom in nmrResidue.nmrAtoms] # backboneAtoms = DEFAULT_RESIDUE_ATOMS.copy() backboneAtoms = residueAtoms.copy() if nmrResidue.residueType == 'GLY': # GLY doesn't have CB del backboneAtoms['CB'] # add extra guiAtoms to the list based on the backbone atoms dict above - to self.guiNmrAtomDict[nmrAtoms] self.addBackboneAtoms(nmrResidue, backboneAtoms, nmrAtomNames, guiAtoms) # add the sideChain atoms to self.guiNmrAtomDict[nmrAtoms] if showSideChain: if 'CB' in backboneAtoms and nmrResidue.residueType: cbAtom = guiAtoms['CB'] self.addSideChainAtoms(nmrResidue, cbAtom, nmrAtomNames, guiAtoms) # store the reference to all gui NmrAtoms from nmrResidue self.guiNmrAtomsFromNmrResidue[nmrResidue] = guiAtoms # self._updateAllNmrResidueSize() # # add the new nmrResidue to the current list # if not self.allNmrResidues: # # # append to the list self.allNmrResidues # self.allNmrResidues = [None] * len(mainNmrResidues) # self.allNmrResidues[mainNmrResidues.index(nmrResidue)] = (nmrResidue, guiAtoms) # # self._appendNmrResiduePair(nmrResidue, guiAtoms) # # else: # insert into the correct nmrChain if _insertNmrRes: self._insertNmrResiduePair(nmrChainId, nmrResidueIndex, nmrResidue) # index = mainNmrResidues.index(nmrResidue) # self.allNmrResidues[nmrResidue][index] = (nmrResidue, guiAtoms) # compile a gui group for this nmrResidue - self.guiNmrResidues[nmrResidue newGuiResidueGroup = self._assembleGroupResidue(nmrResidue, guiAtoms, showPredictions=showPredictions) return newGuiResidueGroup def _addGhostResidue(self, nmrResidueCon1: NmrResidue, # guiRef: GuiNmrAtom, nmrResidueCon0: NmrResidue, # name1: str, name0: str, # offsetAdjust, atomSpacing=None, lineList=None, residueAtoms=None): """Takes an Nmr Residue and a direction, either '-1 or '+1', and adds a residue to the sequence graph corresponding to the Nmr Residue. Nmr Residue name displayed beneath CA of residue drawn and residue type predictions displayed beneath Nmr Residue name """ # need to keep a list of the atoms that have been added so don't repeat count = 0 if nmrResidueCon0 in self.ghostList: count = len(self.ghostList[nmrResidueCon0]) if nmrResidueCon1 in self.ghostList[nmrResidueCon0]: # already exists in the dict so exit return else: self.ghostList[nmrResidueCon0] = () nmrResidue = nmrResidueCon1 atoms = {} if atomSpacing: self.atomSpacing = atomSpacing nmrAtoms = [nmrAtom.name for nmrAtom in nmrResidue.nmrAtoms] # residueAtoms = DEFAULT_RESIDUE_ATOMS.copy() residueAtomsCopy = residueAtoms.copy() if nmrResidue.residueType == 'GLY': del residueAtomsCopy['CB'] for k, v in residueAtomsCopy.items(): # if k in nmrAtoms: nmrAtom = nmrResidue.getNmrAtom(k) # else: # nmrAtom = None atoms[k] = self._createGhostGuiNmrAtom(k, v, nmrAtom) newGuiResidueGroup = self._assembleGhostResidue(nmrResidue, atoms, lineList=lineList) newGuiResidueGroup.crossChainCount = count newGuiResidueGroup.crossChainResidue = nmrResidueCon0 self.ghostList[nmrResidueCon0] += (nmrResidueCon1,) return atoms #========================================================================================== def _createGuiNmrAtom(self, atomType: str, position: typing.Iterable, nmrAtom: NmrAtom = None) -> GuiNmrAtom: """Creates a GuiNmrAtom specified by the atomType and graphical position supplied. GuiNmrAtom can be linked to an NmrAtom by supplying it to the function. """ guiAtom = GuiNmrAtom(self.mainWindow, text=atomType, pos=list(position), nmrAtom=nmrAtom) if nmrAtom: # only add to the dict if the nmrAtom exists self.guiNmrAtoms[nmrAtom] = guiAtom return guiAtom def _createGhostGuiNmrAtom(self, atomType: str, position: typing.Iterable, nmrAtom: NmrAtom = None) -> GuiNmrAtom: """Creates a GuiNmrAtom specified by the atomType and graphical position supplied. GuiNmrAtom can be linked to an NmrAtom by supplying it to the function. """ guiAtom = GuiNmrAtom(self.mainWindow, text=atomType, pos=list(position), nmrAtom=nmrAtom) if nmrAtom: # only add to the dict if the nmrAtom exists self.guiNmrAtoms[nmrAtom] = guiAtom return guiAtom #========================================================================================== def _nmrAtomID(self, nmrAtom): """Create an id string to retrieve guiNmrAtoms. """ return nmrAtom.nmrResidue.id + nmrAtom.name
[docs] def addBackboneAtoms(self, nmrResidue, backboneAtoms, atomNames, guiAtoms): """add the backbone atoms. """ for k, v in backboneAtoms.items(): # if k in atomNames: nmrAtom = nmrResidue.getNmrAtom(k) # else: # nmrAtom = None guiAtoms[k] = self._createGuiNmrAtom(k, v, nmrAtom)
[docs] def addSideChainAtoms(self, nmrResidue, cbAtom, atomNames, guiAtoms): """Add the sideChain atoms above the backbone line. """ # residue = {} # for k, v in ATOM_POSITION_DICT[nmrResidue.residueType].items(): for k, v in self._atomPositionDict[nmrResidue.residueType].items(): if k != 'boundAtoms': position = [cbAtom.x() + v[0], cbAtom.y() + v[1]] # if k in atomNames: nmrAtom = nmrResidue.getNmrAtom(k) # else: # nmrAtom = None newAtom = self._createGuiNmrAtom(k, position, nmrAtom) # self.scene.addItem(newAtom) # residue[k] = newAtom guiAtoms[k] = newAtom
#========================================================================================== def _assembleGroupResidue(self, nmrResidue: NmrResidue, guiAtoms: typing.Dict[str, GuiNmrAtom], showPredictions: bool = True): """Takes an Nmr Residue and a dictionary of atom names and GuiNmrAtoms and creates a graphical representation of a residue in the assigner """ guiResidueGroup = GuiNmrResidueGroup(self._module, nmrResidue, guiAtoms['CA'], 0, self._lineSpacing) # insert into the gui list and add to the scene self.guiNmrResidues[nmrResidue] = guiResidueGroup self._scene.addItem(guiResidueGroup) # add the atoms to the group and set the reverse link for item in guiAtoms.values(): guiResidueGroup.addToGroup(item) item.guiNmrResidueGroup = guiResidueGroup # add the backbone lines - sidechain will be added in the future if "CB" in guiAtoms: self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['CA'], guiAtoms['CB'], self._lineColour, self._lineConnectWidth, lineList=self.connectingLines, lineId=nmrResidue) if "H" in guiAtoms and nmrResidue.residueType != 'PRO': self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['H'], guiAtoms['N'], self._lineColour, self._lineConnectWidth, lineList=self.connectingLines, lineId=nmrResidue) self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['N'], guiAtoms['CA'], self._lineColour, self._lineConnectWidth, lineList=self.connectingLines, lineId=nmrResidue) self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['C'], guiAtoms['CA'], self._lineColour, self._lineConnectWidth, lineList=self.connectingLines, lineId=nmrResidue) self.addConnectionsBetweenAllGroups(nmrResidue.nmrChain.pid) if showPredictions: self._addGroupResiduePredictions(guiResidueGroup, nmrResidue, guiAtoms['CA']) return guiResidueGroup def _assembleGhostResidue(self, nmrResidue: NmrResidue, guiAtoms: typing.Dict[str, GuiNmrAtom], lineList=None): """Takes an Nmr Residue and a dictionary of atom names and GuiNmrAtoms and creates a graphical representation of a residue in the assigner """ guiResidueGroup = GuiNmrResidueGroup(self._module, nmrResidue, guiAtoms['CA'], 0, self._lineSpacing) self.guiGhostNmrResidues[nmrResidue] = guiResidueGroup self._scene.addItem(guiResidueGroup) # add the atoms to the group and set the reverse link for item in guiAtoms.values(): guiResidueGroup.addToGroup(item) item.guiNmrResidueGroup = guiResidueGroup # add the backbone lines - sidechain will be added in the future if "CB" in list(guiAtoms.keys()): self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['CA'], guiAtoms['CB'], self._lineColour, self._lineConnectWidth, lineList=lineList, lineId=nmrResidue) if "H" in list(guiAtoms.keys()) and nmrResidue.residueType != 'PRO': self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['H'], guiAtoms['N'], self._lineColour, self._lineConnectWidth, lineList=lineList, lineId=nmrResidue) self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['N'], guiAtoms['CA'], self._lineColour, self._lineConnectWidth, lineList=lineList, lineId=nmrResidue) self._addConnectingLineToGroup(guiResidueGroup, guiAtoms['C'], guiAtoms['CA'], self._lineColour, self._lineConnectWidth, lineList=lineList, lineId=nmrResidue) return guiResidueGroup
[docs] def setNmrResidueSelection(self, nmrResidues): # clear previous selection self.guiSelectionBoxes.clear() for nmrResidue in nmrResidues: if nmrResidue in self.guiNmrResidues: guiRes = self.guiNmrResidues[nmrResidue] self.guiSelectionBoxes.addSelection(nmrResidue, guiRes, getColours()[BORDERFOCUS], self._lineWidth, None, self._atomSpacing)
#========================================================================================== def _addConnectingLineToGroup(self, group: GuiNmrResidueGroup, guiAtom1: GuiNmrAtom, guiAtom2: GuiNmrAtom, colour: str, width: float, displacement: float = None, style: str = None, peak: Peak = None, lineList=None, lineId=typing.Any, zValue=-1): """Adds a line between two GuiNmrAtoms using the width, colour, displacement and style specified. """ itemKey = id(lineId) if itemKey not in lineList: lineList[itemKey] = [] for line in lineList[itemKey]: if (line.guiAtom1 == guiAtom1 and line.guiAtom2 == guiAtom2 and line._peak == peak) or \ (line.guiAtom2 == guiAtom1 and line.guiAtom1 == guiAtom2 and line._peak == peak): break else: # add a newLine only if it doesn't already exists - may cause some gaps in the displacements newLine = AssignmentLine(0, 0, 0, 0, colour, width, parent=self, style=style, peak=peak, guiAtom1=guiAtom1, guiAtom2=guiAtom2, displacement=displacement) newLine.setParentItem(group) newLine.setZValue(zValue) lineList[itemKey].append(newLine) return newLine
[docs] def addConnectionsBetweenAllGroups(self, nmrChainId): """Add the connections between the groups. """ # get the list of nmrResidues in the required nmrChain referenced by nmrChainId mainNmrResidues = self.nmrChains[nmrChainId] if nmrChainId in self.nmrChains else [] #[resPair[0] for resPair in self.nmrChains[nmrChainId]] # iterate through the adjacent pairs for prevRes, thisRes in zip(mainNmrResidues[:-1], mainNmrResidues[1:]): thisGroup = self.guiNmrResidues[prevRes] if thisGroup.connected: continue # add the connection the minus residue and point to the right - may need to change for +1 residues if prevRes in self.guiNmrAtomsFromNmrResidue and thisRes in self.guiNmrAtomsFromNmrResidue: prevGuiAtoms = self.guiNmrAtomsFromNmrResidue[prevRes] thisGuiAtoms = self.guiNmrAtomsFromNmrResidue[thisRes] if (prevRes.nextNmrResidue and prevRes.nextNmrResidue is thisRes): # and connectsNeeded: # connect from the previous 'C' to this 'N' thisGroup.connected = self._addConnectingLineToGroup(thisGroup, prevGuiAtoms['C'], thisGuiAtoms['N'], self._lineColour, self._lineConnectWidth, lineList=self.connectingLines, lineId=thisRes, zValue=-3)
# def addConnectionsBetweenGroups(self, nmrResidue): # """Add a single connection to the right of a group # """ # # connectsNeeded = self._module.nmrResiduesCheckBox.isChecked() # why was this here? # # resList = ((nmrResidue.previousNmrResidue, nmrResidue), (nmrResidue, nmrResidue.nextNmrResidue)) # # for (prevRes, thisRes) in resList: # if prevRes and thisRes: # thisGroup = self.guiNmrResidues[prevRes] # if thisGroup and not thisGroup.connected: # # add the connection the minus residue and point to the right - may need to change for +1 residues # # prevRes, prevGuiAtoms = prev # # thisRes, thisGuiAtoms = this # try: # prevGuiAtoms = self.guiNmrAtomsFromNmrResidue[prevRes] # thisGuiAtoms = self.guiNmrAtomsFromNmrResidue[thisRes] # thisGroup = self.guiNmrResidues[prevRes] # # if (prevRes.nextNmrResidue and prevRes.nextNmrResidue is thisRes) and not thisGroup.connected: # and connectsNeeded: # # connect from this 'N' to the previous 'C' # thisGroup.connected = self._addConnectingLineToGroup(self.guiNmrResidues[prevRes], # prevGuiAtoms['C'], thisGuiAtoms['N'], # self._lineColour, self._lineConnectWidth, # lineList=self.connectingLines, # lineId=thisRes, # zValue=-3) # except: # pass #========================================================================================== def _addGroupResiduePredictions(self, guiResidueGroup: GuiNmrResidueGroup, nmrResidue: NmrResidue, caAtom: GuiNmrAtom): """Gets predictions for residue type based on BMRB statistics and determines label positions based on caAtom position. """ label = guiResidueGroup.nmrResidue.id if self._module._chemicalShiftList: predictions = list(set(getNmrResiduePrediction(nmrResidue, self._module._chemicalShiftList))) predictions.sort(key=lambda a: float(a[1][:-1]), reverse=True) if predictions: label += '\n\n' + '\n'.join([(prediction[0] + ' ' + prediction[1]) for prediction in predictions]) guiResidueGroup.nmrResidueLabel.setText(label) def _updateGroupResiduePredictions(self, showPredictions): """Update predictions for residue type based on BMRB statistics and determines label positions based on caAtom position. """ for guiRes in self.guiNmrResidues.values(): self._updateGroupResiduePrediction(guiRes, showPredictions) def _updateGroupResiduePrediction(self, guiResidue, showPredictions): """Update predictions for residue type based on BMRB statistics and determines label positions based on caAtom position. """ label = guiResidue.nmrResidue.id if self._module._chemicalShiftList and showPredictions: predictions = list(set(getNmrResiduePrediction(guiResidue.nmrResidue, self._module._chemicalShiftList))) predictions.sort(key=lambda a: float(a[1][:-1]), reverse=True) if predictions: label += '\n\n' + '\n'.join([(prediction[0] + ' ' + prediction[1]) for prediction in predictions]) guiResidue.nmrResidueLabel.setText(label) #==========================================================================================
[docs] def updateMainChainPositions(self, nmrChainId): """Update the positions of the group in the scene. May need to set vertical positions when more groups are allowed """ if nmrChainId not in self.nmrChains: return # get the list of nmrResidues in the required nmrChain referenced by nmrChainId # mainNmrResidues = self.nmrChains[nmrChainId] #[resPair[0] for resPair in self.nmrChains[nmrChainId]] mainNmrResidues = [nmrResidue for nmrResidue in self.nmrChains[nmrChainId] if nmrResidue.nmrChain.pid == nmrChainId and not nmrResidue._flaggedForDelete] for ii, nmrResidue in enumerate(mainNmrResidues): # nmrResidue, guiAtoms = item # guiAtoms = self.guiNmrAtomsFromNmrResidue[nmrResidue] if nmrResidue in self.guiNmrResidues: guiItem = self.guiNmrResidues[nmrResidue] guiItem.setPos(ii * self.atomSpacing * 3.0, 0.0)
[docs] def updateConnectedChainPositions(self): """Update the positions of the groups in the scene. """ # update crossChainResidue positions for res in self.guiGhostNmrResidues.values(): if res.crossChainResidue and res.crossChainResidue in self.guiNmrResidues: link = self.guiNmrResidues[res.crossChainResidue] count = res.crossChainCount newPosx = link.x() newPosy = link.y() res.setPos(newPosx + (count * 0.5 - 1.0) * self.atomSpacing, newPosy + (count * 2.5 + 5.0) * self.atomSpacing)
#========================================================================================== def _addAllPeakAssignments(self, nmrChainId): """Add all the peak assignments to the scene. """ if self._SGwidget.checkBoxes['peakAssignments']['widget'].isChecked(): # # create a set of sets ordered by spectra for active lines # self.LOCALinterResidueAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALinterChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALcrossChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # mainNmrResidues = self.nmrChain.mainNmrResidues # get the list of nmrResidues in the required nmrChain referenced by nmrChainId mainNmrResidues = self.nmrChains[nmrChainId] if nmrChainId in self.nmrChains else [] #[resPair[0] for resPair in self.nmrChains[nmrChainId]] for nmrResidue in mainNmrResidues: # guiRes = self.guiNmrAtomsFromNmrResidue[nmrResidue] # add the internally connected Lines internalAssignments, interChainAssignments, crossChainAssignments = self._getPeakAssignmentsForResidue(nmrResidue) self._addPeakAssignmentLinesToGroup(internalAssignments, self.assignmentLines) self._addPeakAssignmentLinesToGroup(interChainAssignments, self.assignmentLines) # add assignment lines and create ghost nmrResidues if required self._addPeakAssignmentLinesToAdjacentGroup(nmrResidue, crossChainAssignments, self.assignmentLines, self.connectingLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterResidueAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterChainAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToAdjacentGroup(self._module.nmrChain, self.LOCALcrossChainAtomPairing, # self.assignmentLines, self.connectingLines) #========================================================================================== def _addPeakAssignmentLinesToGroup(self, assignments, lineList): """Add the local peak assignments to each guiNmrResidue. """ for specAssignments in assignments.values(): for nmrAtomPair in specAssignments: guiNmrAtomPair = (self.guiNmrAtoms.get(nmrAtomPair[0]), self.guiNmrAtoms.get(nmrAtomPair[1]), nmrAtomPair[2] ) # skip if not defined if None in guiNmrAtomPair: continue # get the peak and the spectrum peak = guiNmrAtomPair[2] spectrum = peak.peakList.spectrum displacement = guiNmrAtomPair[0].getConnectedList(guiNmrAtomPair[1]) # add the internal line to the guiNmrResidueGroup, should now move when group is moved guiNmrResidue = self.guiNmrResidues[guiNmrAtomPair[0].nmrAtom.nmrResidue] self._addConnectingLineToGroup(guiNmrResidue, guiNmrAtomPair[0], guiNmrAtomPair[1], spectrum.positiveContourColour, self._lineWidth, displacement=displacement, peak=peak, lineList=lineList, lineId=peak) # update displacements for both guiNmrAtoms guiNmrAtomPair[0].addConnectedList(guiNmrAtomPair[1]) guiNmrAtomPair[1].addConnectedList(guiNmrAtomPair[0]) def _addPeakAssignmentLinesToAdjacentGroup(self, nmrResidue, assignments, peaklineList, connectingLineList): """Add the peak assignments to nmrResidues in the same chain. """ for specAssignments in assignments.values(): for nmrAtomPair in specAssignments: guiNmrAtomPair = (self.guiNmrAtoms.get(nmrAtomPair[0]), self.guiNmrAtoms.get(nmrAtomPair[1]), nmrAtomPair[2] ) # get the peak and the spectrum peak = guiNmrAtomPair[2] spectrum = peak.peakList.spectrum if guiNmrAtomPair[0] is None and guiNmrAtomPair[1] is None: continue if guiNmrAtomPair[0] is None: if nmrAtomPair[1].nmrResidue.nmrChain is not nmrResidue.nmrChain: continue self._addGhostResidue(nmrAtomPair[0].nmrResidue, # guiNmrAtomPair[1], nmrAtomPair[1].nmrResidue, # nmrAtomPair[0].name, # nmrAtomPair[1].name, # True, lineList=connectingLineList, residueAtoms=self._defaultResidueAtoms) guiNmrAtomPair = (self.guiNmrAtoms.get(nmrAtomPair[0]), self.guiNmrAtoms.get(nmrAtomPair[1]), nmrAtomPair[2] ) if None not in guiNmrAtomPair: group = self.guiNmrResidues[nmrAtomPair[1].nmrResidue] displacement = guiNmrAtomPair[1].getConnectedList(guiNmrAtomPair[0]) self._addConnectingLineToGroup(group, guiNmrAtomPair[1], guiNmrAtomPair[0], spectrum.positiveContourColour, self._lineWidth, displacement=displacement, peak=peak, lineList=peaklineList, lineId=nmrResidue) # NOTE:ED - this should be in _addConnectingLineToGroup guiNmrAtomPair[0].addConnectedList(guiNmrAtomPair[1]) guiNmrAtomPair[1].addConnectedList(guiNmrAtomPair[0]) elif guiNmrAtomPair[1] is None: if nmrAtomPair[0].nmrResidue.nmrChain is not nmrResidue.nmrChain: continue self._addGhostResidue(nmrAtomPair[1].nmrResidue, # guiNmrAtomPair[0], nmrAtomPair[0].nmrResidue, # nmrAtomPair[1].name, # nmrAtomPair[0].name, # True, lineList=connectingLineList, residueAtoms=self._defaultResidueAtoms) guiNmrAtomPair = (self.guiNmrAtoms.get(nmrAtomPair[0]), self.guiNmrAtoms.get(nmrAtomPair[1]), nmrAtomPair[2] ) if None not in guiNmrAtomPair: group = self.guiNmrResidues[nmrAtomPair[0].nmrResidue] displacement = guiNmrAtomPair[0].getConnectedList(guiNmrAtomPair[1]) self._addConnectingLineToGroup(group, guiNmrAtomPair[0], guiNmrAtomPair[1], spectrum.positiveContourColour, self._lineWidth, displacement=displacement, peak=peak, lineList=peaklineList, lineId=nmrResidue) guiNmrAtomPair[0].addConnectedList(guiNmrAtomPair[1]) guiNmrAtomPair[1].addConnectedList(guiNmrAtomPair[0]) else: if nmrAtomPair[0].nmrResidue.nmrChain is nmrResidue.nmrChain: group = self.guiNmrResidues[nmrAtomPair[0].nmrResidue] displacement = guiNmrAtomPair[0].getConnectedList(guiNmrAtomPair[1]) self._addConnectingLineToGroup(group, guiNmrAtomPair[0], guiNmrAtomPair[1], spectrum.positiveContourColour, self._lineWidth, displacement=displacement, peak=peak, lineList=peaklineList, lineId=nmrResidue) elif nmrAtomPair[1].nmrResidue.nmrChain is nmrResidue.nmrChain: group = self.guiNmrResidues[nmrAtomPair[1].nmrResidue] displacement = guiNmrAtomPair[1].getConnectedList(guiNmrAtomPair[0]) self._addConnectingLineToGroup(group, guiNmrAtomPair[1], guiNmrAtomPair[0], spectrum.positiveContourColour, self._lineWidth, displacement=displacement, peak=peak, lineList=peaklineList, lineId=nmrResidue) else: continue if None not in guiNmrAtomPair: guiNmrAtomPair[0].addConnectedList(guiNmrAtomPair[1]) guiNmrAtomPair[1].addConnectedList(guiNmrAtomPair[0]) def _getPeakAssignmentsForResidue(self, nmrResidue, nmrAtomIncludeList=None): """Get the list of peak assignments from the nmrAtoms interResidueAtomPairing is the linking within the same nmrResidue interChainAtomPairing is the linking within the same chain but to different nmrResidues crossChainAtomPairing is the linking to different chains """ # create a set of sets ordered by spectra _keys = self._module.magnetisationTransfers.keys() interResidueAtomPairing = {spec: set() for spec in _keys} interChainAtomPairing = {spec: set() for spec in _keys} crossChainAtomPairing = {spec: set() for spec in _keys} # emptyAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) nmrChain = nmrResidue.nmrChain assignments = [(assignment, peak, peak.peakList.spectrum) for nmrAtom in nmrResidue.nmrAtoms if not (nmrAtom._flaggedForDelete or nmrAtom.isDeleted) for peak in nmrAtom.assignedPeaks if not (peak._flaggedForDelete or peak.isDeleted) for assignment in peak.assignments ] for assignment, peak, spec in assignments: # for nmrAtom in nmrResidue.nmrAtoms: # # if nmrAtom._flaggedForDelete or nmrAtom.isDeleted: # continue # # for peak in nmrAtom.assignedPeaks: # # # ignore peaks that are due for delete (can probably also use the notifier list) # if peak._flaggedForDelete or peak.isDeleted: # continue # # spec = peak.peakList.spectrum # for assignment in peak.assignments: # find the mainNmrResidue for -1 and +1 connections newCon = list(assignment) for conNum in range(len(assignment)): nmrResCon = assignment[conNum] and assignment[conNum].nmrResidue if not nmrResCon: continue # assignments could be None if nmrResCon.relativeOffset == -1: # and inCon[conNum].nmrResidue.nmrChain.isConnected: # this is a minus residue so find connected, have to traverse to the previousNmrResidue # will it always exist? conName = assignment[conNum].name preN = nmrResCon.mainNmrResidue.previousNmrResidue if preN: for preNAtom in preN.nmrAtoms: if preNAtom.name == conName: newCon[conNum] = preNAtom break # newConSwap = [nmrA for nmrA in preN.nmrAtoms if nmrA.name == conName] # if newConSwap: # newCon[conNum] = newConSwap[0] else: newCon[conNum] = None # not connected so skip elif nmrResCon.relativeOffset == +1: # and inCon[conNum].nmrResidue.nmrChain.isConnected: # this is a plus residue so find connected, have to traverse to the nextNmrResidue # will it always exist? conName = assignment[conNum].name preN = nmrResCon.mainNmrResidue.nextNmrResidue if preN: for preNAtom in preN.nmrAtoms: if preNAtom.name == conName: newCon[conNum] = preNAtom break # newConSwap = [nmrA for nmrA in preN.nmrAtoms if nmrA.name == conName] # if newConSwap: # newCon[conNum] = newConSwap[0] else: newCon[conNum] = None # not connected so skip assignment = newCon # only get the assignments a-b if a and b are defined in the spectrum magnetisationTransfers list for mag in self._module.magnetisationTransfers[spec]: nmrAtom0 = assignment[mag[0] - 1] nmrAtom1 = assignment[mag[1] - 1] nmrAtom0 = nmrAtom0 if nmrAtom0 and not (nmrAtom0.isDeleted or nmrAtom0._flaggedForDelete) else None nmrAtom1 = nmrAtom1 if nmrAtom1 and not (nmrAtom1.isDeleted or nmrAtom1._flaggedForDelete) else None if not None in (nmrAtom0, nmrAtom1): # ignore nmrAtoms that are not in the include list (if specified) if nmrAtomIncludeList is not None and not (nmrAtom0 in nmrAtomIncludeList or nmrAtom1 in nmrAtomIncludeList): continue if (nmrAtom0.nmrResidue is nmrResidue) and (nmrAtom1.nmrResidue is nmrResidue): # interResidueAtomPairing if (nmrAtom1, nmrAtom0, peak) not in interResidueAtomPairing[spec]: interResidueAtomPairing[spec].add((nmrAtom0, nmrAtom1, peak)) elif (nmrAtom0.nmrResidue.nmrChain == nmrChain) and (nmrAtom1.nmrResidue.nmrChain == nmrChain): # connections within the same chain if (nmrAtom1, nmrAtom0, peak) not in interChainAtomPairing[spec]: interChainAtomPairing[spec].add((nmrAtom0, nmrAtom1, peak)) # elif (nmrAtom0.nmrResidue.nmrChain is nmrChain) and (nmrAtom1.nmrResidue.nmrChain is not nmrChain): else: # connections to a dif if (nmrAtom1, nmrAtom0, peak) not in crossChainAtomPairing[spec]: crossChainAtomPairing[spec].add((nmrAtom0, nmrAtom1, peak)) return interResidueAtomPairing, interChainAtomPairing, crossChainAtomPairing # return emptyAtomPairing, emptyAtomPairing, crossChainAtomPairing #========================================================================================== # spectrum update def _removeLinesFromScene(self, lineDist): """Remove all the lines in the group from the scene. """ for lineList in lineDist.values(): for line in lineList: if line in self._scene.items(): self._scene.removeItem(line) lineDist.clear()
[docs] def removeAssignmentLinesFromScene(self): """Remove all the peakLines from the scene. """ self._removeLinesFromScene(self.assignmentLines)
[docs] def removeConnectionLinesFromScene(self): """Remove all the connection from the scene. """ self._removeLinesFromScene(self.connectingLines)
[docs] def clearAllGuiNmrAtoms(self): """clear the displacements in the nmrAtoms. """ # clear the displacement values but keep the dict connections for guiAtom in self.guiNmrAtoms.values(): guiAtom.clearConnectedList()
[docs] def rebuildPeakAssignments(self): """Rebuild all the peak assignments in the display after changing the number of spectra. """ # remove all previous assignment lines and reset the dict self.removeAssignmentLinesFromScene() self.clearAllGuiNmrAtoms() for nmrChainId in self.nmrChains.keys(): self._addAllPeakAssignments(nmrChainId) # update the endpoints self.updateEndPoints(self.assignmentLines)
[docs] def updateEndPoints(self, lineDict): """Update the end points from the dict. """ for lineList in lineDict.values(): for line in lineList: try: line.updateEndPoints() except: pass
[docs] def updateAssignmentLines(self): """Update the endpoints of the assignment lines. """ self.updateEndPoints(self.assignmentLines)
[docs] def updateConnectionLines(self): """Update the endpoints of the connection lines. """ self.updateEndPoints(self.connectingLines)
[docs] def updateGuiResiduePositions(self, nmrChainId, updateMainChain=True, updateConnectedChains=True): """Update the positions of the residues and connected residues in other chains if required. """ if updateMainChain: # update the group positions self.updateMainChainPositions(nmrChainId) if updateConnectedChains: # update crossChainResidue positions self.updateConnectedChainPositions() # update the endpoints self.updateConnectionLines() self.updateAssignmentLines()
#==========================================================================================
[docs] def getAssignmentLinesFromPeaks(self, peaks): """Get the list of assignment lines attached o the given peaks. """
def _addAdjacentResiduesToSet(self, nmrResidue, residueSet): """Add the adjacent nmrResidues into the set. """ residueSet.add(nmrResidue) nmr = nmrResidue.previousNmrResidue if nmr and nmr.mainNmrResidue: residueSet.add(nmr.mainNmrResidue) nmr = nmrResidue.nextNmrResidue if nmr and nmr.mainNmrResidue: residueSet.add(nmr.mainNmrResidue)
[docs] def rebuildPeakLines(self, peaks, rebuildPeakLines=False, makeListFromPeak=False): """Clear all lines on the display associated with peak. """ # find the current lines associated with the notified peak (or list of peaks) peaks = makeIterableList(peaks) # make list of peakLines attached to these peaks peakLines = [peakLine for peakLineList in self.assignmentLines.values() for peakLine in peakLineList if peakLine._peak in peaks] guiNmrAtomSet = set() nmrResidueSet = set() if not makeListFromPeak: # make a list of all the guiNmrAtoms/nmrResidues that are associated with the peak for peakLine in peakLines: # current associated guiNmrAtoms guiNmrAtomSet.add(peakLine.guiAtom1) guiNmrAtomSet.add(peakLine.guiAtom2) # current associated nmrResidues and their previous/nextNmrResidues self._addAdjacentResiduesToSet(peakLine.guiAtom1.nmrAtom.nmrResidue, nmrResidueSet) self._addAdjacentResiduesToSet(peakLine.guiAtom2.nmrAtom.nmrResidue, nmrResidueSet) else: # make a new list for creating a peak; necessary for undo of delete peak as the assignedNmrAtom list exists assignmentAtoms = set([nmrAtom for peak in peaks for assignment in peak.assignments for nmrAtom in assignment if nmrAtom in self.guiNmrAtoms]) for nmrAtom in assignmentAtoms: guiNmrAtomSet.add(self.guiNmrAtoms[nmrAtom]) self._addAdjacentResiduesToSet(nmrAtom.nmrResidue, nmrResidueSet) for guiAtom in guiNmrAtomSet: for peakLineList in self.assignmentLines.values(): peakLines = [peakLine for peakLine in peakLineList if peakLine.guiAtom1 is guiAtom or peakLine.guiAtom2 is guiAtom] # remove all graphic lines for peakLine in peakLines: peakLineList.remove(peakLine) if peakLine in self._scene.items(): self._scene.removeItem(peakLine) # clear connectivity list of guiNmrAtoms, but don't delete guiAtom.clearConnectedList() if rebuildPeakLines: # now rebuild for the new peak values # assumes that the peakAssignments have changed - possibly use different notifier if self._SGwidget.checkBoxes['peakAssignments']['widget'].isChecked(): nmrAtomIncludeList = tuple(guiAtom.nmrAtom for guiAtom in guiNmrAtomSet) # # create a set of sets ordered by spectra for active lines # self.LOCALinterResidueAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALinterChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALcrossChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) for nmrResidue in nmrResidueSet: # only process residues in the current visible chain if nmrResidue.nmrChain is self._module.nmrChain: # add the internally connected Lines internalAssignments, interChainAssignments, crossChainAssignments = \ self._getPeakAssignmentsForResidue(nmrResidue, nmrAtomIncludeList=nmrAtomIncludeList) self._addPeakAssignmentLinesToGroup(internalAssignments, self.assignmentLines) self._addPeakAssignmentLinesToGroup(interChainAssignments, self.assignmentLines) self._addPeakAssignmentLinesToAdjacentGroup(nmrResidue, crossChainAssignments, self.assignmentLines, self.connectingLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterResidueAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterChainAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToAdjacentGroup(self._module.nmrChain, self.LOCALcrossChainAtomPairing, # self.assignmentLines, self.connectingLines) first = next(iter(nmrResidueSet or []), None) thisId = first.nmrChain.pid if first else 'noChainId' self.updateGuiResiduePositions(thisId, updateMainChain=True, updateConnectedChains=True)
#========================================================================================== def _addNmrAtomToGuiResidues(self, nmrAtom, atomSpacing=None): """Update the guiNmrAtoms for a newly created/undeleted nmrAtom. Assumes that the nmrAtom/guiNmrAtom does not exist """ nmrResidue = nmrAtom.nmrResidue guiAtoms = {} if atomSpacing: self.atomSpacing = atomSpacing atomNames = [nmrAtom.name for nmrAtom in nmrResidue.nmrAtoms] # residueAtoms = DEFAULT_RESIDUE_ATOMS.copy() residueAtoms = self._defaultResidueAtoms.copy() for k, v in residueAtoms.items(): # if k in atomNames: fetchedNmrAtom = nmrResidue.getNmrAtom(k) # else: # fetchedNmrAtom = None if fetchedNmrAtom is nmrAtom: guiAtoms[k] = self._createGuiNmrAtom(k, v, nmrAtom) # ii = self.getIndexNmrResidue(nmrResidue) # if ii is not None: # res, oldGuiAtoms = self._getNmrResiduePair(ii) # self._setNmrResiduePair(ii, res, oldGuiAtoms.update(guiAtoms)) if nmrResidue in self.guiNmrResidues: guiResidueGroup = self.guiNmrResidues[nmrResidue] # add the guiAtoms to the group and set the reverse link for item in guiAtoms.values(): guiResidueGroup.addToGroup(item) item.guiNmrResidueGroup = guiResidueGroup
[docs] def createNmrAtoms(self, nmrAtoms): """Create new peak lines associated with the created/undeleted nmrAtoms. """ nmrAtoms = makeIterableList(nmrAtoms) peaks = [peak for nmrAtom in nmrAtoms for peak in nmrAtom.assignedPeaks] for nmrAtom in nmrAtoms: if nmrAtom not in self.guiNmrAtoms: # add the new nmrAtoms self._addNmrAtomToGuiResidues(nmrAtom) self.rebuildPeakLines(peaks, rebuildPeakLines=True, makeListFromPeak=True)
def _searchPeakLines(self, nmrAtoms, includeDeleted=False): """Return a list of the peakLines containing one of the nmrAtoms in the list. """ peakLines = [] for lineList in self.assignmentLines.values(): for line in lineList: nmrAtom = line.guiAtom1.nmrAtom if line.guiAtom1 else None if nmrAtom in nmrAtoms and (includeDeleted or not (nmrAtom.isDeleted or nmrAtom._flaggedForDelete)): peakLines.append(line) nmrAtom = line.guiAtom2.nmrAtom if line.guiAtom2 else None if nmrAtom in nmrAtoms and (includeDeleted or not (nmrAtom.isDeleted or nmrAtom._flaggedForDelete)): peakLines.append(line) return peakLines
[docs] def deleteNmrAtoms(self, nmrAtoms): """Delete peak lines associated with the deleted nmrAtoms. """ nmrAtoms = makeIterableList(nmrAtoms) peakLines = self._searchPeakLines(nmrAtoms, includeDeleted=True) peaks = [peakLine._peak for peakLine in peakLines] self.rebuildPeakLines(peaks, rebuildPeakLines=True)
#==========================================================================================
[docs] def rebuildNmrResidues(self, nmrResidues): """Rebuild the peaks of a specified nmrResidue. """ # now rebuild for the new peak values # assumes that the peakAssignments have changed - possibly use different notifier nmrResidues = makeIterableList(nmrResidues) nmrAtomIncludeList = tuple(nmrAtom for nmrResidue in nmrResidues for nmrAtom in nmrResidue.nmrAtoms) guiNmrAtomSet = set([self.guiNmrAtoms[nmrAtom] for nmrAtom in nmrAtomIncludeList if nmrAtom in self.guiNmrAtoms]) for guiAtom in guiNmrAtomSet: for peakLineList in self.assignmentLines.values(): peakLines = [peakLine for peakLine in peakLineList if peakLine.guiAtom1 is guiAtom or peakLine.guiAtom2 is guiAtom] # remove all graphic lines for peakLine in peakLines: peakLineList.remove(peakLine) if peakLine in self._scene.items(): self._scene.removeItem(peakLine) # clear connectivity list of guiNmrAtoms guiAtom.clearConnectedList() if self._SGwidget.checkBoxes['peakAssignments']['widget'].isChecked(): # # create a set of sets ordered by spectra for active lines # self.LOCALinterResidueAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALinterChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALcrossChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) for nmrResidue in nmrResidues: # only process residues in the current visible chain if nmrResidue is nmrResidue.mainNmrResidue and nmrResidue.nmrChain is self._module.nmrChain: # add the internally connected Lines internalAssignments, interChainAssignments, crossChainAssignments = self._getPeakAssignmentsForResidue(nmrResidue, nmrAtomIncludeList=nmrAtomIncludeList) self._addPeakAssignmentLinesToGroup(internalAssignments, self.assignmentLines) self._addPeakAssignmentLinesToGroup(interChainAssignments, self.assignmentLines) self._addPeakAssignmentLinesToAdjacentGroup(nmrResidue, crossChainAssignments, self.assignmentLines, self.connectingLines) if nmrResidue.nextNmrResidue and nmrResidue.nextNmrResidue.mainNmrResidue: nextNmrResidue = nmrResidue.nextNmrResidue.mainNmrResidue # only process residues in the current visible chain # add the internally connected Lines internalAssignments, interChainAssignments, crossChainAssignments = self._getPeakAssignmentsForResidue(nextNmrResidue, nmrAtomIncludeList=nmrAtomIncludeList) self._addPeakAssignmentLinesToGroup(internalAssignments, self.assignmentLines) self._addPeakAssignmentLinesToGroup(interChainAssignments, self.assignmentLines) self._addPeakAssignmentLinesToAdjacentGroup(nextNmrResidue, crossChainAssignments, self.assignmentLines, self.connectingLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterResidueAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterChainAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToAdjacentGroup(self._module.nmrChain, self.LOCALcrossChainAtomPairing, # self.assignmentLines, self.connectingLines) self.updateGuiResiduePositions(nmrResidues[0].nmrChain.pid, updateMainChain=True, updateConnectedChains=True)
#========================================================================================== #========================================================================================== #========================================================================================== #========================================================================================== # Sequence Graph Main Module #========================================================================================== LINKTOPULLDOWNCLASS = 'linkToPulldownClass'
[docs]class SequenceGraphModule(CcpnModule): """ A module for the display of stretches of sequentially linked and assigned stretches of NmrResidues. """ className = 'SequenceGraph' includeSettingsWidget = True maxSettingsState = 2 # states are defined as: 0: invisible, 1: both visible, 2: only settings visible settingsPosition = 'left' # consistent with nmrResidueTable - move to generic class later activePulldownClass = NmrChain def __init__(self, mainWindow=None, name='Sequence Graph', nmrChain=None): CcpnModule.__init__(self, mainWindow=mainWindow, name=name) # Derive application, project, and current from mainWindow self.mainWindow = mainWindow if self.mainWindow: self.application = mainWindow.application self.project = mainWindow.application.project self.current = mainWindow.application.current ###self.setMode('fragment') # cannot be moved up! else: self.application = None self.project = None self.current = None self.splitter = Splitter(self.mainWidget, horizontal=False) self._sequenceWidgetFrame = Frame(None, setLayout=True) self.mainWidget.getLayout().addWidget(self.splitter, 1, 0, 1, 1) self.thisSequenceWidget = SequenceWidget(moduleParent=self, parent=self._sequenceWidgetFrame, mainWindow=mainWindow, chains=self.project.chains) # must match the chain selection below self.colours = getColours() self._lineColour = self.colours[SEQUENCEGRAPHMODULE_LINE] self._textColour = self.colours[SEQUENCEGRAPHMODULE_TEXT] ###frame = Frame(parent=self.mainWidget) self._sequenceGraphScrollArea = QtWidgets.QScrollArea() self._sequenceGraphScrollArea.setWidgetResizable(True) self._sequenceGraphScrollArea.setMinimumHeight(80) self.splitter.addWidget(self._sequenceGraphScrollArea) self.splitter.addWidget(self._sequenceWidgetFrame) self.splitter.setStretchFactor(0, 5) self.splitter.setChildrenCollapsible(False) # add the settings widgets defined from the following orderedDict - test for refactored settingsDict = OrderedDict((('SpectrumDisplays', {'label' : '', 'tipText' : '', 'callBack': None, #self.restraintTablePulldown, 'enabled' : True, '_init' : None, 'type' : SpectrumDisplaySelectionWidget, 'kwds' : {'texts' : [], 'displayText': [], 'defaults' : [], 'objectName' : 'SpectrumDisplaysSelection'}, #objectName is used to save to layout }), ('ChainSelection', {'label' : '', 'tipText' : '', 'callBack': self.showChainsChanged, 'enabled' : True, '_init' : None, 'type' : ChainSelectionWidget, 'kwds' : {'texts' : [ALL], 'displayText': [], 'defaults' : [ALL], 'objectName' : 'ChainSelection'}, }), ('ChemicalShiftList', {'label' : 'ChemicalShiftListSelection', 'tipText' : '', 'callBack': self.showShiftListPulldown, 'enabled' : True, '_init' : None, 'type' : ChemicalShiftListPulldown, 'kwds' : {'showSelectName': False, 'labelText' : 'Select ChemicalShiftList', 'hAlign' :'left'}, }), ('showPredictions', {'label' : 'Show Predictions', 'tipText' : 'Show predictions and calculate predicted sequences.', 'callBack': self.showPredictions, 'enabled' : True, 'checked' : True, '_init' : None, }), ('peakAssignments', {'label' : 'Show peak assignments', 'tipText' : 'Show peak assignments on display coloured by positiveContourColour.', 'callBack': self.showNmrChainFromPulldown, 'enabled' : True, 'checked' : True, '_init' : None, }), ('treeView', {'label' : 'Tree view', 'tipText' : 'Show peak assignments as a tree below the main backbone.', 'callBack': None, #self._updateShowTreeAssignments, 'enabled' : False, 'checked' : False, '_init' : None, #self._updateShowTreeAssignments, }), ('showSideChain', {'label' : 'Show side chain', 'tipText' : 'Show side chain atoms and connections above the main chain.', 'callBack': None, #self.showNmrChainFromPulldown, 'enabled' : False, 'checked' : False, '_init' : None, }), ('sequentialStrips', {'label' : 'Show sequential strips', 'tipText' : 'Show nmrResidue in all strips.', 'callBack': None, #self.showNmrChainFromPulldown, 'enabled' : True, 'checked' : False, '_init' : None, }), ('markPositions', {'label' : 'Mark positions', 'tipText' : 'Mark positions in all strips.', 'callBack': None, #self.showNmrChainFromPulldown, 'enabled' : True, 'checked' : True, '_init' : None, }), ('autoClearMarks', {'label' : 'Auto clear marks', 'tipText' : 'Auto clear all previous marks', 'callBack': None, 'enabled' : True, 'checked' : True, '_init' : None, }), )) if self.activePulldownClass: settingsDict.update(OrderedDict(((LINKTOPULLDOWNCLASS, {'label' : 'Link to current %s' % self.activePulldownClass.className, 'tipText' : 'Set/update current %s when selecting from pulldown' % self.activePulldownClass.className, 'callBack': None, 'enabled' : True, 'checked' : True, '_init' : None, }), ))) self._SGwidget = ModuleSettingsWidget(parent=self.settingsWidget, mainWindow=self.mainWindow, settingsDict=settingsDict, grid=(0, 0)) # NOTE:ED - need to clean this up self._SGwidget.chainsWidget = self._SGwidget.checkBoxes['ChainSelection']['widget'] # self._SGwidget.chainsWidget.listWidget.changed.connect(self.showChainsChanged) self._SGwidget.displaysWidget = self._SGwidget.checkBoxes['SpectrumDisplays']['widget'] self.initialiseScene() self.residueCount = 0 self.defineAtoms() self.nmrResidueList = NmrResidueList(self.mainWindow, self._SGwidget, self._lineColour, self._textColour, self.atomSpacing, self.lineSpacing, self.lineWidth, self.lineConnectWidth, self.scene, self, self.DEFAULT_RESIDUE_ATOMS, self.ATOM_POSITION_DICT) self._deleteStore = {} # seems to need nested frames to enforce the sizeConstraint self._MWwidgetFrame2 = Frame(self.mainWidget, setLayout=True, grid=(0, 0), vAlign='top', hAlign='left', hPolicy='ignored', vPolicy='minimum') self._MWwidgetFrame = Frame(self._MWwidgetFrame2, setLayout=True, grid=(0, 0), vAlign='top', hAlign='left', ) self._MWwidgetFrame.getLayout().setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize) self._MWwidget = Frame(self._MWwidgetFrame, setLayout=True, grid=(0, 0), vAlign='top', hAlign='left', hPolicy='fixed', vPolicy='fixed') _col = 0 self.nmrChainPulldown = NmrChainPulldown(self._MWwidget, self.mainWindow, grid=(0, _col), gridSpan=(1, 1), showSelectName=True, # fixedWidths=(colwidth, colwidth, colwidth), callback=self.showNmrChainFromPulldown) # self.refreshCheckBox = CheckBoxCompoundWidget(self._MWwidget, # labelText='Auto refresh NmrChain:', # checked=True, # fixedWidths=(colwidth, 15), # orientation='right', hAlign='left', # tipText='Update display when current.nmrChain changes', # grid=(0, 1), gridSpan=(1, 1)) _col += 1 _height = getFontHeight() Spacer(self._MWwidget, _height * 3, 5, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed, grid=(0, _col), gridSpan=(1, 1)) _col += 1 self.sequenceCheckBox = CheckBoxCompoundWidget(self._MWwidget, labelText='Show Sequence:', checked=True, # fixedWidths=(colwidth, 15), orientation='left', hAlign='left', tipText='Show chain sequences', callback=self._toggleSequence, grid=(0, _col), gridSpan=(1, 1)) _col += 1 self.nmrResiduesCheckBox = CheckBoxCompoundWidget(self._MWwidget, labelText='Show all NmrResidues:', checked=True, # fixedWidths=(colwidth, 15), orientation='left', hAlign='left', tipText='Show all the NmrResidues in the NmrChain', callback=self.showNmrChainFromPulldown, grid=(0, _col), gridSpan=(1, 1)) _col += 1 _minSize = max(24, _height * 1.25) # # put next to _MWidget so height can stretch # self._editingToolbarFrame = Frame(self._MWwidgetFrame, setLayout=True, # grid=(0, 1), vAlign='top', hAlign='left', # hPolicy='expanding', vPolicy='ignored') # self.editingToolbar = ToolBar(self._editingToolbarFrame, grid=(0, 0), gridSpan=(1, 1), hAlign='right', # iconSizes=(_minSize, _minSize), # ) self._MWwidget.setContentsMargins(5, 5, 5, 5) self.settingsWidget.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Minimum) # self.disconnectPreviousAction = self.editingToolbar.addAction("disconnectPrevious", self.disconnectPreviousNmrResidue) self.disconnectPreviousIcon = Icon('icons/disconnectPrevious') # self.disconnectPreviousAction.setIcon(self.disconnectPreviousIcon) # self.disconnectAction = self.editingToolbar.addAction("disconnect", self.disconnectNmrResidue) self.disconnectIcon = Icon('icons/disconnect') # self.disconnectAction.setIcon(self.disconnectIcon) # self.disconnectNextAction = self.editingToolbar.addAction("disconnectNext", self.disconnectNextNmrResidue) self.disconnectNextIcon = Icon('icons/disconnectNext') # self.disconnectNextAction.setIcon(self.disconnectNextIcon) # self.shiftListPulldown = ChemicalShiftListPulldown(self._MWwidget, self.mainWindow, grid=(1, 0), gridSpan=(1, 1), # showSelectName=True, # # fixedWidths=(colwidth, colwidth, colwidth), # callback=self.showShiftListPulldown) self.shiftListPulldown = self._SGwidget.checkBoxes['ChemicalShiftList']['widget'] self._chains = self.project.chains # this must match the sequence module init and the chains pulldown init self._chemicalShiftList = self.project.chemicalShiftLists[0] if self.project.chemicalShiftLists else None # add mouse handler for the QGraphicsLineItems self._preMouserelease = self.scene.mouseReleaseEvent self.scene.mouseReleaseEvent = self._sceneMouseRelease # calculate the connections between axes based on experiment types self._updateMagnetisationTransfers() # initialise notifiers self._registerNotifiers() self.selectSequence(nmrChain) def _sceneMouseRelease(self, event): """Add a mouse handler to popupa menu from the contained scene """ if event.button() == QtCore.Qt.RightButton: obj = self.scene.mouseGrabberItem() if obj: pos = QtGui.QCursor().pos() self._raiseContextMenu(obj, pos) self._preMouserelease(event) # def _checkLayoutInit(self): # """This is a hack so that the state changes when the layout loads # After the layout initialise, this function is removed # """ # self._updateShowTreeAssignments() # self.assignmentsTreeCheckBox.checkBox.stateChanged.disconnect(self._checkLayoutInit) def _maximise(self): """Maximise the attached table """ pass def _updateMagnetisationTransfers(self): """Generate the list that defines which couplings there are between the nmrAtoms attached to each peak. """ # self.magnetisationTransfers = OrderedDict() # for spec in self.project.spectra: # if not (spec.isDeleted or spec._flaggedForDelete): # self.magnetisationTransfers[spec] = {} # for mt in spec.magnetisationTransfers: # self.magnetisationTransfers[spec][mt] = set() self.magnetisationTransfers = {spec: {mt: set() for mt in spec.magnetisationTransfers} for spec in self.project.spectra if not (spec.isDeleted or spec._flaggedForDelete) }
[docs] @contextmanager def sceneBlocking(self): """Context manager to handle blocking, unblocking, resizing of the scene. """ with self.mainWidget.blockWidgetSignals(self.scrollContents, recursive=False, additionalWidgets=[self.scene]): yield # resize to the new items and spawns a repaint self.scene.setSceneRect(self.scene.itemsBoundingRect().adjusted(-30, -50, 30, 30)) self.scene.update()
def _updateSpectra(self, data=None): """Update list of current spectra and generate new magnetisationTransfer list """ if data: trigger = data[Notifier.TRIGGER] self._updateMagnetisationTransfers() if trigger in [Notifier.CREATE, Notifier.DELETE]: nmrChainPid = self.nmrChainPulldown.getText() if nmrChainPid: with self.sceneBlocking(): self.nmrResidueList.rebuildPeakAssignments()
[docs] def selectSequence(self, nmrChain=None): """Manually select a Sequence from the pullDown """ if nmrChain is None: # logger.warning('select: No Sequence selected') # raise ValueError('select: No Sequence selected') self.nmrChainPulldown.selectFirstItem() else: if not isinstance(nmrChain, NmrChain): logger.warning('select: Object is not of type Sequence') raise TypeError('select: Object is not of type Sequence') else: for widgetObj in self.nmrChainPulldown.textList: if nmrChain.pid == widgetObj: self.nmrChainPulldown.select(nmrChain.pid)
def _registerNotifiers(self): """Register the required notifiers """ self._peakNotifier = self.setNotifier(self.project, [Notifier.CHANGE, Notifier.CREATE, Notifier.DELETE], Peak.className, self._updatePeaks, onceOnly=True) # not required # self._nmrChainNotifier = self.setNotifier(self.project, # [Notifier.CHANGE, Notifier.CREATE, Notifier.DELETE], # NmrChain.className, # self._updateNmrChains, # onceOnly=True) self._nmrResidueNotifier = self.setNotifier(self.project, [Notifier.CREATE, Notifier.DELETE, Notifier.RENAME], NmrResidue.className, self._updateNmrResidues, onceOnly=True) self._nmrResidueChangeNotifier = self.setNotifier(self.project, [Notifier.CHANGE], NmrResidue.className, self._changeNmrResidues, onceOnly=True) self._nmrAtomNotifier = self.setNotifier(self.project, [Notifier.CHANGE, Notifier.CREATE, Notifier.DELETE], NmrAtom.className, self._updateNmrAtoms, onceOnly=True) # notifier to change the magnetisationTransfer list when new spectrum added self._spectrumListNotifier = self.setNotifier(self.project, [Notifier.CREATE, Notifier.DELETE], Spectrum.className, self._updateSpectra) self._currentNmrResidueNotifier = self.setNotifier(self.current, [Notifier.CURRENT], targetName=NmrResidue._pluralLinkName, callback=self._selectCurrentNmrResidues) # new notifier to respond to changing current nmrChain if self.activePulldownClass: self._setCurrentPulldown = Notifier(self.current, [Notifier.CURRENT], targetName=self.activePulldownClass._pluralLinkName, callback=self._selectCurrentPulldownClass) def _selectCurrentPulldownClass(self, data): """Respond to change in current activePulldownClass """ checkBox = self._SGwidget.getWidget(LINKTOPULLDOWNCLASS) if self.activePulldownClass and checkBox and checkBox.isChecked() and \ self.current.nmrChain and self.current.nmrChain != self.nmrChain: self.nmrChainPulldown.select(self.current.nmrChain.pid) def _repopulateModule(self): """CCPN Internal: Repopulate the required widgets in the module This is will be attached to GuiNotifiers """ self.showNmrChainFromPulldown() # def _updateModule(self, nmrChains=None): # """Update in response to change of current.nmrChains # """ # #if nmrChains is None or len(nmrChains)==0: return # nmrChain = self.current.nmrChain # if not nmrChain: # return # # if not self.refreshCheckBox.isChecked(): # return # # # select the chain from the pullDown - should automatically change the display # self.nmrChainPulldown.select(nmrChain.pid) # def setMode(self, mode): # if self.project.nmrChains: # self.editingToolbar.hide() # if mode == 'fragment': # self.editingToolbar.show() # #self.nmrChainPulldown.setData([c.pid for c in self.project.nmrChains]) # #self.nmrChainLabel.setText('NmrChain: ') # elif mode == 'Assigned - backbone': # pass # #self.nmrChainLabel.setText('Chain: ') # #self.nmrChainPulldown.setData([self.project.getByPid('NC:%s' % chain.shortName).pid for chain in self.project.chains if self.project.getByPid('NC:%s' % chain.shortName)]) # self.modePulldown.select(mode) # self.setNmrChainDisplay(self.nmrChainPulldown.getText()) # else: # logger.warning('No valid NmrChain is selected.') # def _addAdjacentResiduesToSet(self, nmrResidue, residueSet): # residueSet.add(nmrResidue) # nmr = nmrResidue.previousNmrResidue # if nmr: # nmr = nmr.mainNmrResidue # residueSet.add(nmr) # nmr = nmrResidue.nextNmrResidue # if nmr: # nmr = nmr.mainNmrResidue # residueSet.add(nmr) def _rebuildNmrResidues(self, nmrChainId, nmrResidues): """Rebuild the peaks of a specified nmrResidue. """ # now rebuild for the new peak values # assumes that the peakAssignments have changed - possibly use different notifier nmrResidues = makeIterableList(nmrResidues) nmrAtomIncludeList = tuple(nmrAtom for nmrResidue in nmrResidues for nmrAtom in nmrResidue.nmrAtoms) guiNmrAtomSet = set([self.nmrResidueList.guiNmrAtoms[nmrAtom] for nmrAtom in nmrAtomIncludeList]) for guiAtom in guiNmrAtomSet: for peakLineList in self.nmrResidueList.assignmentLines.values(): peakLines = [peakLine for peakLine in peakLineList if peakLine.guiAtom1 is guiAtom or peakLine.guiAtom2 is guiAtom] # remove all graphic lines for peakLine in peakLines: peakLineList.remove(peakLine) if peakLine in self.scene.items(): self.scene.removeItem(peakLine) # clear connectivity list of guiNmrAtoms guiAtom.clearConnectedList() if self._SGwidget.checkBoxes['peakAssignments']['widget'].isChecked(): # # create a set of sets ordered by spectra for active lines # self.LOCALinterResidueAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALinterChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) # self.LOCALcrossChainAtomPairing = OrderedDict((spec, set()) for spec in self._module.magnetisationTransfers.keys()) for nmrResidue in nmrResidues: # only process residues in the current visible chain if nmrResidue is nmrResidue.mainNmrResidue and nmrResidue.nmrChain is self.nmrChain: # add the internally connected Lines internalAssignments, interChainAssignments, crossChainAssignments = self.nmrResidueList._getPeakAssignmentsForResidue(nmrResidue, nmrAtomIncludeList=nmrAtomIncludeList) self.nmrResidueList._addPeakAssignmentLinesToGroup(internalAssignments, self.nmrResidueList.assignmentLines) self.nmrResidueList._addPeakAssignmentLinesToGroup(interChainAssignments, self.nmrResidueList.assignmentLines) self.nmrResidueList._addPeakAssignmentLinesToAdjacentGroup(nmrResidue, crossChainAssignments, self.nmrResidueList.assignmentLines, self.nmrResidueList.connectingLines) if nmrResidue.nextNmrResidue and nmrResidue.nextNmrResidue.mainNmrResidue: nextNmrResidue = nmrResidue.nextNmrResidue.mainNmrResidue # only process residues in the current visible chain # add the internally connected Lines internalAssignments, interChainAssignments, crossChainAssignments = self.nmrResidueList._getPeakAssignmentsForResidue(nextNmrResidue, nmrAtomIncludeList=nmrAtomIncludeList) self.nmrResidueList._addPeakAssignmentLinesToGroup(internalAssignments, self.nmrResidueList.assignmentLines) self.nmrResidueList._addPeakAssignmentLinesToGroup(interChainAssignments, self.nmrResidueList.assignmentLines) self.nmrResidueList._addPeakAssignmentLinesToAdjacentGroup(nextNmrResidue, crossChainAssignments, self.nmrResidueList.assignmentLines, self.nmrResidueList.connectingLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterResidueAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToGroup(self.LOCALinterChainAtomPairing, self.assignmentLines) # self._addPeakAssignmentLinesToAdjacentGroup(self._module.nmrChain, self.LOCALcrossChainAtomPairing, # self.assignmentLines, self.connectingLines) self.nmrResidueList.updateGuiResiduePositions(nmrChainId, updateMainChain=True, updateConnectedChains=True) def _updatePeaks(self, data): """Update the peaks in the display. """ peak = data[Notifier.OBJECT] trigger = data[Notifier.TRIGGER] with self.sceneBlocking(): if trigger == Notifier.DELETE: # print('>>>_updatePeaks delete', peak) self.nmrResidueList.rebuildPeakLines(peak, rebuildPeakLines=True) elif trigger == Notifier.CREATE: # print('>>>_updatePeaks create', peak) self.nmrResidueList.rebuildPeakLines(peak, rebuildPeakLines=True, makeListFromPeak=True) elif trigger == Notifier.CHANGE: # print('>>>_updatePeaks change', peak) self.nmrResidueList.rebuildPeakLines(peak, rebuildPeakLines=True, makeListFromPeak=True) # def _updateNmrChains(self, data): # """Update the nmrChains in the display. # """ # nmrChain = data[Notifier.OBJECT] # # # print('>>>_updateNmrChains', nmrChain) # trigger = data[Notifier.TRIGGER] # # # with self.sceneBlocking(): # # if trigger == Notifier.DELETE: # # print('>>>delete nmrChain - no action', nmrChain) # # # # elif trigger == Notifier.CREATE: # # print('>>>create nmrChain - no action', nmrChain) # # # # elif trigger == Notifier.CHANGE: # # print('>>>change nmrChain - no action', nmrChain) def _selectCurrentNmrResidues(self, data): """ Notifier Callback for selecting current nmrResidue """ objList = data[CallBack.OBJECT] nmrResidue = objList.nmrResidue if not self.nmrResiduesCheckBox.isChecked(): # redraw the nmrResidues if current is in the displayed chain and not already visible if nmrResidue.nmrChain == self.nmrChain and nmrResidue not in self.nmrResidueList.guiNmrResidues: # print('>>> change current.nmrResidue') self.showNmrChainFromPulldown(nmrResidue) # clear selections and reset selection boxes self.nmrResidueList.setNmrResidueSelection([nmrResidue]) def _updateNmrResidues(self, data): """Update the nmrResidues in the display. """ nmrResidue = data[Notifier.OBJECT] # print('>>>_updateNmrResidues', nmrResidue) trigger = data[Notifier.TRIGGER] showPredictions = self._SGwidget.checkBoxes['showPredictions']['widget'].isChecked() showSideChain = self._SGwidget.checkBoxes['showSideChain']['widget'].isChecked() with self.sceneBlocking(): if trigger == Notifier.DELETE: # print('>>>delete nmrResidue', nmrResidue) self._deleteNmrResidues(nmrResidue) elif trigger == Notifier.CREATE: # print('>>>create nmrResidue', nmrResidue) if not self._createNmrResidues(nmrResidue, showPredictions, showSideChain): # print('>>>error? redraw list') # self.setNmrChainDisplay(self.nmrChain) pass elif trigger == Notifier.RENAME: oldPid = data[Notifier.OLDPID] self._renameNmrResidue(nmrResidue, oldPid, showPredictions) # elif trigger == Notifier.CHANGE: # print('>>>change nmrResidue - no action', nmrResidue) # # elif trigger == Notifier.OBSERVE: # print('>>>observe nmrResidue - no action', nmrResidue) def _changeNmrResidues(self, data): """Update the nmrResidues in the display. """ nmrResidue = data[Notifier.OBJECT] try: with self.sceneBlocking(): showPredictions = self._SGwidget.checkBoxes['showPredictions']['widget'].isChecked() showSideChain = self._SGwidget.checkBoxes['showSideChain']['widget'].isChecked() if nmrResidue in self.nmrChain.nmrResidues and nmrResidue not in self.nmrResidueList.guiNmrResidues: # print('>>>change nmrResidue - create', nmrResidue) if not self._createNmrResidues(nmrResidue, showPredictions, showSideChain): # print('>>>error? redraw list') # self.setNmrChainDisplay(self.nmrChain) pass elif nmrResidue in self.nmrResidueList.guiNmrResidues and nmrResidue not in self.nmrChain.nmrResidues: # not in chain, but in residues as other chain self._deleteGuiNmrResidues(nmrResidue, showPredictions) # self._deleteNmrResidues(nmrResidue) else: # print('>>>change2 nmrResidue - create **** rename', nmrResidue) # this is the event that fires on a name change # self._deleteBadNmrResidues(nmrResidue) self._deleteNmrResidues(nmrResidue) if not self._createNmrResidues(nmrResidue, showPredictions, showSideChain): # print('>>>error? redraw list') # self.setNmrChainDisplay(self.nmrChain) pass except Exception as es: # strange error not traced yet, interesting, but not fatal if trapped - think I've found it getLogger().warning(str(es)) def _updateNmrAtoms(self, data): """Update the nmrAtoms in the display. """ # Done nmrAtom = data[Notifier.OBJECT] trigger = data[Notifier.TRIGGER] # only mainNmrResidues are shown on the screen with self.sceneBlocking(): if trigger == Notifier.DELETE: # print('>>>delete nmrAtom', nmrAtom) self.nmrResidueList.deleteNmrAtoms(nmrAtom) elif trigger == Notifier.CREATE: # print('>>>create nmrAtom', nmrAtom) self.nmrResidueList.createNmrAtoms(nmrAtom) def _renameNmrResidue(self, nmrResidue, oldPid: str, showPredictions): """Reset pid for NmrResidue and all offset NmrResidues """ with self.sceneBlocking(): if nmrResidue in self.nmrResidueList.guiNmrResidues: # self.nmrResidueList.guiNmrResidues[nmrResidue].nmrResidueLabel._update() self.nmrResidueList._updateGroupResiduePrediction(self.nmrResidueList.guiNmrResidues[nmrResidue], showPredictions) if nmrResidue in self.nmrResidueList.guiGhostNmrResidues: # self.nmrResidueList.guiGhostNmrResidues[nmrResidue].nmrResidueLabel._update() self.nmrResidueList._updateGroupResiduePrediction(self.nmrResidueList.guiGhostNmrResidues[nmrResidue], showPredictions) self.nmrResidueList.setNmrResidueSelection([self.current.nmrResidue]) # nmrChainPid = self.nmrChainPulldown.getText() # if self.project.getByPid(nmrChainPid): # # for nr in [nmrResidue] + list(nmrResidue.offsetNmrResidues): # for guiNmrResidueGroup in self.nmrResidueList.guiNmrResidues.values(): # if guiNmrResidueGroup.nmrResidue is nr: # guiNmrResidueGroup.nmrResidueLabel._update() def _createNmrResidues(self, nmrResidues, showPredictions=True, showSideChain=False): """Create new nmrResidues in the scene """ # print('>>>_createNmrResidues') # get the nmrResidue in the current selected chain nmrResidues = makeIterableList(nmrResidues) for nmrChainId in self.nmrResidueList.nmrChains.keys(): thisResList = [nmrResidue for nmrResidue in nmrResidues if nmrResidue.nmrChain.pid == nmrChainId] if thisResList: self._buildNmrResidues(nmrChainId, thisResList, showPredictions=showPredictions, showSideChain=showSideChain) return True def _deleteNmrResidues(self, nmrResidues): """Delete the nmrResidue from the scene """ # print('>>>_deleteNmrResidues') # get the nmrResidue in the current selected chain nmrResidues = makeIterableList(nmrResidues) for nmrChainId in self.nmrResidueList.nmrChains.keys(): thisResList = [nmrResidue for nmrResidue in nmrResidues if nmrResidue.nmrChain.pid == nmrChainId] if thisResList: self._removeNmrResidues(nmrChainId, thisResList) return True def _removeNmrResidues(self, nmrChainId, nmrResidues): """Delete the nmrResidue from the scene """ # print('>>> _removeNmrResidues') nmrResidues = makeIterableList(nmrResidues) for nmrResidue in nmrResidues: # this SHOULD never fail if nmrResidue not in self.nmrResidueList.nmrChains[nmrChainId]: continue ii = self.nmrResidueList.nmrChains[nmrChainId].index(nmrResidue) # take the current nmrList, and remove the deleted nmrResidue # with the mainNmrResidues - should be correct order or empty delResSet = list(OrderedSet(self.nmrResidueList.nmrChains[nmrChainId]) - OrderedSet([nmrResidue])) # print('>>> delResSet', delResSet) self.nmrResidueList.nmrChains[nmrChainId] = delResSet if ii > 0: # rebuild peak lines, etc, for the previous nmrResidue - may need to check for +1 offsets previousNmrResidue = self.nmrResidueList.nmrChains[nmrChainId][ii - 1] self._rebuildNmrResidues(nmrChainId, previousNmrResidue) self._cleanupNmrResidue(nmrResidue) # update the prediction in the sequenceModule self.predictSequencePosition(self.nmrResidueList.nmrChains[nmrChainId]) def _cleanupNmrResidue(self, nmrResidue): """remove guiNmrAtoms and guiNmrResidue from scene Clean up dicts in nmrResidueList """ guiNmrAtomSet = set([self.nmrResidueList.guiNmrAtoms[nmrAtom] for nmrAtom in nmrResidue.nmrAtoms if nmrAtom in self.nmrResidueList.guiNmrAtoms]) for guiAtom in guiNmrAtomSet: for guiLineList in self.nmrResidueList.assignmentLines.values(): guiLines = [guiLine for guiLine in guiLineList if guiLine.guiAtom1 is guiAtom or guiLine.guiAtom2 is guiAtom] # remove all graphic lines for guiLine in guiLines: guiLineList.remove(guiLine) if guiLine in self.scene.items(): self.scene.removeItem(guiLine) for guiLineList in self.nmrResidueList.connectingLines.values(): guiLines = [guiLine for guiLine in guiLineList if guiLine.guiAtom1 is guiAtom or guiLine.guiAtom2 is guiAtom] # remove all graphic lines for guiLine in guiLines: guiLineList.remove(guiLine) if guiLine in self.scene.items(): self.scene.removeItem(guiLine) # clear connectivity list of guiNmrAtoms guiAtom.clearConnectedList() self.scene.removeItem(self.nmrResidueList.guiNmrResidues[nmrResidue]) del self.nmrResidueList.guiNmrResidues[nmrResidue] for nmrAtom in nmrResidue.nmrAtoms: if nmrAtom in self.nmrResidueList.guiNmrAtoms: del self.nmrResidueList.guiNmrAtoms[nmrAtom] def _deleteGuiNmrResidues(self, nmrResidues, showPredictions): """Delete items from an old nmrResidue. """ # print('>>>_deleteGuiNmrResidues') nmrResidues = makeIterableList(nmrResidues) for nmrResidue in nmrResidues: self._cleanupNmrResidue(nmrResidue) # nmrChains contain nmrResidue in the wrong place and must be removed before sequence prediction for nmrChainId, nmrList in self.nmrResidueList.nmrChains.items(): thisResList = [nmrResidue for nmrResidue in nmrList if nmrResidue.nmrChain.pid == nmrChainId] if thisResList: # update the prediction in the sequenceModule self.predictSequencePosition(thisResList, showPredictions) # put all the guiResidueGroups in the correct positions self.nmrResidueList.updateGuiResiduePositions(nmrChainId, updateMainChain=True, updateConnectedChains=True) def _updateEndPoints(self, lineDict): """Update the end points from the dict. """ for lineList in lineDict.values(): for line in lineList: try: line.updateEndPoints() except: pass def _buildNmrResidues(self, nmrChainId, nmrResidueList, showPredictions=True, showSideChain=False): """Build the new residues in the list, inserting into the predicted stretch at the correct index. """ # print('>>> _buildNmrResidues') # this SHOULD be a list of only one item but use like this just to be sure for nmrResidue in nmrResidueList: if nmrResidue is nmrResidue.mainNmrResidue: # take the current nmrList, and the new nmrResidue, and get intersection # with the mainNmrResidues - should be correct order or empty newResSet = list((OrderedSet(self.nmrResidueList.nmrChains[nmrChainId]) | OrderedSet([nmrResidue])) & \ OrderedSet(nmrResidue.nmrChain.mainNmrResidues)) # keeps the ordering of the second set # print('>>> newResSet', newResSet) # if not showing all nmrResidues then get the connected stretch from the current nmrResidue if not self.nmrResiduesCheckBox.isChecked(): # get the connected stretch of mainNmrResidues if self.current.nmrResidue: mainNmrRes = self.current.nmrResidue.mainNmrResidue if mainNmrRes in newResSet: indL = indR = newResSet.index(mainNmrRes) while newResSet[indL].previousNmrResidue and indL > 0: indL -= 1 while newResSet[indR].nextNmrResidue and indR < len(newResSet): indR += 1 newResSet = newResSet[indL:indR + 1] if not newResSet: return # update to the new list self.nmrResidueList.nmrChains[nmrChainId] = newResSet # iterate through and and add new residues that don't already exists for ii, nmrRes in enumerate(newResSet): # do not _insertNmrRes as the list is built self.nmrResidueList.addNmrResidue(nmrChainId, nmrRes, ii, _insertNmrRes=False, spacing=self.atomSpacing, residueAtoms=self.DEFAULT_RESIDUE_ATOMS, showPredictions=showPredictions, showSideChain=showSideChain) # add the connecting lines # guiNmrResidues = [self.guiNmrResidues[nmrResidue] for nmrResidue in nmrResidueList if nmrResidue is nmrResidue.mainNmrResidue] # add the connecting lines # self.nmrResidueList.addConnectionsBetweenGroups() self.nmrResidueList.rebuildNmrResidues(nmrResidueList) # update the prediction in the sequenceModule self.predictSequencePosition(self.nmrResidueList.nmrChains[nmrChainId], showPredictions) return True
[docs] def resetScene(self): """Reset all gui items and data in the scene. """ with self.mainWidget.blockWidgetSignals(): self.nmrResidueList.reset() self.scene.clear() # self.scene.setSceneRect(self.scene.itemsBoundingRect()) self.thisSequenceWidget._initialiseChainLabels()
[docs] def setNmrChain(self, nmrChain): self.nmrResidueList.nmrChain = nmrChain
# from ccpn.util.decorators import profile # # @profile
[docs] def setNmrChainDisplay(self, nmrChainOrPid, showPredictions=True, showSideChain=False): # print('>>>setNmrChainDisplay') if isinstance(nmrChainOrPid, str): if not Pid.isValid(nmrChainOrPid): self.resetScene() return nmrChain = self.project.getByPid(nmrChainOrPid) else: nmrChain = nmrChainOrPid # nmrChainOrPid could be '<Select>' in which case nmrChain would be None if not nmrChain: self.resetScene() return self.nmrChain = nmrChain thisChainId = nmrChain.pid with self.mainWidget.blockWidgetSignals(): # self.mainWidget.setVisible(False) # currently only handles one visible nmrChain at a time - but changing to a dict self.resetScene() self.setNmrChain(nmrChain) # self.removeNmrChainNotifiers() # self.addNmrChainNotifiers() nmrList = nmrChain.mainNmrResidues if self.nmrResiduesCheckBox.isChecked(): nmrList = nmrChain.mainNmrResidues if not self.nmrResiduesCheckBox.isChecked(): # get the connected stretch of mainNmrResidues if self.current.nmrResidue: mainNmrRes = self.current.nmrResidue.mainNmrResidue if mainNmrRes in nmrList: indL = indR = nmrList.index(mainNmrRes) while nmrList[indL].previousNmrResidue and indL > 0: indL -= 1 while nmrList[indR].nextNmrResidue and indR < len(nmrList): indR += 1 nmrList = nmrList[indL:indR + 1] # add the nmrResidues to the scene for ii, nmrRes in enumerate(nmrList): self.nmrResidueList.addNmrResidue(thisChainId, nmrRes, index=ii, spacing=self.atomSpacing, residueAtoms=self.DEFAULT_RESIDUE_ATOMS, showPredictions=showPredictions, showSideChain=showSideChain) # # add the connecting lines # self.nmrResidueList.addConnectionsBetweenAllGroups(thisChainId) # add the peakAssignment lines self.nmrResidueList._addAllPeakAssignments(thisChainId) # put all the guiResidueGroups in the correct positions self.nmrResidueList.updateGuiResiduePositions(thisChainId, updateMainChain=True, updateConnectedChains=True) # update the prediction in the sequenceModule for thisChainId in self.nmrResidueList.nmrChains.values(): self.predictSequencePosition(thisChainId, showPredictions)
# self.mainWidget.setVisible(True)
[docs] def showChainsChanged(self, data=None): """Respond to a change in the chains list """ objs = self._SGwidget.chainsWidget._getObjects() showPredictions = self._SGwidget.checkBoxes['showPredictions']['widget'].isChecked() self._chains = objs self.thisSequenceWidget.setChains(objs) # update the prediction in the sequenceModule for thisChainId in self.nmrResidueList.nmrChains.values(): self.predictSequencePosition(thisChainId, showPredictions)
[docs] def showShiftListPulldown(self, data=None, chains=None): """Clear and redraw the nmrChain selected from the pulldown. """ # recalculate probabilities/predicted sequences if needed shiftListPid = self.shiftListPulldown.getText() if shiftListPid: objs = chains or self._SGwidget.chainsWidget._getObjects() showPredictions = self._SGwidget.checkBoxes['showPredictions']['widget'].isChecked() self._chemicalShiftList = self.project.getByPid(shiftListPid) # update sequence graph predictions self.nmrResidueList._updateGroupResiduePredictions(showPredictions) # update the prediction in the sequenceModule for thisChainId in self.nmrResidueList.nmrChains.values(): self.predictSequencePosition(thisChainId, showPredictions) self.nmrResidueList.setNmrResidueSelection([self.current.nmrResidue])
[docs] def showPredictions(self, data=None): """Show predictions and calculate predicted sequences """ self.showNmrChainFromPulldown(data)
[docs] def showNmrChainFromPulldown(self, data=None): """Clear and redraw the nmrChain selected from the pulldown. """ # print('>>>showNmrChainFromPulldown') nmrChainPid = self.nmrChainPulldown.getText() if nmrChainPid: showPredictions = self._SGwidget.checkBoxes['showPredictions']['widget'].isChecked() showSideChain = self._SGwidget.checkBoxes['showSideChain']['widget'].isChecked() with self.sceneBlocking(): self.setNmrChainDisplay(nmrChainPid, showPredictions=showPredictions, showSideChain=showSideChain) self.nmrResidueList.setNmrResidueSelection([self.current.nmrResidue]) # check whether to update self.current.nmrChain self._setCurrentNmrChain(nmrChainPid) else: # nmrChainOrPid could be '<Select>' in which case nmrChain would be None self.resetScene()
def _setCurrentNmrChain(self, nmrChainOrPid): if isinstance(nmrChainOrPid, str): if not Pid.isValid(nmrChainOrPid): return nmrChain = self.project.getByPid(nmrChainOrPid) else: nmrChain = nmrChainOrPid # nmrChainOrPid could be '<Select>' in which case nmrChain would be None if not nmrChain: self.resetScene() return checkBox = self._SGwidget.getWidget(LINKTOPULLDOWNCLASS) if self.current.nmrChain and self.current.nmrChain != nmrChain and checkBox and checkBox.isChecked(): self.current.nmrChain = nmrChain
[docs] def resetSequenceGraph(self): """Reset the module to the default nmrChain. """ self.nmrChainPulldown.pulldownList.select('NC:@-')
def _closeModule(self): """CCPN-INTERNAL: used to close the module """ self.thisSequenceWidget.close() super()._closeModule()
[docs] def unlinkNearestNmrResidue(self, selectedNmrResidue=None): if self.current.nmrResidue: selected = str(self.current.nmrResidue.pid) if self.current.nmrResidue.mainNmrResidue.previousNmrResidue: with progressManager(self.mainWindow, 'unlinking Previous NmrResidue to:\n ' + selected): try: self.current.nmrResidue.unlinkPreviousNmrResidue() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es elif self.current.nmrResidue.mainNmrResidue.previousNmrResidue: with progressManager(self.mainWindow, 'unlinking Next NmrResidue to:\n ' + selected): try: self.current.nmrResidue.unlinkNextNmrResidue() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es if self.current.nmrResidue: self.showNmrChainFromPulldown()
[docs] def disconnectPreviousNmrResidue(self, selectedNmrResidue=None): if self.current.nmrResidue: selected = str(self.current.nmrResidue.pid) with progressManager(self.mainWindow, 'disconnecting Previous NmrResidue to:\n ' + selected): try: self.current.nmrResidue.disconnectPrevious() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es if self.current.nmrResidue: self.showNmrChainFromPulldown()
[docs] def disconnectNmrResidue(self, selectedNmrResidue=None): if self.current.nmrResidue: selected = str(self.current.nmrResidue.pid) with progressManager(self.mainWindow, 'disconnecting NmrResidue:\n ' + selected): try: self.current.nmrResidue.disconnect() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es if self.current.nmrResidue: self.showNmrChainFromPulldown()
[docs] def disconnectNextNmrResidue(self, selectedNmrResidue=None): if self.current.nmrResidue: selected = str(self.current.nmrResidue.pid) with progressManager(self.mainWindow, 'disconnecting Next NmrResidue to:\n ' + selected): try: self.current.nmrResidue.disconnectNext() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es if self.current.nmrResidue: self.showNmrChainFromPulldown()
[docs] def disconnectAllNmrResidues(self, selectedNmrResidue=None): if self.current.nmrResidue: selected = str(self.current.nmrResidue.pid) with progressManager(self.mainWindow, 'disconnecting all NmrResidues connected to:\n ' + selected): try: self.current.nmrResidue.disconnectAll() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es if self.current.nmrResidue: self.showNmrChainFromPulldown()
[docs] def deassignNmrChain(self, selectedNmrResidue=None): if self.current.nmrResidue: selected = str(self.current.nmrResidue.nmrChain.pid) with progressManager(self.mainWindow, 'deassigning nmrResidues in NmrChain:\n ' + selected): try: self.current.nmrResidue.deassignNmrChain() except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es if self.current.nmrResidue: self.showNmrChainFromPulldown()
[docs] def deassignPeak(self, selectedPeak=None, selectedNmrAtom=None): """Deassign the peak by removing the assigned nmrAtoms from the list """ selectedPeak = self.project.getByPid(selectedPeak) if isinstance(selectedPeak, str) else selectedPeak if not isinstance(selectedPeak, Peak): raise TypeError('selectedPeak must be of type Peak') selectedNmrAtom = self.project.getByPid(selectedNmrAtom) if isinstance(selectedNmrAtom, str) else selectedNmrAtom if not isinstance(selectedNmrAtom, NmrAtom): raise TypeError('selectedNmrAtom must be of type NmrAtom') if selectedPeak: with undoBlockWithoutSideBar(): try: newList = [] # remove the nmrAtom from the list and replace with None for atomList in selectedPeak.assignedNmrAtoms: atoms = [(atom if atom != selectedNmrAtom else None) for atom in list(atomList)] newList.append(tuple(atoms)) selectedPeak.assignedNmrAtoms = tuple(newList) except Exception as es: showWarning(str(self.windowTitle()), str(es)) if self.application._isInDebugMode: raise es
[docs] def initialiseScene(self): """Replace the scene with a new one to reset the size of the scrollbars. """ # Only needed to be done the first time, scene is resized at the end of setNmrChainDisplay self.scene = QtWidgets.QGraphicsScene(self) self.scrollContents = QtWidgets.QGraphicsView(self.scene) self.scrollContents.setRenderHints(QtGui.QPainter.Antialiasing) self.scrollContents.setInteractive(True) self.scrollContents.setGeometry(QtCore.QRect(0, 0, 300, 400)) self.scrollContents.setAlignment(QtCore.Qt.AlignCenter) self._sequenceGraphScrollArea.setWidget(self.scrollContents) self._setFocusColour()
def _setFocusColour(self, focusColour=None, noFocusColour=None): """Set the focus/noFocus colours for the widget """ focusColour = getColours()[BORDERFOCUS] noFocusColour = getColours()[BORDERNOFOCUS] styleSheet = "QGraphicsView { " \ "border: 1px solid;" \ "border-radius: 1px;" \ "border-color: %s;" \ "} " \ "QGraphicsView:focus { " \ "border: 1px solid %s; " \ "border-radius: 1px; " \ "}" % (noFocusColour, focusColour) self.scrollContents.setStyleSheet(styleSheet)
[docs] def predictSequencePosition(self, nmrResidueList: list, showPredictions=True): """ Predicts sequence position for Nmr residues displayed in the Assigner and highlights appropriate positions in the Sequence Module if it is displayed. """ if len(nmrResidueList) < 3 or not showPredictions: self.thisSequenceWidget._initialiseChainLabels() return if self._chains: if self._chemicalShiftList: nmrResidues = nmrResidueList # [item[0] for item in nmrResidueList] checkDict = getAllSpinSystems(self.project, nmrResidues, self._chains, [self._chemicalShiftList]) for chainNum in checkDict.keys(): self.thisSequenceWidget._clearStretches(chainNum) possibleMatches = checkDict[chainNum] if possibleMatches: for chemList in possibleMatches: for possibleMatch in chemList: if possibleMatch[0] > 1 and not len(possibleMatch[1]) < len(nmrResidues): self.thisSequenceWidget._highlightPossibleStretches(chainNum, possibleMatch[1]) else: for chNum, chain in enumerate(self._chains): self.thisSequenceWidget._clearStretches(chNum)
def _toggleSequence(self): if not self.sequenceCheckBox.isChecked(): self._sequenceWidgetFrame.hide() else: self._sequenceWidgetFrame.show()
[docs] def navigateToNmrResidue(self, selectedNmrResidue=None): """Navigate in selected displays to nmrResidue; skip if none defined """ nmrResidue = self.current.nmrResidue if not nmrResidue: return logger.debug('nmrResidue=%s' % (nmrResidue.id)) displays = self._SGwidget.displaysWidget.getDisplays() if len(displays) == 0: logger.warning('Undefined display module(s); select in settings first') showWarning('startAssignment', 'Undefined display module(s);\nselect in settings first') return with undoBlockWithoutSideBar(): # optionally clear the marks if self._SGwidget.checkBoxes['autoClearMarks']['widget'].isChecked(): self.mainWindow.clearMarks() # navigate the displays for display in displays: if display and len(display.strips) > 0 and display.strips[0].spectrumViews: newWidths = None #_getCurrentZoomRatio(display.strips[0].viewRange()) if display.strips[0].spectrumViews[0].spectrum.dimensionCount <= 2: widths = _getCurrentZoomRatio(display.strips[0].viewRange()) navigateToNmrResidueInDisplay(nmrResidue, display, stripIndex=0, widths=newWidths, #['full'] * len(display.strips[0].axisCodes), showSequentialResidues=(len(display.axisCodes) > 2) and self._SGwidget.checkBoxes['sequentialStrips']['widget'].isChecked(), markPositions=self._SGwidget.checkBoxes['markPositions']['widget'].isChecked() )
def _raiseContextMenu(self, obj, pos): """Creates and raises a context menu enabling items to be disconnected """ contextMenu = Menu('', self.mainWindow, isFloatWidget=True) pressed = obj #.scene.mouseGrabberItem() if isinstance(pressed, AssignmentLine): # self.selectedLine: thisLine = pressed #self.selectedLine if thisLine._peak and thisLine._peak.assignedNmrAtoms: contextMenu.addAction('deassign nmrAtoms from Peak: %s' % str(thisLine._peak.id)) contextMenu.addSeparator() # add the nmrAtoms to the menu for nmrAtomList in thisLine._peak.assignedNmrAtoms: for nmrAtom in nmrAtomList: if nmrAtom: # contextMenu.addAction(nmrAtom.id, partial(self.deassignPeak, thisLine._peak, nmrAtom)) if nmrAtom.nmrResidue is None or nmrAtom.nmrResidue.offsetNmrResidues: contextMenu.addAction(nmrAtom.id, partial(self.deassignPeak, thisLine._peak, nmrAtom)) else: contextMenu.addAction('(' + nmrAtom.id + ')', partial(self.deassignPeak, thisLine._peak, nmrAtom)) contextMenu.move(pos.x(), pos.y() + 10) contextMenu.exec_() elif isinstance(pressed, GuiNmrResidue): try: # create the nmrResidue menu self._disconnectPreviousActionMenu = contextMenu.addAction(self.disconnectPreviousIcon, 'disconnect Previous nmrResidue', partial(self.disconnectPreviousNmrResidue)) self._disconnectActionMenu = contextMenu.addAction(self.disconnectIcon, 'disconnect nmrResidue', partial(self.disconnectNmrResidue)) self._disconnectNextActionMenu = contextMenu.addAction(self.disconnectNextIcon, 'disconnect Next nmrResidue', partial(self.disconnectNextNmrResidue)) contextMenu.addSeparator() self._disconnectAllActionMenu = contextMenu.addAction('disconnect all nmrResidues', partial(self.disconnectAllNmrResidues)) if obj.nmrResidue.residue: contextMenu.addSeparator() self._deassignNmrChainActionMenu = contextMenu.addAction('deassign nmrChain', partial(self.deassignNmrChain)) assign = pressed.nmrResidue.residue is not None self._deassignNmrChainActionMenu.setEnabled(assign) contextMenu.addSeparator() self._showActionMenu = contextMenu.addAction('Show nmrResidue', partial(self.showNmrResidue, obj)) prev = pressed.nmrResidue.previousNmrResidue is not None nxt = pressed.nmrResidue.nextNmrResidue is not None self._disconnectPreviousActionMenu.setEnabled(prev) self._disconnectActionMenu.setEnabled(prev or nxt) self._disconnectNextActionMenu.setEnabled(nxt) self._disconnectAllActionMenu.setEnabled(prev or nxt) contextMenu.move(pos.x(), pos.y() + 10) contextMenu.exec_() except Exception as es: print(str(es)) elif isinstance(pressed, GuiNmrAtom): # create the nmrAtom menu contextMenu.addAction('deassign nmrAtoms from Peaks') contextMenu.addSeparator() if pressed.nmrAtom and pressed.nmrAtom.assignedPeaks: # add nmrAtoms to the menu allPeaks = OrderedSet() # add the internal peaks to the list for peak in pressed.nmrAtom.assignedPeaks: allPeaks.add(peak) self._addPeaksToMenu(allPeaks, contextMenu) allAdjacentPeaks = OrderedSet() atom = pressed.nmrAtom atomName = atom.name res = atom.nmrResidue nextRes = res.nextNmrResidue.mainNmrResidue if res.nextNmrResidue else None prevRes = res.previousNmrResidue.mainNmrResidue if res.previousNmrResidue else None # add peaks corresponding to the previous residue if prevRes: for offRes in prevRes.offsetNmrResidues: if offRes.relativeOffset == 1: for offAtm in offRes.nmrAtoms: if offAtm.name == atomName: for peak in offAtm.assignedPeaks: allAdjacentPeaks.add(peak) # add peaks corresponding to the next residue if nextRes: for offRes in nextRes.offsetNmrResidues: if offRes.relativeOffset == -1: for offAtm in offRes.nmrAtoms: if offAtm.name == atomName: for peak in offAtm.assignedPeaks: allAdjacentPeaks.add(peak) if allPeaks and allAdjacentPeaks: contextMenu.addSeparator() self._addPeaksToMenu(allAdjacentPeaks, contextMenu) contextMenu.move(pos.x(), pos.y() + 10) contextMenu.exec_() def _addPeaksToMenu(self, allPeaks, contextMenu): for peak in allPeaks: if peak and peak.assignedNmrAtoms: subMenu = contextMenu.addMenu(peak.id) subMenu.addAction('nmrAtoms') subMenu.addSeparator() for nmrAtomList in peak.assignedNmrAtoms: for nmrAtom in nmrAtomList: if nmrAtom: if nmrAtom.nmrResidue is None or nmrAtom.nmrResidue.offsetNmrResidues: subMenu.addAction(nmrAtom.id, partial(self.deassignPeak, peak, nmrAtom)) else: subMenu.addAction('(' + nmrAtom.id + ')', partial(self.deassignPeak, peak, nmrAtom))
[docs] def showNmrResidue(self, obj): self.navigateToNmrResidue(selectedNmrResidue=obj.nmrResidue)
[docs] def defineAtoms(self): import math self.lineSpacing = getFontHeight(name=SEQUENCEGRAPHFONT) self.atomSpacing = atomSpacing = self.lineSpacing * 5 self.lineConnectWidth = max(2, ((self.lineSpacing - 0) // 6)) self.lineWidth = self.lineConnectWidth + 1 cos36 = math.cos(math.pi / 5) sin36 = math.sin(math.pi / 5) tan36 = math.tan(math.pi / 5) cos54 = math.cos(3 * math.pi / 10) sin54 = math.sin(3 * math.pi / 10) cos60 = math.cos(math.pi / 3) sin60 = math.sin(math.pi / 3) sin72 = math.sin(2 * math.pi / 5) cos72 = math.cos(2 * math.pi / 5) self.DEFAULT_RESIDUE_ATOMS = {'H' : np.array([0, 0]), 'N' : np.array([0, -1 * atomSpacing]), 'CA': np.array([atomSpacing, -1 * atomSpacing]), 'CB': np.array([atomSpacing, -2 * atomSpacing]), 'C' : np.array([2 * atomSpacing, -1 * atomSpacing]) } # need a connectivity between the atoms as a list of pairs e.g., ((H, N), (N, CA), (CA, CB), (CA, C)) # Use loadCompoundPickle from chemBuild to load the structure for these; found in compound.variants.bonds self.ATOM_POSITION_DICT = { 'ALA': {'HB%' : (0.0, -0.75 * atomSpacing), 'boundAtoms': ('')}, 'CYS': {'SG': (0.0, -1 * atomSpacing), 'HG': (0, -1.75 * atomSpacing)}, 'ASP': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG' : (0, -1 * atomSpacing)}, 'ASN': {'HBx' : (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG' : (0, -1 * atomSpacing), 'ND2': (0, -2 * atomSpacing), 'HD2x': (atomSpacing * -0.75, -2 * atomSpacing - (0.75 * atomSpacing * cos60)), 'HD2y': (atomSpacing * +0.75, -2 * atomSpacing - (0.75 * atomSpacing * cos60)), }, 'GLU': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HGx': (atomSpacing * -0.75, -1 * atomSpacing), 'HGy': (atomSpacing * 0.75, -1 * atomSpacing), 'CG' : (0, -1 * atomSpacing), 'CD': (0, -2 * atomSpacing) }, 'GLN': {'HBx' : (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HGx' : (atomSpacing * -0.75, -1 * atomSpacing), 'HGy': (atomSpacing * 0.75, -1 * atomSpacing), 'CG' : (0, -1 * atomSpacing), 'CD': (0, -2 * atomSpacing), 'NE2': (0, -3 * atomSpacing), 'HD2x': (atomSpacing * -0.75, -3 * atomSpacing - (0.75 * atomSpacing * cos60)), 'HD2y': (atomSpacing * +0.75, -3 * atomSpacing - (0.75 * atomSpacing * cos60)), }, 'PHE': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG' : (0, -1 * atomSpacing), 'CD1': (-1 * atomSpacing, (-1 - cos60) * atomSpacing), 'CD2': (1 * atomSpacing, (-1 - cos60) * atomSpacing), 'CE1': (-1 * atomSpacing, (-2 - cos60) * atomSpacing), 'CE2': (1 * atomSpacing, (-2 - cos60) * atomSpacing), 'HD1': (-1.75 * atomSpacing, (-1 - cos60) * atomSpacing), 'HD2': (1.75 * atomSpacing, (-1 - cos60) * atomSpacing), 'HE1': (-1.75 * atomSpacing, (-2 - cos60) * atomSpacing), 'HE2': (1.75 * atomSpacing, (-2 - cos60) * atomSpacing), 'CZ' : (0, (-2 - cos60 - sin60) * atomSpacing), 'HZ': (0, (-2 - cos60 - sin60 - 0.75) * atomSpacing) }, 'TYR': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG' : (0, -1 * atomSpacing), 'CD1': (-1 * atomSpacing, (-1 - cos60) * atomSpacing), 'CD2': (1 * atomSpacing, (-1 - cos60) * atomSpacing), 'CE1': (-1 * atomSpacing, (-2 - cos60) * atomSpacing), 'CE2': (1 * atomSpacing, (-2 - cos60) * atomSpacing), 'HD1': (-1.75 * atomSpacing, (-1 - cos60) * atomSpacing), 'HD2': (1.75 * atomSpacing, (-1 - cos60) * atomSpacing), 'HE1': (-1.75 * atomSpacing, (-2 - cos60) * atomSpacing), 'HE2': (1.75 * atomSpacing, (-2 - cos60) * atomSpacing), 'CZ' : (0, (-2 - cos60 - sin60) * atomSpacing), 'HH': (0, (-2 - cos60 - sin60 - 0.75) * atomSpacing) }, 'SER': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HG' : (0, -1 * atomSpacing) }, 'THR': {'HG1': (atomSpacing * -0.75, 0.0), 'HB': (atomSpacing * 0.75, 0.0), 'CG2': (0, -1 * atomSpacing), 'HG2%': (0, -1.75 * atomSpacing) }, 'MET': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HGx': (atomSpacing * -0.75, -1 * atomSpacing), 'HGy': (atomSpacing * 0.75, -1 * atomSpacing), 'CG' : (0, -1 * atomSpacing), 'SD': (0, -2 * atomSpacing), 'CE': (0, -3 * atomSpacing), 'HE%': (0, -3.75 * atomSpacing) }, 'ARG': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HGx': (atomSpacing * -0.75, -1 * atomSpacing), 'HGy': (atomSpacing * 0.75, -1 * atomSpacing), 'CG' : (0, -1 * atomSpacing), 'CD': (0, -2 * atomSpacing), 'NE': (0, -3 * atomSpacing), 'CZ' : (0, -4 * atomSpacing), 'NH1': (atomSpacing * -1, -4 * atomSpacing - (0.75 * atomSpacing * cos60)), 'NH2': (atomSpacing * +1, -4 * atomSpacing - (0.75 * atomSpacing * cos60)), }, 'VAL': {'HBx' : (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CGx' : (-1 * atomSpacing, -1 * (cos60 * atomSpacing)), 'CGy' : (1 * atomSpacing, -1 * (cos60 * atomSpacing)), 'HGx%': (atomSpacing * -1, -1 * (cos60 * atomSpacing) - (0.75 * atomSpacing)), 'HGy%': (atomSpacing * +1, -1 * (cos60 * atomSpacing) - (0.75 * atomSpacing)) }, 'LEU': {'HBx' : (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HGx' : (atomSpacing * -0.75, -1 * atomSpacing), 'HGy': (atomSpacing * 0.75, -1 * atomSpacing), 'CG' : (0, -1 * atomSpacing), 'CDx' : (-1 * atomSpacing, (-1 - cos60) * atomSpacing), 'CDy' : (1 * atomSpacing, (-1 - cos60) * atomSpacing), 'HDx%': (atomSpacing * -1, ((-1 - cos60) * atomSpacing) - (0.75 * atomSpacing)), 'HDy%': (atomSpacing * +1, ((-1 - cos60) * atomSpacing) - (0.75 * atomSpacing)) }, 'ILE': {'HBx' : (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG1' : (-1 * atomSpacing, -1 * (cos60 * atomSpacing)), 'CG2%': (1 * atomSpacing, -1 * (cos60 * atomSpacing)), 'HG1x': (atomSpacing * -1.75, -1 * (cos60 * atomSpacing)), 'HG1y': (atomSpacing * -0.25, -1 * (cos60 * atomSpacing)), 'HG2%': (1 * atomSpacing, -1 * (cos60 * atomSpacing) - (0.75 * atomSpacing)), 'CD1%': (-1 * atomSpacing, -1 * (cos60 * atomSpacing) - atomSpacing), 'HD1%': (-1 * atomSpacing, -1 * (cos60 * atomSpacing) - (1.75 * atomSpacing)), }, 'LYS': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'HGx': (atomSpacing * -0.75, -1 * atomSpacing), 'HGy': (atomSpacing * 0.75, -1 * atomSpacing), 'CG' : (0, -1 * atomSpacing), 'CD': (0, -2 * atomSpacing), 'HDx': (atomSpacing * -0.75, -2 * atomSpacing), 'HDy': (atomSpacing * 0.75, -2 * atomSpacing), 'HEx': (atomSpacing * -0.75, -3 * atomSpacing), 'HEy': (atomSpacing * 0.75, -3 * atomSpacing), 'CE' : (0, -3 * atomSpacing), 'NZ' : (0, -4 * atomSpacing), 'HZ%': (0, -4.75 * atomSpacing), }, 'HIS': {'HBx': (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG' : (0, -1 * atomSpacing), 'ND1': (-1 * atomSpacing, -1 * (atomSpacing + (atomSpacing / (2 * tan36)))), 'CD2': (atomSpacing, -1 * (atomSpacing + (atomSpacing / (2 * tan36)))), 'NE2': (atomSpacing / 2, -1 * (atomSpacing + (atomSpacing / (2 * sin36)) + (atomSpacing / (2 * tan36)))), 'CD1': (-0.5 * atomSpacing, -1 * (atomSpacing + (atomSpacing / (2 * sin36)) + (atomSpacing / (2 * tan36)))), }, 'TRP': {'HBx' : (atomSpacing * -0.75, 0.0), 'HBy': (atomSpacing * 0.75, 0.0), 'CG' : (0, -1 * atomSpacing), 'CD1': (atomSpacing, -1 * atomSpacing), 'NE1' : (atomSpacing + (atomSpacing * cos72), -1 * (atomSpacing + (atomSpacing * sin72))), 'CE2' : (atomSpacing + (atomSpacing * cos72) - (atomSpacing * sin54), -1 * (atomSpacing + (atomSpacing * sin72) + (atomSpacing * cos54))), 'CD2' : (-1 * (atomSpacing * cos72), -1 * (atomSpacing + (atomSpacing * sin72))), 'CE3' : (atomSpacing + (atomSpacing * cos72) - (atomSpacing * sin54) - (2 * (atomSpacing * sin60)), -1 * (atomSpacing + (atomSpacing * sin72) + (atomSpacing * cos54))), 'CZ2' : (atomSpacing + (atomSpacing * cos72) - (atomSpacing * sin54), -1 * (2 * atomSpacing + (atomSpacing * sin72) + (atomSpacing * cos54))), 'CZ3' : (atomSpacing + (atomSpacing * cos72) - (atomSpacing * sin54) - (2 * (atomSpacing * sin60)), -1 * (2 * atomSpacing + (atomSpacing * sin72) + (atomSpacing * cos54))), 'CH2' : (-1 * (atomSpacing * cos72), -1 * (2 * atomSpacing + (atomSpacing * sin72) + (atomSpacing * cos54) + (atomSpacing * cos60))), 'boundAtoms': (('CG', 'CD1'), ('CG', 'CD2'), ('CD2', 'CE3'), ('CD2', 'CE2'), ('CD1', 'NE1'), ('CE2', 'CZ2'), ('CE3', 'CZ3'), ('CZ3', 'CH2'), ('CZ2', 'CH2'), ('NE1', 'CE2')) }, 'PRO': { 'CB': (atomSpacing * cos72, -1 * (atomSpacing * sin72) + atomSpacing), 'CG': (-0.5 * atomSpacing, -1 * atomSpacing / (2 * tan36)), 'CD': (-1 * (atomSpacing + (atomSpacing * cos72)), -1 * (atomSpacing * sin72) + atomSpacing), } }
# if residueType == 'ALA': # hb = self._createGuiNmrAtom('HB%', (cbAtom.x(), cbAtom.y()-self.atomSpacing)) # self.scene.addItem(hb) # self._addConnectingLine(hb, cbAtom, 'white', 1.0, 0.0) # # if residueType == 'CYS': # sg = self._createGuiNmrAtom('SG', (cbAtom.x(), cbAtom.y()-self.atomSpacing)) # hg = self._createGuiNmrAtom('HG', (cbAtom.x(), cbAtom.y()-(2*self.atomSpacing))) # self.scene.addItem(sg) # self.scene.addItem(hg) # self._addConnectingLine(sg, cbAtom, 'white', 1.0, 0.0) # self._addConnectingLine(sg, hg, 'white', 1.0, 0.0) # # if residueType == 'ASP': # hb2 = self._createGuiNmrAtom('HBx', (cbAtom.x()-(self.atomSpacing*0.75), cbAtom.y())) # hb3 = self._createGuiNmrAtom('HBy', (cbAtom.x()+(self.atomSpacing*0.75), cbAtom.y())) # cg = self._createGuiNmrAtom('CG', (cbAtom.x(), cbAtom.y()-self.atomSpacing)) # self.scene.addItem(hb2) # self.scene.addItem(hb3) # self.scene.addItem(cg) # self._addConnectingLine(hb2, cbAtom, 'white', 1.0, 0.0) # self._addConnectingLine(hb3, cbAtom, 'white', 1.0, 0.0) # self._addConnectingLine(cg, cbAtom, 'white', 1.0, 0.0) # # if residueType == 'GLU': # hb2 = self._createGuiNmrAtom('HBx', (cbAtom.x()-(self.atomSpacing*0.75), cbAtom.y())) # hb3 = self._createGuiNmrAtom('HBy', (cbAtom.x()+(self.atomSpacing*0.75), cbAtom.y())) # cg = self._createGuiNmrAtom('CG', (cbAtom.x(), cbAtom.y()-self.atomSpacing)) # hg2 = self._createGuiNmrAtom('HBx', (cg.x()-(self.atomSpacing*0.75), cbAtom.y())) # hg3 = self._createGuiNmrAtom('HBy', (cg.x()+(self.atomSpacing*0.75), cbAtom.y())) # cd = self._createGuiNmrAtom('CD', (cbAtom.x(), cbAtom.y()-(2*self.atomSpacing))) # self.scene.addItem(hb2) # self.scene.addItem(hb3) # self.scene.addItem(cg) # self.scene.addItem(hg2) # self.scene.addItem(hg3) # self.scene.addItem(cd) # self._addConnectingLine(hb2, cbAtom, 'white', 1.0, 0.0) # self._addConnectingLine(hb3, cbAtom, 'white', 1.0, 0.0) # self._addConnectingLine(cg, hg2, 'white', 1.0, 0.0) # self._addConnectingLine(cg, hg3, 'white', 1.0, 0.0) # self._addConnectingLine(cg, cd, 'white', 1.0, 0.0) if __name__ == '__main__': from ccpn.ui.gui.widgets.Application import TestApplication from ccpn.ui.gui.widgets.TextEditor import TextEditor from ccpnmodel.ccpncore.lib.assignment.ChemicalShift import PROTEIN_ATOM_NAMES, ALL_ATOMS_SORTED isotopes = ['13C', '1H', '15N'] axisCodes = ['C', 'H', 'N'] atoms = {'H', 'N', 'CA', 'CB', 'C'} for k, v in ALL_ATOMS_SORTED.items(): atoms = atoms | set(v) thisDict = {} for axis, isotope in zip(axisCodes, isotopes): thisDict[isotope] = sorted([at for at in set(atoms) if at.startswith(axis)], key=greekKey) # app = TestApplication() # # popup = SequenceGraphModule() # # popup.show() # popup.raise_() # app.start()