biotite 0.38.0__cp310-cp310-macosx_11_0_arm64.whl → 0.40.0__cp310-cp310-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of biotite might be problematic. Click here for more details.
- biotite/__init__.py +3 -3
- biotite/application/application.py +33 -28
- biotite/application/dssp/app.py +18 -18
- biotite/application/sra/__init__.py +5 -0
- biotite/application/sra/app.py +337 -55
- biotite/database/entrez/__init__.py +2 -1
- biotite/database/entrez/check.py +14 -3
- biotite/database/entrez/download.py +20 -13
- biotite/database/entrez/key.py +44 -0
- biotite/database/entrez/query.py +38 -34
- biotite/database/pubchem/query.py +44 -44
- biotite/database/rcsb/download.py +19 -14
- biotite/database/rcsb/query.py +46 -46
- biotite/sequence/align/__init__.py +5 -1
- biotite/sequence/align/banded.c +1408 -1025
- biotite/sequence/align/banded.cpython-310-darwin.so +0 -0
- biotite/sequence/align/buckets.py +69 -0
- biotite/sequence/align/cigar.py +389 -0
- biotite/sequence/align/kmeralphabet.c +3220 -2850
- biotite/sequence/align/kmeralphabet.cpython-310-darwin.so +0 -0
- biotite/sequence/align/kmersimilarity.c +713 -663
- biotite/sequence/align/kmersimilarity.cpython-310-darwin.so +0 -0
- biotite/sequence/align/kmertable.cpp +68398 -0
- biotite/sequence/align/kmertable.cpython-310-darwin.so +0 -0
- biotite/sequence/align/localgapped.c +1507 -1074
- biotite/sequence/align/localgapped.cpython-310-darwin.so +0 -0
- biotite/sequence/align/localungapped.c +1143 -833
- biotite/sequence/align/localungapped.cpython-310-darwin.so +0 -0
- biotite/sequence/align/multiple.c +1569 -1092
- biotite/sequence/align/multiple.cpython-310-darwin.so +0 -0
- biotite/sequence/align/pairwise.c +1612 -1212
- biotite/sequence/align/pairwise.cpython-310-darwin.so +0 -0
- biotite/sequence/align/permutation.c +33259 -0
- biotite/sequence/align/permutation.cpython-310-darwin.so +0 -0
- biotite/sequence/align/primes.txt +821 -0
- biotite/sequence/align/{kmertable.c → selector.c} +9129 -16497
- biotite/sequence/align/selector.cpython-310-darwin.so +0 -0
- biotite/sequence/align/tracetable.c +685 -646
- biotite/sequence/align/tracetable.cpython-310-darwin.so +0 -0
- biotite/sequence/codec.c +1159 -841
- biotite/sequence/codec.cpython-310-darwin.so +0 -0
- biotite/sequence/graphics/alignment.py +212 -2
- biotite/sequence/io/genbank/annotation.py +11 -11
- biotite/sequence/phylo/nj.c +684 -636
- biotite/sequence/phylo/nj.cpython-310-darwin.so +0 -0
- biotite/sequence/phylo/tree.c +970 -673
- biotite/sequence/phylo/tree.cpython-310-darwin.so +0 -0
- biotite/sequence/phylo/upgma.c +672 -626
- biotite/sequence/phylo/upgma.cpython-310-darwin.so +0 -0
- biotite/structure/__init__.py +1 -1
- biotite/structure/atoms.py +1 -1
- biotite/structure/basepairs.py +7 -12
- biotite/structure/bonds.c +3861 -3749
- biotite/structure/bonds.cpython-310-darwin.so +0 -0
- biotite/structure/celllist.c +727 -707
- biotite/structure/celllist.cpython-310-darwin.so +0 -0
- biotite/structure/charges.c +1561 -1560
- biotite/structure/charges.cpython-310-darwin.so +0 -0
- biotite/structure/filter.py +30 -37
- biotite/structure/info/__init__.py +5 -8
- biotite/structure/info/atoms.py +25 -67
- biotite/structure/info/bonds.py +46 -100
- biotite/structure/info/ccd/README.rst +8 -0
- biotite/structure/info/ccd/amino_acids.txt +1646 -0
- biotite/structure/info/ccd/carbohydrates.txt +1133 -0
- biotite/structure/info/ccd/components.bcif +0 -0
- biotite/structure/info/ccd/nucleotides.txt +797 -0
- biotite/structure/info/ccd.py +95 -0
- biotite/structure/info/groups.py +90 -0
- biotite/structure/info/masses.py +21 -20
- biotite/structure/info/misc.py +11 -22
- biotite/structure/info/standardize.py +17 -12
- biotite/structure/io/__init__.py +2 -4
- biotite/structure/io/ctab.py +1 -1
- biotite/structure/io/general.py +37 -43
- biotite/structure/io/mmtf/__init__.py +3 -0
- biotite/structure/io/mmtf/convertarray.c +528 -365
- biotite/structure/io/mmtf/convertarray.cpython-310-darwin.so +0 -0
- biotite/structure/io/mmtf/convertfile.c +725 -676
- biotite/structure/io/mmtf/convertfile.cpython-310-darwin.so +0 -0
- biotite/structure/io/mmtf/decode.c +1070 -754
- biotite/structure/io/mmtf/decode.cpython-310-darwin.so +0 -0
- biotite/structure/io/mmtf/encode.c +727 -677
- biotite/structure/io/mmtf/encode.cpython-310-darwin.so +0 -0
- biotite/structure/io/mmtf/file.py +34 -26
- biotite/structure/io/npz/__init__.py +3 -0
- biotite/structure/io/npz/file.py +21 -18
- biotite/structure/io/pdb/__init__.py +3 -3
- biotite/structure/io/pdb/file.py +72 -70
- biotite/structure/io/pdb/hybrid36.c +540 -478
- biotite/structure/io/pdb/hybrid36.cpython-310-darwin.so +0 -0
- biotite/structure/io/pdbqt/file.py +82 -68
- biotite/structure/io/pdbx/__init__.py +13 -6
- biotite/structure/io/pdbx/bcif.py +649 -0
- biotite/structure/io/pdbx/cif.py +1028 -0
- biotite/structure/io/pdbx/component.py +243 -0
- biotite/structure/io/pdbx/convert.py +707 -359
- biotite/structure/io/pdbx/encoding.c +112813 -0
- biotite/structure/io/pdbx/encoding.cpython-310-darwin.so +0 -0
- biotite/structure/io/pdbx/error.py +14 -0
- biotite/structure/io/pdbx/legacy.py +267 -0
- biotite/structure/molecules.py +151 -151
- biotite/structure/residues.py +40 -40
- biotite/structure/sasa.c +713 -644
- biotite/structure/sasa.cpython-310-darwin.so +0 -0
- biotite/structure/superimpose.py +158 -115
- biotite/visualize.py +9 -11
- {biotite-0.38.0.dist-info → biotite-0.40.0.dist-info}/METADATA +2 -2
- {biotite-0.38.0.dist-info → biotite-0.40.0.dist-info}/RECORD +112 -102
- {biotite-0.38.0.dist-info → biotite-0.40.0.dist-info}/WHEEL +1 -1
- biotite/structure/info/amino_acids.json +0 -1556
- biotite/structure/info/amino_acids.py +0 -42
- biotite/structure/info/carbohydrates.json +0 -1122
- biotite/structure/info/carbohydrates.py +0 -39
- biotite/structure/info/intra_bonds.msgpack +0 -0
- biotite/structure/info/link_types.msgpack +0 -1
- biotite/structure/info/nucleotides.json +0 -772
- biotite/structure/info/nucleotides.py +0 -39
- biotite/structure/info/residue_masses.msgpack +0 -0
- biotite/structure/info/residue_names.msgpack +0 -3
- biotite/structure/info/residues.msgpack +0 -0
- biotite/structure/io/pdbx/file.py +0 -652
- {biotite-0.38.0.dist-info → biotite-0.40.0.dist-info}/LICENSE.rst +0 -0
- {biotite-0.38.0.dist-info → biotite-0.40.0.dist-info}/top_level.txt +0 -0
|
Binary file
|
biotite/structure/superimpose.py
CHANGED
|
@@ -8,24 +8,86 @@ This module provides functions for structure superimposition.
|
|
|
8
8
|
|
|
9
9
|
__name__ = "biotite.structure"
|
|
10
10
|
__author__ = "Patrick Kunzmann, Claude J. Rogers"
|
|
11
|
-
__all__ = ["superimpose", "superimpose_apply"]
|
|
11
|
+
__all__ = ["superimpose", "superimpose_apply", "AffineTransformation"]
|
|
12
|
+
|
|
12
13
|
|
|
13
14
|
import numpy as np
|
|
14
15
|
from .atoms import coord
|
|
15
16
|
from .geometry import centroid
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
class AffineTransformation:
|
|
20
|
+
"""
|
|
21
|
+
An affine transformation, consisting of translations and a rotation.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
center_translation : ndarray, shape=(3,) or shape=(m,3), dtype=float
|
|
26
|
+
The translation vector for moving the centroid into the
|
|
27
|
+
origin.
|
|
28
|
+
rotation : ndarray, shape=(3,3) or shape=(m,3,3), dtype=float
|
|
29
|
+
The rotation matrix.
|
|
30
|
+
target_translation : ndarray, shape=(m,3), dtype=float
|
|
31
|
+
The translation vector for moving the structure onto the
|
|
32
|
+
fixed one.
|
|
33
|
+
|
|
34
|
+
Attributes
|
|
35
|
+
----------
|
|
36
|
+
center_translation, rotation, target_translation : ndarray
|
|
37
|
+
Same as the parameters.
|
|
38
|
+
"""
|
|
39
|
+
def __init__(self, center_translation, rotation, target_translation):
|
|
40
|
+
self.center_translation = center_translation
|
|
41
|
+
self.rotation = rotation
|
|
42
|
+
self.target_translation = target_translation
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def apply(self, atoms):
|
|
46
|
+
"""
|
|
47
|
+
Apply this transformation on the given structure.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
atoms : AtomArray or AtomArrayStack or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
|
|
52
|
+
The structure to apply the transformation on.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
transformed : AtomArray or AtomArrayStack or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
|
|
57
|
+
A copy of the `atoms` structure,
|
|
58
|
+
with transformations applied.
|
|
59
|
+
Only coordinates are returned, if coordinates were given in
|
|
60
|
+
`atoms`.
|
|
61
|
+
"""
|
|
62
|
+
mobile_coord = coord(atoms)
|
|
63
|
+
original_shape = mobile_coord.shape
|
|
64
|
+
mobile_coord = _reshape_to_3d(mobile_coord)
|
|
65
|
+
|
|
66
|
+
superimposed_coord = mobile_coord.copy()
|
|
67
|
+
superimposed_coord += self.center_translation[:, np.newaxis, :]
|
|
68
|
+
superimposed_coord = _multi_matmul(self.rotation, superimposed_coord)
|
|
69
|
+
superimposed_coord += self.target_translation[:, np.newaxis, :]
|
|
70
|
+
|
|
71
|
+
superimposed_coord = superimposed_coord.reshape(original_shape)
|
|
72
|
+
if isinstance(atoms, np.ndarray):
|
|
73
|
+
return superimposed_coord
|
|
74
|
+
else:
|
|
75
|
+
superimposed = atoms.copy()
|
|
76
|
+
superimposed.coord = superimposed_coord
|
|
77
|
+
return superimposed
|
|
78
|
+
|
|
79
|
+
|
|
18
80
|
def superimpose(fixed, mobile, atom_mask=None):
|
|
19
81
|
"""
|
|
20
82
|
Superimpose structures onto a fixed structure.
|
|
21
|
-
|
|
83
|
+
|
|
22
84
|
The superimposition is performed using the Kabsch algorithm
|
|
23
85
|
:footcite:`Kabsch1976, Kabsch1978`, so that the RMSD between the
|
|
24
86
|
superimposed and the fixed structure is minimized.
|
|
25
|
-
|
|
87
|
+
|
|
26
88
|
Parameters
|
|
27
89
|
----------
|
|
28
|
-
fixed : AtomArray, shape(n,) or ndarray, shape(n,), dtype=float
|
|
90
|
+
fixed : AtomArray, shape(n,) or AtomArrayStack, shape(m,n) or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
|
|
29
91
|
The fixed structure.
|
|
30
92
|
Alternatively coordinates can be given.
|
|
31
93
|
mobile: AtomArray, shape(n,) or AtomArrayStack, shape(m,n) or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
|
|
@@ -41,7 +103,7 @@ def superimpose(fixed, mobile, atom_mask=None):
|
|
|
41
103
|
on the covered atoms instead of all atoms.
|
|
42
104
|
The returned superimposed structure will contain all atoms
|
|
43
105
|
of the input structure, regardless of this parameter.
|
|
44
|
-
|
|
106
|
+
|
|
45
107
|
Returns
|
|
46
108
|
-------
|
|
47
109
|
fitted : AtomArray or AtomArrayStack or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
|
|
@@ -49,54 +111,43 @@ def superimpose(fixed, mobile, atom_mask=None):
|
|
|
49
111
|
superimposed on the fixed structure.
|
|
50
112
|
Only coordinates are returned, if coordinates were given in
|
|
51
113
|
`mobile`.
|
|
52
|
-
transformation :
|
|
53
|
-
|
|
54
|
-
`mobile`.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
The second element contains the rotation matrix.
|
|
59
|
-
The third element contains the translation vector for moving the
|
|
60
|
-
structure onto the fixed.
|
|
61
|
-
The three transformations are performed sequentially.
|
|
62
|
-
|
|
63
|
-
See Also
|
|
64
|
-
--------
|
|
65
|
-
superimpose_apply
|
|
66
|
-
|
|
114
|
+
transformation : AffineTransformation
|
|
115
|
+
This object contains the affine transformation(s) that were
|
|
116
|
+
applied on `mobile`.
|
|
117
|
+
:meth:`AffineTransformation.apply()` can be used to transform
|
|
118
|
+
another AtomArray in the same way.
|
|
119
|
+
|
|
67
120
|
Notes
|
|
68
121
|
-----
|
|
69
|
-
The `transformation`
|
|
70
|
-
|
|
71
|
-
:class:`AtomArray` in the same way.
|
|
72
|
-
This can come in handy, in case you want to superimpose two
|
|
122
|
+
The `transformation` can come in handy, in case you want to
|
|
123
|
+
superimpose two
|
|
73
124
|
structures with different amount of atoms.
|
|
74
125
|
Often the two structures need to be filtered in order to obtain the
|
|
75
126
|
same size and annotation arrays.
|
|
76
127
|
After superimposition the transformation can be applied on the
|
|
77
|
-
original structure using :
|
|
78
|
-
|
|
128
|
+
original structure using :meth:`AffineTransformation.apply()`.
|
|
129
|
+
|
|
79
130
|
References
|
|
80
131
|
----------
|
|
81
|
-
|
|
132
|
+
|
|
82
133
|
.. footbibliography::
|
|
83
|
-
|
|
134
|
+
|
|
84
135
|
Examples
|
|
85
136
|
--------
|
|
86
|
-
|
|
137
|
+
|
|
87
138
|
At first two models of a structure are taken and one of them is
|
|
88
139
|
randomly rotated/translated.
|
|
89
140
|
Consequently the RMSD is quite large:
|
|
90
|
-
|
|
141
|
+
|
|
91
142
|
>>> array1 = atom_array_stack[0]
|
|
92
143
|
>>> array2 = atom_array_stack[1]
|
|
93
144
|
>>> array2 = translate(array2, [1,2,3])
|
|
94
145
|
>>> array2 = rotate(array2, [1,2,3])
|
|
95
146
|
>>> print("{:.3f}".format(rmsd(array1, array2)))
|
|
96
147
|
11.260
|
|
97
|
-
|
|
148
|
+
|
|
98
149
|
RMSD decreases after superimposition of only CA atoms:
|
|
99
|
-
|
|
150
|
+
|
|
100
151
|
>>> array2_fit, transformation = superimpose(
|
|
101
152
|
... array1, array2, atom_mask=(array2.atom_name == "CA")
|
|
102
153
|
... )
|
|
@@ -110,95 +161,48 @@ def superimpose(fixed, mobile, atom_mask=None):
|
|
|
110
161
|
>>> print("{:.3f}".format(rmsd(array1, array2_fit)))
|
|
111
162
|
1.928
|
|
112
163
|
"""
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
mshape = m_coord.shape
|
|
117
|
-
mdim = m_coord.ndim
|
|
118
|
-
if f_coord.ndim != 2:
|
|
119
|
-
raise ValueError("Expected fixed array to be an AtomArray")
|
|
120
|
-
if mdim < 2:
|
|
121
|
-
raise ValueError(
|
|
122
|
-
"Expected mobile array to be an AtomArray or AtomArrayStack"
|
|
123
|
-
)
|
|
124
|
-
if mdim == 2:
|
|
125
|
-
# normalize inputs. Fixed coords has shape (n, 3)
|
|
126
|
-
# and mobile has shape (m, n, 3)
|
|
127
|
-
m_coord = m_coord[np.newaxis, ...]
|
|
128
|
-
|
|
129
|
-
nmodels = m_coord.shape[0]
|
|
130
|
-
if f_coord.shape[0] != m_coord.shape[1]:
|
|
131
|
-
raise ValueError(
|
|
132
|
-
f"Expected fixed array and mobile array to have the same number "
|
|
133
|
-
f"of atoms, but {f_coord.shape[0]} != {m_coord.shape[1]}"
|
|
134
|
-
)
|
|
164
|
+
# Bring coordinates into the same dimensionality
|
|
165
|
+
mob_coord = _reshape_to_3d(coord(mobile))
|
|
166
|
+
fix_coord = _reshape_to_3d(coord(fixed))
|
|
135
167
|
|
|
136
168
|
if atom_mask is not None:
|
|
137
169
|
# Implicitly this creates array copies
|
|
138
|
-
mob_filtered =
|
|
139
|
-
fix_filtered =
|
|
170
|
+
mob_filtered = mob_coord[:, atom_mask, :]
|
|
171
|
+
fix_filtered = fix_coord[:, atom_mask, :]
|
|
140
172
|
else:
|
|
141
|
-
mob_filtered = np.copy(
|
|
142
|
-
fix_filtered = np.copy(
|
|
143
|
-
|
|
173
|
+
mob_filtered = np.copy(mob_coord)
|
|
174
|
+
fix_filtered = np.copy(fix_coord)
|
|
175
|
+
|
|
144
176
|
# Center coordinates at (0,0,0)
|
|
145
177
|
mob_centroid = centroid(mob_filtered)
|
|
146
178
|
fix_centroid = centroid(fix_filtered)
|
|
147
|
-
mob_filtered
|
|
148
|
-
fix_filtered
|
|
149
|
-
|
|
150
|
-
s_coord = m_coord.copy() - mob_centroid[..., np.newaxis, :]
|
|
151
|
-
# Perform Kabsch algorithm for every model
|
|
152
|
-
transformations = [None] * nmodels
|
|
153
|
-
for i in range(nmodels):
|
|
154
|
-
rotation = _superimpose(fix_filtered, mob_filtered[i])
|
|
155
|
-
s_coord[i] = np.dot(rotation, s_coord[i].T).T
|
|
156
|
-
transformations[i] = (-mob_centroid[i], rotation, fix_centroid)
|
|
157
|
-
s_coord += fix_centroid
|
|
158
|
-
|
|
159
|
-
if isinstance(mobile, np.ndarray):
|
|
160
|
-
superimposed = s_coord.reshape(mshape)
|
|
161
|
-
else:
|
|
162
|
-
superimposed = mobile.copy()
|
|
163
|
-
superimposed.coord = s_coord.reshape(mshape)
|
|
179
|
+
mob_centered_filtered = mob_filtered - mob_centroid[:, np.newaxis, :]
|
|
180
|
+
fix_centered_filtered = fix_filtered - fix_centroid[:, np.newaxis, :]
|
|
164
181
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
rotation = _get_rotation_matrices(
|
|
183
|
+
fix_centered_filtered, mob_centered_filtered
|
|
184
|
+
)
|
|
185
|
+
transform = AffineTransformation(-mob_centroid, rotation, fix_centroid)
|
|
186
|
+
return transform.apply(mobile), transform
|
|
169
187
|
|
|
170
188
|
|
|
171
|
-
def
|
|
172
|
-
"""
|
|
173
|
-
Perform the Kabsch algorithm using only the coordinates.
|
|
189
|
+
def superimpose_apply(atoms, transformation):
|
|
174
190
|
"""
|
|
175
|
-
|
|
176
|
-
y = mob_centered
|
|
177
|
-
x = fix_centered
|
|
178
|
-
# Calculate covariance matrix
|
|
179
|
-
cov = np.dot(x.T, y)
|
|
180
|
-
v, s, w = np.linalg.svd(cov)
|
|
181
|
-
# Remove possibility of reflected atom coordinates
|
|
182
|
-
if np.linalg.det(v) * np.linalg.det(w) < 0:
|
|
183
|
-
v[:,-1] *= -1
|
|
184
|
-
rotation = np.dot(v,w)
|
|
185
|
-
return rotation
|
|
191
|
+
Superimpose structures using a given :class:`AffineTransformation`.
|
|
186
192
|
|
|
193
|
+
The :class:`AffineTransformation` can be obtained by prior
|
|
194
|
+
superimposition.
|
|
195
|
+
|
|
196
|
+
DEPRECATED: Use :func:`AffineTransformation.apply()` instead.
|
|
187
197
|
|
|
188
|
-
def superimpose_apply(atoms, transformation):
|
|
189
|
-
"""
|
|
190
|
-
Superimpose structures using a given transformation tuple.
|
|
191
|
-
|
|
192
|
-
The transformation tuple is obtained by prior superimposition.
|
|
193
|
-
|
|
194
198
|
Parameters
|
|
195
199
|
----------
|
|
196
200
|
atoms : AtomArray or ndarray, shape(n,), dtype=float
|
|
197
201
|
The structure to apply the transformation on.
|
|
198
202
|
Alternatively coordinates can be given.
|
|
199
|
-
transformation:
|
|
200
|
-
The transformation
|
|
201
|
-
|
|
203
|
+
transformation: AffineTransformation
|
|
204
|
+
The transformation, obtained by :func:`superimpose()`.
|
|
205
|
+
|
|
202
206
|
Returns
|
|
203
207
|
-------
|
|
204
208
|
fitted : AtomArray or AtomArrayStack
|
|
@@ -206,20 +210,59 @@ def superimpose_apply(atoms, transformation):
|
|
|
206
210
|
with transformations applied.
|
|
207
211
|
Only coordinates are returned, if coordinates were given in
|
|
208
212
|
`atoms`.
|
|
209
|
-
|
|
213
|
+
|
|
210
214
|
See Also
|
|
211
215
|
--------
|
|
212
216
|
superimpose
|
|
213
217
|
"""
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
218
|
+
return transformation.apply(atoms)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _reshape_to_3d(coord):
|
|
222
|
+
"""
|
|
223
|
+
Reshape the coordinate array to 3D, if it is 2D.
|
|
224
|
+
"""
|
|
225
|
+
if coord.ndim < 2:
|
|
226
|
+
raise ValueError(
|
|
227
|
+
"Coordinates must be at least two-dimensional"
|
|
228
|
+
)
|
|
229
|
+
if coord.ndim == 2:
|
|
230
|
+
return coord[np.newaxis, ...]
|
|
231
|
+
elif coord.ndim == 3:
|
|
232
|
+
return coord
|
|
222
233
|
else:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
234
|
+
raise ValueError(
|
|
235
|
+
"Coordinates must be at most three-dimensional"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _get_rotation_matrices(fixed, mobile):
|
|
240
|
+
"""
|
|
241
|
+
Get the rotation matrices to superimpose the given mobile
|
|
242
|
+
coordinates into the given fixed coordinates, minimizing the RMSD.
|
|
243
|
+
|
|
244
|
+
Uses the *Kabsch* algorithm.
|
|
245
|
+
Both sets of coordinates must already be centered at origin.
|
|
246
|
+
"""
|
|
247
|
+
# Calculate cross-covariance matrices
|
|
248
|
+
cov = np.sum(fixed[:,:,:,np.newaxis] * mobile[:,:,np.newaxis,:], axis=1)
|
|
249
|
+
v, s, w = np.linalg.svd(cov)
|
|
250
|
+
# Remove possibility of reflected atom coordinates
|
|
251
|
+
reflected_mask = (np.linalg.det(v) * np.linalg.det(w) < 0)
|
|
252
|
+
v[reflected_mask, :, -1] *= -1
|
|
253
|
+
matrices = np.matmul(v, w)
|
|
254
|
+
return matrices
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _multi_matmul(matrices, vectors):
|
|
258
|
+
"""
|
|
259
|
+
Calculate the matrix multiplication of m matrices
|
|
260
|
+
with m x n vectors.
|
|
261
|
+
"""
|
|
262
|
+
return np.transpose(
|
|
263
|
+
np.matmul(
|
|
264
|
+
matrices,
|
|
265
|
+
np.transpose(vectors, axes=(0, 2, 1))
|
|
266
|
+
),
|
|
267
|
+
axes=(0, 2, 1)
|
|
268
|
+
)
|
biotite/visualize.py
CHANGED
|
@@ -35,7 +35,7 @@ def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
|
|
|
35
35
|
Instead of having the font size fixed in 'pt', the size of the text
|
|
36
36
|
scales to the specied width/height and adapts to changes in the
|
|
37
37
|
plot's width/height.
|
|
38
|
-
The scaling can be proportional or non-proportional, depending
|
|
38
|
+
The scaling can be proportional or non-proportional, depending
|
|
39
39
|
the `mode`.
|
|
40
40
|
|
|
41
41
|
Parameters
|
|
@@ -75,7 +75,7 @@ def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
|
|
|
75
75
|
This behavior is not equal for all initial font sizes (in 'pt'),
|
|
76
76
|
the boundaries for an initial size of 1 'pt' seem to be most exact.
|
|
77
77
|
"""
|
|
78
|
-
from matplotlib.transforms import Bbox
|
|
78
|
+
from matplotlib.transforms import Bbox, Affine2D
|
|
79
79
|
from matplotlib.patheffects import AbstractPathEffect
|
|
80
80
|
|
|
81
81
|
class TextScaler(AbstractPathEffect):
|
|
@@ -98,7 +98,7 @@ def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
|
|
|
98
98
|
raise
|
|
99
99
|
bbox = text.get_window_extent(renderer)
|
|
100
100
|
bbox = Bbox(ax.transData.inverted().transform(bbox))
|
|
101
|
-
|
|
101
|
+
|
|
102
102
|
if self._mode == "proportional":
|
|
103
103
|
if self._width is None:
|
|
104
104
|
# Proportional scaling based on height
|
|
@@ -122,9 +122,9 @@ def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
|
|
|
122
122
|
scale = min(scale_x, scale_y)
|
|
123
123
|
scale_x, scale_y = scale, scale
|
|
124
124
|
|
|
125
|
-
affine =
|
|
125
|
+
affine = Affine2D().scale(scale_x, scale_y) + affine
|
|
126
126
|
renderer.draw_path(gc, tpath, affine, rgbFace)
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
if mode in ["unlocked", "minimum", "maximum"]:
|
|
129
129
|
if width is None or height is None:
|
|
130
130
|
raise TypeError(
|
|
@@ -146,8 +146,6 @@ try:
|
|
|
146
146
|
# Only create this class when matplotlib is installed
|
|
147
147
|
from matplotlib.transforms import Bbox
|
|
148
148
|
from matplotlib.patches import FancyArrow
|
|
149
|
-
from matplotlib.patheffects import AbstractPathEffect
|
|
150
|
-
import matplotlib.pyplot as plt
|
|
151
149
|
|
|
152
150
|
class AdaptiveFancyArrow(FancyArrow):
|
|
153
151
|
"""
|
|
@@ -178,7 +176,7 @@ try:
|
|
|
178
176
|
Other parameters that are used in the constructor of
|
|
179
177
|
`FancyArrow`.
|
|
180
178
|
"""
|
|
181
|
-
|
|
179
|
+
|
|
182
180
|
def __init__(self, x, y, dx, dy,
|
|
183
181
|
tail_width, head_width, head_ratio, draw_head=True,
|
|
184
182
|
shape="full", **kwargs):
|
|
@@ -219,7 +217,7 @@ try:
|
|
|
219
217
|
# only draw the arrow head with reduced length
|
|
220
218
|
head_length = arrow_length
|
|
221
219
|
if not self._draw_head:
|
|
222
|
-
head_length = 0
|
|
220
|
+
head_length = 0
|
|
223
221
|
|
|
224
222
|
# Renew the arrow's properties
|
|
225
223
|
super().__init__(
|
|
@@ -231,7 +229,7 @@ try:
|
|
|
231
229
|
)
|
|
232
230
|
self.set_clip_path(self.axes.patch)
|
|
233
231
|
super().draw(renderer)
|
|
234
|
-
|
|
232
|
+
|
|
235
233
|
# Override to replace docstring
|
|
236
234
|
# Removes warning:
|
|
237
235
|
# unknown document: /tutorials/intermediate/constrainedlayout_guide
|
|
@@ -245,7 +243,7 @@ try:
|
|
|
245
243
|
return super().set_in_layout(in_layout)
|
|
246
244
|
|
|
247
245
|
except ImportError:
|
|
248
|
-
|
|
246
|
+
|
|
249
247
|
# Dummy class that propagates a meaningful error,
|
|
250
248
|
# i.e. that Matplotlib is not installed
|
|
251
249
|
class AdaptiveFancyArrow():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: biotite
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.40.0
|
|
4
4
|
Summary: A comprehensive library for computational molecular biology
|
|
5
5
|
Author: The Biotite contributors
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -52,7 +52,7 @@ Requires-Python: >=3.7
|
|
|
52
52
|
Description-Content-Type: text/x-rst
|
|
53
53
|
License-File: LICENSE.rst
|
|
54
54
|
Requires-Dist: requests >=2.12
|
|
55
|
-
Requires-Dist: numpy
|
|
55
|
+
Requires-Dist: numpy <=2.0,>=1.14.5
|
|
56
56
|
Requires-Dist: msgpack >=0.5.6
|
|
57
57
|
Requires-Dist: networkx >=2.0
|
|
58
58
|
Provides-Extra: test
|