Atom Groups¶
The example below shows how to build an AtomGroup
from scratch. We start
by importing everything from the ProDy package and the NumPy package:
In [1]: from prody import *
In [2]: from numpy import *
In [3]: from pylab import *
In [4]: ion()
Building an Atom Group¶
The best way to start constructing an AtomGroup
is by setting the
coordinates first. Number of atoms will be automatically set according to
the size of the coordinate data array:
In [5]: wtr1 = AtomGroup('Water')
In [6]: wtr1
Out[6]: <AtomGroup: Water (0 atoms; no coordinates)>
In [7]: coords = array([[1, 0, 0], [0, 0, 0], [0, 0, 1]], dtype=float)
In [8]: coords
Out[8]:
array([[1., 0., 0.],
[0., 0., 0.],
[0., 0., 1.]])
In [9]: wtr1.setCoords(coords)
In [10]: wtr1
Out[10]: <AtomGroup: Water (3 atoms)>
Attributes¶
Attributes must be passed in a list or an array whose size is the same as the number of atoms.
In [11]: wtr1.setNames(['H', 'O', 'H'])
In [12]: wtr1.setResnums([1, 1, 1])
In [13]: wtr1.setResnames(['WAT', 'WAT', 'WAT'])
Accessing data will return a copy of the data. This means you can manipulate the return values safely without affecting the original values. For example:
In [14]: names = wtr1.getNames()
In [15]: names[0] = names[0] + '1'
In [16]: names
Out[16]: array(['H1', 'O', 'H'], dtype='|S6')
In [17]: wtr1.getNames()
Out[17]: array(['H', 'O', 'H'], dtype='|S6')
Atoms¶
Atoms are represented by instance of Atom
.
Iteration¶
Atoms in an AtomGroup
can be iterated over
In [18]: for a in wtr1:
....: print(a)
....:
Atom H (index 0)
Atom O (index 1)
Atom H (index 2)
Indexing¶
Atoms in an atom group can be accessed via indexing:
In [19]: a = wtr1[0]
In [20]: a
Out[20]: <Atom: H from Water (index 0)>
In [21]: a.getCoords()
Out[21]: array([1., 0., 0.])
Coordinate sets¶
Let’s add another coordinate set to the atom group:
In [22]: wtr1.addCoordset(array([[0, 1, 0], [0, 0, 0], [0, 0, 1.1]], dtype=float))
In [23]: wtr1
Out[23]: <AtomGroup: Water (3 atoms; active #0 of 2 coordsets)>
Note that the number of coordinate sets is now 2, but the active coordinate set index
is still 0. Active coordinate set index can be changed for AtomGroup
as follows:
In [24]: a.setACSIndex(1)
In [25]: a
Out[25]: <Atom: H from Water (index 0; active #1 of 2 coordsets)>
Changing active coordinate set for an atom group, does not affect the active coordinate set of the atom group:
In [26]: wtr1
Out[26]: <AtomGroup: Water (3 atoms; active #0 of 2 coordsets)>
Coordinates for the atom group will be returned from the active coordinate set
In [27]: a.getCoords()
Out[27]: array([0., 1., 0.])
In [28]: a.setACSIndex(0)
In [29]: a.getCoords()
Out[29]: array([1., 0., 0.])
Copying and Merging¶
Now let’s make another copy of this water:
In [31]: wtr2 = wtr1.copy()
In [32]: wtr2
Out[32]: <AtomGroup: Water (3 atoms; active #0 of 2 coordsets)>
Translate copy¶
Let’s translate the coordinates of wtr2 so that it does not overlap with wtr1
In [33]: wtr2.setCoords(wtr2.getCoords() + 2)
In [34]: wtr2.getCoords()
Out[34]:
array([[3., 2., 2.],
[2., 2., 2.],
[2., 2., 3.]])
Above operation only translated the coordinate set at index 0
In [35]: wtr2.setACSIndex(1)
In [36]: wtr2.getCoords()
Out[36]:
array([[0. , 1. , 0. ],
[0. , 0. , 0. ],
[0. , 0. , 1.1]])
In [37]: wtr2.setCoords(wtr2.getCoords() + 2) # translate the 2nd coordset as well
Change attributes¶
Before we merge wtr1 and wtr2, let’s change resid’s of wtr2:
In [38]: wtr2.setResnums( [2, 2, 2] )
In [39]: wtr2.getResnums()
Out[39]: array([2, 2, 2])
We can do this in an alternate way too:
In [40]: wtr2.select('all').setResnums(2)
In [41]: wtr2.getResnums()
Out[41]: array([2, 2, 2])
Merge two copies¶
Let’s merge the two water atom groups:
In [42]: wtrs = wtr1 + wtr2
In [43]: wtrs
Out[43]: <AtomGroup: Water + Water (6 atoms; active #0 of 2 coordsets)>
In [44]: wtrs.getCoords()
Out[44]:
array([[1., 0., 0.],
[0., 0., 0.],
[0., 0., 1.],
[3., 2., 2.],
[2., 2., 2.],
[2., 2., 3.]])
In [45]: wtrs.getNames()
Out[45]: array(['H', 'O', 'H', 'H', 'O', 'H'], dtype='|S6')
In [46]: wtrs.getResnums()
Out[46]: array([1, 1, 1, 2, 2, 2])
Hierarchical views¶
Hierarchical views of atom groups are represented by HierView
.
Residues (and also chains) in an atom group can also be iterated over
In [47]: for res in wtrs.getHierView().iterResidues():
....: print(res)
....:
WAT 1
WAT 2
Renaming an atom group¶
Finally, it’s is possible to change the name of wtrs from “Water + Water” to something shorter:
In [48]: wtrs.setTitle('2Waters')
In [49]: wtrs
Out[49]: <AtomGroup: 2Waters (6 atoms; active #0 of 2 coordsets)>
Storing data in AtomGroup¶
Now let’s get an atom group from a PDB file:
In [50]: structure = parsePDB('1p38')
In addition to what’s in a PDB file, you can store arbitrary atomic attributes
in AtomGroup
objects.
Set a new attribute¶
For the purposes of this example, we will manufacture atomic data by dividing the residue number of each atom by 10:
In [51]: myresnum = structure.getResnums() / 10.0
We will add this to the atom group using AtomGroup.setData()
method by passing a name for the attribute and the data:
In [52]: structure.setData('myresnum', myresnum)
We can check if a custom atomic attribute exists using
AtomGroup.isDataLabel()
method:
In [53]: structure.isDataLabel('myresnum')
Out[53]: True
Access subset of data¶
Custom attributes can be accessed from selections:
In [54]: calpha = structure.calpha
In [55]: calpha.getData('myresnum')
Out[55]:
array([ 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2, 1.3, 1.4,
1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5,
2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4, 3.5, 3.6,
3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7,
4.8, 4.9, 5. , 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8,
5.9, 6. , 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9,
7. , 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8. ,
8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9. , 9.1,
9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 10. , 10.1, 10.2,
10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11. , 11.1, 11.2, 11.3,
11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12. , 12.1, 12.2, 12.3, 12.4,
12.5, 12.6, 12.7, 12.8, 12.9, 13. , 13.1, 13.2, 13.3, 13.4, 13.5,
13.6, 13.7, 13.8, 13.9, 14. , 14.1, 14.2, 14.3, 14.4, 14.5, 14.6,
14.7, 14.8, 14.9, 15. , 15.1, 15.2, 15.3, 15.4, 15.5, 15.6, 15.7,
15.8, 15.9, 16. , 16.1, 16.2, 16.3, 16.4, 16.5, 16.6, 16.7, 16.8,
16.9, 17. , 17.1, 17.2, 17.3, 17.4, 17.5, 17.6, 17.7, 17.8, 17.9,
18. , 18.1, 18.2, 18.3, 18.4, 18.5, 18.6, 18.7, 18.8, 18.9, 19. ,
19.1, 19.2, 19.3, 19.4, 19.5, 19.6, 19.7, 19.8, 19.9, 20. , 20.1,
20.2, 20.3, 20.4, 20.5, 20.6, 20.7, 20.8, 20.9, 21. , 21.1, 21.2,
21.3, 21.4, 21.5, 21.6, 21.7, 21.8, 21.9, 22. , 22.1, 22.2, 22.3,
22.4, 22.5, 22.6, 22.7, 22.8, 22.9, 23. , 23.1, 23.2, 23.3, 23.4,
23.5, 23.6, 23.7, 23.8, 23.9, 24. , 24.1, 24.2, 24.3, 24.4, 24.5,
24.6, 24.7, 24.8, 24.9, 25. , 25.1, 25.2, 25.3, 25.4, 25.5, 25.6,
25.7, 25.8, 25.9, 26. , 26.1, 26.2, 26.3, 26.4, 26.5, 26.6, 26.7,
26.8, 26.9, 27. , 27.1, 27.2, 27.3, 27.4, 27.5, 27.6, 27.7, 27.8,
27.9, 28. , 28.1, 28.2, 28.3, 28.4, 28.5, 28.6, 28.7, 28.8, 28.9,
29. , 29.1, 29.2, 29.3, 29.4, 29.5, 29.6, 29.7, 29.8, 29.9, 30. ,
30.1, 30.2, 30.3, 30.4, 30.5, 30.6, 30.7, 30.8, 30.9, 31. , 31.1,
31.2, 31.3, 31.4, 31.5, 31.6, 31.7, 31.8, 31.9, 32. , 32.1, 32.2,
32.3, 32.4, 32.5, 32.6, 32.7, 32.8, 32.9, 33. , 33.1, 33.2, 33.3,
33.4, 33.5, 33.6, 33.7, 33.8, 33.9, 34. , 34.1, 34.2, 34.3, 34.4,
34.5, 34.6, 34.7, 34.8, 34.9, 35. , 35.1, 35.2, 35.3, 35.4])
Make selections¶
Custom atomic attributes can be used in selections:
In [56]: mysel = structure.select('0 < myresnum and myresnum < 10')
In [57]: mysel
Out[57]: <Selection: '0 < myresnum and myresnum < 10' from 1p38 (788 atoms)>
This gives the same result as the following selection:
In [58]: structure.select('0 < resnum and resnum < 100') == mysel
Out[58]: True
Save attributes¶
It is not possible to save custom attributes in PDB files, but
saveAtoms()
function can be used them to save in disk for later use:
In [59]: saveAtoms(structure)
Out[59]: '1p38.ag.npz'
Let’s load it using loadAtoms()
function:
In [60]: structure = loadAtoms('1p38.ag.npz')
In [61]: structure.getData('myresnum')
Out[61]: array([ 0.4, 0.4, 0.4, ..., 77.1, 77.3, 77.6])
Delete an attribute¶
Finally, when done with an attribute, it can be deleted using
AtomGroup.delData()
method:
In [62]: structure.delData('myresnum')
Out[62]: array([ 0.4, 0.4, 0.4, ..., 77.1, 77.3, 77.6])