OpenStructure
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
superpositiondialog.py
Go to the documentation of this file.
1 #------------------------------------------------------------------------------
2 # This file is part of the OpenStructure project <www.openstructure.org>
3 #
4 # Copyright (C) 2008-2011 by the OpenStructure authors
5 #
6 # This library is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation; either version 3.0 of the License, or (at your option)
9 # any later version.
10 # This library is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 # details.
14 #
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with this library; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #------------------------------------------------------------------------------
19 #
20 # Authors: Stefan Bienert
21 #
22 from PyQt4.QtCore import *
23 from PyQt4.QtGui import *
24 from ost.mol.alg import Superpose
25 from ost import mol
26 
27 class ChainComboBox(QComboBox):
28  def __init__(self, ent, gfx, parent=None):
29  # class variables
30  self.all_chains = 'All'
31  QComboBox.__init__(self, parent)
32  self.entity = ent
33  self.addItem(self.all_chains)
34  for chain in self.entity.chains:
35  self.addItem(chain.name)
36  if self.count()>0:
37  self.setCurrentIndex(0)
38  if gfx:
39  self.gfx = gfx
40  QObject.connect(self,
41  SIGNAL('highlighted (const QString&)'),
42  self._HighlightChain)
43  else:
44  self.gfx = None
45 
46  def focusOutEvent (self, event):
47  if self.gfx:
48  self.gfx.selection = None
49 
50  def SetItems(self, ent, gfx):
51  self.clear()
52  self.entity = ent
53  self.addItem(self.all_chains)
54  for chain in self.entity.chains:
55  self.addItem(chain.name)
56  if self.count()>0:
57  self.setCurrentIndex(0)
58  if gfx:
59  self.gfx = gfx
60 
61  def _HighlightChain(self, chain):
62  if str(chain) != 'All':
63  self.gfx.SetSelection(self.entity.Select('cname="%s"' % str(chain)))
64  else:
65  self.gfx.SetSelection(self.entity.Select(''))
66 
67  def _GetSelectedChain(self):
68  if self.currentIndex() == -1:
69  return mol.EntityHandle()
70  elif self.currentText() == self.all_chains:
71  return self.entity
72  return self.entity.Select('cname="%s"' % str(self.currentText()))
73 
74  def _SetSelectedChain(self, chain):
75  if hasattr(chain, 'name'):
76  name = chain.name
77  else:
78  name = str(chain)
79  for i in range(self.count()):
80  if self.itemText(i) == name:
81  self.setCurrentIndex(i)
82  break
83  selected_chain = property(_GetSelectedChain, _SetSelectedChain)
84 
85 class SuperpositionDialog(QDialog):
86  """
87  Provides a graphical user interface to structurally superpose two entities.
88  Uses function :func:`~ost.mol.alg.Superpose`. The RMSD of two superposed
89  molecules will be stored in attribute ``rmsd``. An index for the selected
90  reference molecule will be stored in attribute ``reference``.
91 
92  :param ent_one: The first entity
93  :type ent_one: :class:`~ost.mol.EntityView`, :class:`~ost.mol.EntityHandle`
94  or :class:`~ost.gfx.Entity`
95  :param ent_two: The second entity
96  :type ent_two: :class:`~ost.mol.EntityView`, :class:`~ost.mol.EntityHandle`
97  or :class:`~ost.gfx.Entity`
98 
99  **Example Usage:**
100 
101  .. code-block:: python
102 
103  e1=io.LoadPDB('examples/code_fragments/entity/pdb1ake.ent')
104  e2=io.LoadPDB('examples/code_fragments/entity/pdb4ake.ent')
105 
106  sd = ost.gui.dng.superpositiondialog.SuperpositionDialog(e1, e2)
107 
108  g1=gfx.Entity('G1', e1)
109  g2=gfx.Entity('G2', e2)
110  scene.Add(g1)
111  scene.Add(g2)
112 
113  if sd.reference == 0:
114  scene.CenterOn(g1)
115  else:
116  scene.CenterOn(g2)
117 
118  if sd.rmsd != None:
119  LogScript('RMSD: %.3f'%sd.rmsd)
120  """
121 
122  def __init__(self, ent_one, ent_two, parent=None):
123  # class variables
124  self.rmsd = None
125  self._mmethod_dict = {'number': 'number',
126  'index': 'index',
127  'local alignment': 'local-aln',
128  'global alignment': 'global-aln'}
129  self.gfx_one = None
130  self.gfx_two = None
131  self.gfx_select_one = None
132  self.gfx_select_two = None
133  QDialog.__init__(self, parent)
134  self.setWindowTitle('Superpose structures')
135  if not isinstance(ent_one, mol.EntityHandle) and \
136  not isinstance(ent_one, mol.EntityView):
137  n_one = ent_one.GetName()
138  self.gfx_one = ent_one
139  self.gfx_select_one = self.gfx_one.GetSelection()
140  self.ent_one = ent_one.GetView()
141  else:
142  if isinstance(ent_one, mol.EntityHandle):
143  n_one = ent_one.GetName()
144  elif isinstance(ent_one, mol.EntityView):
145  n_one = ent_one.GetHandle().GetName()
146  self.ent_one = ent_one
147  if len(n_one) == 0:
148  n_one = '1'
149  if not isinstance(ent_two, mol.EntityHandle) and \
150  not isinstance(ent_two, mol.EntityView):
151  n_two = ent_two.GetName()
152  self.gfx_two = ent_two
153  self.gfx_select_two = self.gfx_two.GetSelection()
154  self.ent_two = ent_two.GetView()
155  else:
156  if isinstance(ent_two, mol.EntityHandle):
157  n_two = ent_two.GetName()
158  elif isinstance(ent_two, mol.EntityView):
159  n_two = ent_two.GetHandle().GetName()
160  self.ent_two = ent_two
161  if len(n_two) == 0:
162  n_two = '2'
163  if n_one == n_two:
164  n_one = n_one + ' 1'
165  n_two = n_two + ' 2'
166  layout = QGridLayout(self)
167  # select reference molecule
168  self.reference = 0;
169  self._reference = self._ReferenceSelection(n_one, n_two)
170  grow = 0
171  layout.addWidget(QLabel("reference"), grow, 0)
172  layout.addWidget(self._reference, grow, 1)
173  grow += 1
174  # chains
175  self._chain_one = ChainComboBox(self.ent_one, self.gfx_one, self)
176  self._chain_two = ChainComboBox(self.ent_two, self.gfx_two, self)
177  layout.addWidget(QLabel("reference chain"), grow, 0)
178  layout.addWidget(self._chain_one, grow, 1)
179  grow += 1
180  layout.addWidget(QLabel("chain"), grow, 0)
181  layout.addWidget(self._chain_two, grow, 1)
182  grow += 1
183  # link chain and reference selection
184  QObject.connect(self._reference,
185  SIGNAL('currentIndexChanged(int)'),
187  # match methods
188  self._methods = self._MatchMethods()
189  layout.addWidget(QLabel('match residues by'), grow, 0)
190  grow += 1
191  layout.addWidget(self._methods)
192  # atoms
193  self._atoms = self._FetchAtoms(self._methods.size(),
194  self.ent_one,
195  self.ent_two)
196  self._atmselectbx, self._atmselectgrp = self._AtomSelectionBox()
197  layout.addWidget(self._atmselectbx, grow, 1)
198  grow += 1
199  # buttons
200  ok_button = QPushButton("Superpose")
201  QObject.connect(ok_button, SIGNAL('clicked()'), self.accept)
202  cancel_button = QPushButton("Cancel")
203  hbox_layout = QHBoxLayout()
204  hbox_layout.addStretch(1)
205  layout.addLayout(hbox_layout, grow, 0, 1, 2)
206  grow += 1
207  QObject.connect(cancel_button, SIGNAL('clicked()'), self.reject)
208  QObject.connect(self, SIGNAL('accepted()'), self._Superpose)
209  hbox_layout.addWidget(cancel_button, 0)
210  hbox_layout.addWidget(ok_button, 0)
211  ok_button.setDefault(True)
212  self.exec_()
213  # restore old selections
214  if self.gfx_one:
215  self.gfx_one.SetSelection(self.gfx_select_one)
216  if self.gfx_two:
217  self.gfx_two.SetSelection(self.gfx_select_two)
218 
219  def _Superpose(self):
220  view_one = self._chain_one.selected_chain
221  view_two = self._chain_two.selected_chain
222  atoms = self._GetAtomSelection()
223  sp = Superpose(view_two, view_one,
224  self._mmethod_dict[str(self._methods.currentText())],
225  atoms)
226  self.rmsd = sp.rmsd
227 
228  def _toggle_atoms(self, checked):
229  if checked:
230  self._atoms.setEnabled(True)
231  else:
232  self._atoms.setEnabled(False)
233 
234  def _AtomSelectionBox(self):
235  bt1 = QRadioButton('All')
236  bt2 = QRadioButton('Backbone')
237  bt3 = QRadioButton('CA')
238  self.cstmbtntxt = 'Custom'
239  custom_rbutton = QRadioButton(self.cstmbtntxt)
240  group = QButtonGroup()
241  group.addButton(bt1)
242  group.addButton(bt2)
243  group.addButton(bt3)
244  group.addButton(custom_rbutton)
245  bt1.setChecked(True)
246  vbox_layout = QVBoxLayout()
247  vbox_layout.addWidget(bt1)
248  vbox_layout.addWidget(bt2)
249  vbox_layout.addWidget(bt3)
250  vbox_layout.addWidget(custom_rbutton)
251  vbox_layout.addWidget(self._atoms)
252  QObject.connect(custom_rbutton, SIGNAL('toggled(bool)'), self._toggle_atoms)
253  box = QGroupBox("atom selection")
254  box.setLayout(vbox_layout)
255  return box, group
256 
257  def _GetAtomSelection(self):
258  checkedbtn = self._atmselectgrp.checkedButton()
259  if str(checkedbtn.text()) != self.cstmbtntxt:
260  return str(checkedbtn.text())
261  slctn_model = self._atoms.selectionModel()
262  dt_model = slctn_model.model()
263  atms = list()
264  for idx in slctn_model.selectedRows():
265  slctn = dt_model.data(idx, Qt.DisplayRole).toString()
266  atms.append(str(slctn))
267  return atms
268 
269  def _FetchAtoms(self, dim, ent_a, ent_b):
270  # fetch list of atoms: only those which are in both entities are considered
271  atm_dict = {}
272  for atm in ent_a.GetAtomList():
273  atm_dict[atm.name] = 0
274  for atm in ent_b.GetAtomList():
275  if atm.name in atm_dict:
276  atm_dict[atm.name] = 1
277  atmlst = QStringList()
278  for atm in sorted(atm_dict.keys()):
279  if atm_dict[atm]:
280  atmlst.append(atm)
281  elems = QStringListModel(atmlst)
282  atoms = QListView(self)
283  dim.setHeight(3*dim.height())
284  atoms.setFixedSize(dim)
285  atoms.setModel(elems)
286  atoms.setSelectionMode(QAbstractItemView.MultiSelection)
287  atoms.setEditTriggers(QAbstractItemView.NoEditTriggers)
288  atoms.setEnabled(False)
289  return atoms
290 
291  def _ReferenceSelection(self, name_a, name_b):
292  cbox = QComboBox()
293  cbox.addItem(name_a)
294  cbox.addItem(name_b)
295  if cbox.count() > 0:
296  cbox.setCurrentIndex(0)
297  return cbox
298 
299  def _ChangeChainSelection(self, index):
300  if index == 0:
301  self._chain_one.SetItems(self.ent_one, self.gfx_one)
302  self._chain_two.SetItems(self.ent_two, self.gfx_two)
303  self.reference = 0;
304  elif index == 1:
305  self._chain_one.SetItems(self.ent_two, self.gfx_two)
306  self._chain_two.SetItems(self.ent_one, self.gfx_one)
307  self.reference = 1;
308 
309  def _MatchMethods(self):
310  methods=QComboBox(self)
311  for method in sorted(self._mmethod_dict):
312  methods.addItem(method)
313  return methods