BondList
#
- class biotite.structure.BondList(atom_count, bonds=None)[source]#
Bases:
Copyable
A bond list stores indices of atoms (usually of an
AtomArray
orAtomArrayStack
) that form chemical bonds together with the type (or order) of the bond.Internally the bonds are stored as n x 3
ndarray
. For each row, the first column specifies the index of the first atom, the second column the index of the second atom involved in the bond. The third column stores an integer that is interpreted as member of the theBondType
enum, that specifies the order of the bond.When indexing a
BondList
, the index is not forwarded to the internalndarray
. Instead the indexing behavior is consistent with indexing anAtomArray
orAtomArrayStack
: Bonds with at least one atom index that is not covered by the index are removed, atom indices that occur after an uncovered atom index move up. Effectively, this means that after indexing anAtomArray
and aBondList
with the same index, the atom indices in theBondList
will still point to the same atoms in theAtomArray
. Indexing aBondList
with a single integer is equivalent to callingget_bonds()
.The same consistency applies to adding
BondList
instances via the ‘+’ operator: The atom indices of the secondBondList
are increased by the atom count of the firstBondList
and then bothBondList
objects are merged.- Parameters:
- atom_countint
A positive integer, that specifies the number of atoms the
BondList
refers to (usually the length of an atom array (stack)). Effectively, this value is the exclusive maximum for the indices stored in theBondList
.- bondsndarray, shape=(n,2) or shape=(n,3), dtype=int, optional
This array contains the indices of atoms which are bonded: For each row, the first column specifies the first atom, the second row the second atom involved in a chemical bond. If an n x 3 array is provided, the additional column specifies a
BondType
instead ofBondType.ANY
. By default, the createdBondList
is empty.
Notes
When initially providing the bonds as
ndarray
, the input is sanitized: Redundant bonds are removed, and each bond entry is sorted so that the lower one of the two atom indices is in the first column. If a bond appears multiple times with different bond types, the first bond takes precedence.Examples
Construct a
BondList
, where a central atom (index 1) is connected to three other atoms (index 0, 3 and 4):>>> bond_list = BondList(5, np.array([(1,0),(1,3),(1,4)])) >>> print(bond_list) [[0 1 0] [1 3 0] [1 4 0]]
Remove the first atom (index 0) via indexing: The bond containing index 0 is removed, since the corresponding atom does not exist anymore. Since all other atoms move up in their position, the indices in the bond list are decreased by one:
>>> bond_list = bond_list[1:] >>> print(bond_list) [[0 2 0] [0 3 0]]
BondList
objects can be associated to anAtomArray
orAtomArrayStack
. The following snippet shows this for a benzene molecule:>>> benzene = AtomArray(12) >>> # Omit filling most required annotation categories for brevity >>> benzene.atom_name = np.array( ... ["C1", "C2", "C3", "C4", "C5", "C6", "H1", "H2", "H3", "H4", "H5", "H6"] ... ) >>> benzene.bonds = BondList( ... benzene.array_length(), ... np.array([ ... # Bonds between carbon atoms in the ring ... (0, 1, BondType.AROMATIC_SINGLE), ... (1, 2, BondType.AROMATIC_DOUBLE), ... (2, 3, BondType.AROMATIC_SINGLE), ... (3, 4, BondType.AROMATIC_DOUBLE), ... (4, 5, BondType.AROMATIC_SINGLE), ... (5, 0, BondType.AROMATIC_DOUBLE), ... # Bonds between carbon and hydrogen ... (0, 6, BondType.SINGLE), ... (1, 7, BondType.SINGLE), ... (2, 8, BondType.SINGLE), ... (3, 9, BondType.SINGLE), ... (4, 10, BondType.SINGLE), ... (5, 11, BondType.SINGLE), ... ]) ... ) >>> for i, j, bond_type in benzene.bonds.as_array(): ... print( ... f"{BondType(bond_type).name} bond between " ... f"{benzene.atom_name[i]} and {benzene.atom_name[j]}" ... ) AROMATIC_SINGLE bond between C1 and C2 AROMATIC_DOUBLE bond between C2 and C3 AROMATIC_SINGLE bond between C3 and C4 AROMATIC_DOUBLE bond between C4 and C5 AROMATIC_SINGLE bond between C5 and C6 AROMATIC_DOUBLE bond between C1 and C6 SINGLE bond between C1 and H1 SINGLE bond between C2 and H2 SINGLE bond between C3 and H3 SINGLE bond between C4 and H4 SINGLE bond between C5 and H5 SINGLE bond between C6 and H6
Obtain the bonded atoms for the \(C_1\):
>>> bonds, types = benzene.bonds.get_bonds(0) >>> print(bonds) [1 5 6] >>> print(types) [5 6 1] >>> print(f"C1 is bonded to {', '.join(benzene.atom_name[bonds])}") C1 is bonded to C2, C6, H1
Cut the benzene molecule in half. Although the first half of the atoms are missing the indices of the cropped
BondList
still represents the bonds of the remaining atoms:>>> half_benzene = benzene[ ... np.isin(benzene.atom_name, ["C4", "C5", "C6", "H4", "H5", "H6"]) ... ] >>> for i, j, bond_type in half_benzene.bonds.as_array(): ... print( ... f"{BondType(bond_type).name} bond between " ... f"{half_benzene.atom_name[i]} and {half_benzene.atom_name[j]}" ... ) AROMATIC_DOUBLE bond between C4 and C5 AROMATIC_SINGLE bond between C5 and C6 SINGLE bond between C4 and H4 SINGLE bond between C5 and H5 SINGLE bond between C6 and H6
- add_bond(atom_index1, atom_index2, bond_type=BondType.ANY)#
Add a bond to the
BondList
.If the bond is already existent, only the bond type is updated.
- Parameters:
- atom_index1, atom_index2int
The indices of the atoms to create a bond for.
- bond_typeBondType or int, optional
The type of the bond. Default is
BondType.ANY
.
- adjacency_matrix(bond_list)#
Represent this
BondList
as adjacency matrix.The adjacency matrix is a quadratic matrix with boolean values according to
\[\begin{split}M_{i,j} = \begin{cases} \text{True}, & \text{if } \text{Atom}_i \text{ and } \text{Atom}_j \text{ form a bond} \\ \text{False}, & \text{otherwise} \end{cases}.\end{split}\]- Returns:
- matrixndarray, dtype=bool, shape=(n,n)
The created adjacency matrix.
Examples
>>> # BondList for formaldehyde >>> bond_list = BondList( ... 4, ... np.array([ ... # Bond between carbon and oxygen ... (0, 1, BondType.DOUBLE), ... # Bonds between carbon and hydrogen ... (0, 2, BondType.SINGLE), ... (0, 3, BondType.SINGLE), ... ]) ... ) >>> print(bond_list.adjacency_matrix()) [[False True True True] [ True False False False] [ True False False False] [ True False False False]]
- as_array()#
Obtain a copy of the internal
ndarray
.- Returns:
- arrayndarray, shape=(n,3), dtype=np.uint32
Copy of the internal
ndarray
. For each row, the first column specifies the index of the first atom, the second column the index of the second atom involved in the bond. The third column stores theBondType
.
- as_graph()#
Obtain a graph representation of the
BondList
.- Returns:
- bond_setGraph
A NetworkX
Graph
. The atom indices are nodes, the bonds are edges. Each edge has a"bond_type"
attribute containing theBondType
.
Examples
>>> bond_list = BondList(5, np.array([(1,0,2), (1,3,1), (1,4,1)])) >>> graph = bond_list.as_graph() >>> print(graph.nodes) [0, 1, 3, 4] >>> print(graph.edges) [(0, 1), (1, 3), (1, 4)] >>> for i, j in graph.edges: ... print(i, j, graph.get_edge_data(i, j)) 0 1 {'bond_type': <BondType.DOUBLE: 2>} 1 3 {'bond_type': <BondType.SINGLE: 1>} 1 4 {'bond_type': <BondType.SINGLE: 1>}
- as_set()#
Obtain a set representation of the
BondList
.- Returns:
- bond_setset of tuple(int, int, int)
A set of tuples. Each tuple represents one bond: The first integer represents the first atom, the second integer represents the second atom, the third integer represents the
BondType
.
- bond_type_matrix(bond_list)#
Represent this
BondList
as a matrix depicting the bond type.The matrix is a quadratic matrix:
\[\begin{split}M_{i,j} = \begin{cases} \text{BondType}_{ij}, & \text{if } \text{Atom}_i \text{ and } \text{Atom}_j \text{ form a bond} \\ -1, & \text{otherwise} \end{cases}.\end{split}\]- Returns:
- matrixndarray, dtype=bool, shape=(n,n)
The created bond type matrix.
Examples
>>> # BondList for formaldehyde >>> bond_list = BondList( ... 4, ... np.array([ ... # Bond between carbon and oxygen ... (0, 1, BondType.DOUBLE), ... # Bonds between carbon and hydrogen ... (0, 2, BondType.SINGLE), ... (0, 3, BondType.SINGLE), ... ]) ... ) >>> print(bond_list.bond_type_matrix()) [[-1 2 1 1] [ 2 -1 -1 -1] [ 1 -1 -1 -1] [ 1 -1 -1 -1]]
- static concatenate(bonds_lists)#
Concatenate multiple
BondList
objects into a singleBondList
, respectively.- Parameters:
- bonds_listsiterable object of BondList
The bond lists to be concatenated.
- Returns:
- concatenated_bondsBondList
The concatenated bond lists.
Examples
>>> bonds1 = BondList(2, np.array([(0, 1)])) >>> bonds2 = BondList(3, np.array([(0, 1), (0, 2)])) >>> merged_bonds = BondList.concatenate([bonds1, bonds2]) >>> print(merged_bonds.get_atom_count()) 5 >>> print(merged_bonds.as_array()[:, :2]) [[0 1] [2 3] [2 4]]
- copy()#
Create a deep copy of this object.
- Returns:
- copy
A copy of this object.
- get_all_bonds()#
For each atom index, give the indices of the atoms bonded to this atom as well as the corresponding bond types.
- Returns:
- bondsnp.ndarray, dtype=np.uint32, shape=(n,k)
The indices of connected atoms. The first dimension represents the atoms, the second dimension represents the indices of atoms bonded to the respective atom. Atoms can have have different numbers of atoms bonded to them. Therefore, the length of the second dimension k is equal to the maximum number of bonds for an atom in this
BondList
. For atoms with less bonds, the corresponding entry in the array is padded with-1
values.- bond_typesnp.ndarray, dtype=np.uint32, shape=(n,k)
Array of integers, interpreted as
BondType
instances. This array specifies the bond type (or order) corresponding to the returned bonds. It uses the same-1
-padding.
Examples
>>> # BondList for benzene >>> bond_list = BondList( ... 12, ... np.array([ ... # Bonds between the carbon atoms in the ring ... (0, 1, BondType.AROMATIC_SINGLE), ... (1, 2, BondType.AROMATIC_DOUBLE), ... (2, 3, BondType.AROMATIC_SINGLE), ... (3, 4, BondType.AROMATIC_DOUBLE), ... (4, 5, BondType.AROMATIC_SINGLE), ... (5, 0, BondType.AROMATIC_DOUBLE), ... # Bonds between carbon and hydrogen ... (0, 6, BondType.SINGLE), ... (1, 7, BondType.SINGLE), ... (2, 8, BondType.SINGLE), ... (3, 9, BondType.SINGLE), ... (4, 10, BondType.SINGLE), ... (5, 11, BondType.SINGLE), ... ]) ... ) >>> bonds, types = bond_list.get_all_bonds() >>> print(bonds) [[ 1 5 6] [ 0 2 7] [ 1 3 8] [ 2 4 9] [ 3 5 10] [ 4 0 11] [ 0 -1 -1] [ 1 -1 -1] [ 2 -1 -1] [ 3 -1 -1] [ 4 -1 -1] [ 5 -1 -1]] >>> print(types) [[ 5 6 1] [ 5 6 1] [ 6 5 1] [ 5 6 1] [ 6 5 1] [ 5 6 1] [ 1 -1 -1] [ 1 -1 -1] [ 1 -1 -1] [ 1 -1 -1] [ 1 -1 -1] [ 1 -1 -1]] >>> for i in range(bond_list.get_atom_count()): ... bonds_for_atom = bonds[i] ... # Remove trailing '-1' values ... bonds_for_atom = bonds_for_atom[bonds_for_atom != -1] ... print(f"{i}: {bonds_for_atom}") 0: [1 5 6] 1: [0 2 7] 2: [1 3 8] 3: [2 4 9] 4: [ 3 5 10] 5: [ 4 0 11] 6: [0] 7: [1] 8: [2] 9: [3] 10: [4] 11: [5]
- get_atom_count()#
Get the atom count.
- Returns:
- atom_countint
The atom count.
- get_bond_count()#
Get the amount of bonds.
- Returns:
- bond_countint
The amount of bonds. This is equal to the length of the internal
ndarray
containing the bonds.
- get_bonds(atom_index)#
Obtain the indices of the atoms bonded to the atom with the given index as well as the corresponding bond types.
- Parameters:
- atom_indexint
The index of the atom to get the bonds for.
- Returns:
- bondsnp.ndarray, dtype=np.uint32, shape=(k,)
The indices of connected atoms.
- bond_typesnp.ndarray, dtype=np.uint8, shape=(k,)
Array of integers, interpreted as
BondType
instances. This array specifies the type (or order) of the bonds to the connected atoms.
Examples
>>> bond_list = BondList(5, np.array([(1,0),(1,3),(1,4)])) >>> bonds, types = bond_list.get_bonds(1) >>> print(bonds) [0 3 4]
- merge(bond_list)#
Merge another
BondList
with this instance into a new object. If a bond appears in bothBondList
’s, theBondType
from the given bond_list takes precedence.The internal
ndarray
instances containg the bonds are simply concatenated and the new atom count is the maximum of both bond lists.- Parameters:
- bond_listBondList
This bond list is merged with this instance.
- Returns:
- bond_listBondList
The merged
BondList
.
Notes
This is not equal to using the + operator.
Examples
>>> bond_list1 = BondList(3, np.array([(0,1),(1,2)])) >>> bond_list2 = BondList(5, np.array([(2,3),(3,4)])) >>> merged_list = bond_list2.merge(bond_list1) >>> print(merged_list.get_atom_count()) 5 >>> print(merged_list) [[0 1 0] [1 2 0] [2 3 0] [3 4 0]]
The BondList given as parameter takes precedence:
>>> # Specifiy bond type to see where a bond is taken from >>> bond_list1 = BondList(4, np.array([ ... (0, 1, BondType.SINGLE), ... (1, 2, BondType.SINGLE) ... ])) >>> bond_list2 = BondList(4, np.array([ ... (1, 2, BondType.DOUBLE), # This one is a duplicate ... (2, 3, BondType.DOUBLE) ... ])) >>> merged_list = bond_list2.merge(bond_list1) >>> print(merged_list) [[0 1 1] [1 2 1] [2 3 2]]
- offset_indices(offset)#
Increase all atom indices in the
BondList
by the given offset.Implicitly this increases the atom count.
- Parameters:
- offsetint
The atom indices are increased by this value. Must be positive.
Examples
>>> bond_list = BondList(5, np.array([(1,0),(1,3),(1,4)])) >>> print(bond_list) [[0 1 0] [1 3 0] [1 4 0]] >>> bond_list.offset_indices(2) >>> print(bond_list) [[2 3 0] [3 5 0] [3 6 0]]
- remove_aromaticity()#
Remove aromaticity from the bond types.
BondType.AROMATIC_{ORDER}
is converted intoBondType.{ORDER}
.Examples
>>> bond_list = BondList(3) >>> bond_list.add_bond(0, 1, BondType.AROMATIC_SINGLE) >>> bond_list.add_bond(1, 2, BondType.AROMATIC_DOUBLE) >>> bond_list.remove_aromaticity() >>> for i, j, bond_type in bond_list.as_array(): ... print(i, j, BondType(bond_type).name) 0 1 SINGLE 1 2 DOUBLE
- remove_bond(atom_index1, atom_index2)#
Remove a bond from the
BondList
.If the bond is not existent in the
BondList
, nothing happens.- Parameters:
- atom_index1, atom_index2int
The indices of the atoms whose bond should be removed.
- remove_bond_order()#
Convert all bonds to
BondType.ANY
.
- remove_bonds(bond_list)#
Remove multiple bonds from the
BondList
.All bonds present in bond_list are removed from this instance. If a bond is not existent in this instance, nothing happens. Only the bond indices, not the bond types, are relevant for this.
- Parameters:
- bond_listBondList
The bonds in bond_list are removed from this instance.