biotite 1.0.1__cp310-cp310-win_amd64.whl → 1.2.0__cp310-cp310-win_amd64.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.

Files changed (177) hide show
  1. biotite/application/application.py +3 -3
  2. biotite/application/autodock/app.py +1 -1
  3. biotite/application/blast/webapp.py +1 -1
  4. biotite/application/clustalo/app.py +1 -1
  5. biotite/application/dssp/app.py +13 -3
  6. biotite/application/localapp.py +36 -2
  7. biotite/application/msaapp.py +10 -10
  8. biotite/application/muscle/app3.py +5 -18
  9. biotite/application/muscle/app5.py +5 -5
  10. biotite/application/sra/app.py +0 -5
  11. biotite/application/util.py +22 -2
  12. biotite/application/viennarna/rnaalifold.py +8 -8
  13. biotite/application/viennarna/rnaplot.py +9 -3
  14. biotite/application/viennarna/util.py +1 -1
  15. biotite/application/webapp.py +1 -1
  16. biotite/database/afdb/__init__.py +12 -0
  17. biotite/database/afdb/download.py +191 -0
  18. biotite/database/entrez/dbnames.py +10 -0
  19. biotite/database/entrez/download.py +9 -10
  20. biotite/database/entrez/key.py +1 -1
  21. biotite/database/entrez/query.py +5 -4
  22. biotite/database/pubchem/download.py +6 -6
  23. biotite/database/pubchem/error.py +10 -0
  24. biotite/database/pubchem/query.py +12 -23
  25. biotite/database/rcsb/download.py +3 -2
  26. biotite/database/rcsb/query.py +8 -9
  27. biotite/database/uniprot/check.py +22 -17
  28. biotite/database/uniprot/download.py +3 -6
  29. biotite/database/uniprot/query.py +4 -5
  30. biotite/file.py +14 -2
  31. biotite/interface/__init__.py +19 -0
  32. biotite/interface/openmm/__init__.py +16 -0
  33. biotite/interface/openmm/state.py +93 -0
  34. biotite/interface/openmm/system.py +227 -0
  35. biotite/interface/pymol/__init__.py +198 -0
  36. biotite/interface/pymol/cgo.py +346 -0
  37. biotite/interface/pymol/convert.py +185 -0
  38. biotite/interface/pymol/display.py +267 -0
  39. biotite/interface/pymol/object.py +1226 -0
  40. biotite/interface/pymol/shapes.py +178 -0
  41. biotite/interface/pymol/startup.py +169 -0
  42. biotite/interface/rdkit/__init__.py +15 -0
  43. biotite/interface/rdkit/mol.py +490 -0
  44. biotite/interface/version.py +71 -0
  45. biotite/interface/warning.py +19 -0
  46. biotite/sequence/align/__init__.py +0 -4
  47. biotite/sequence/align/alignment.py +49 -14
  48. biotite/sequence/align/banded.cp310-win_amd64.pyd +0 -0
  49. biotite/sequence/align/banded.pyx +26 -26
  50. biotite/sequence/align/cigar.py +2 -2
  51. biotite/sequence/align/kmeralphabet.cp310-win_amd64.pyd +0 -0
  52. biotite/sequence/align/kmeralphabet.pyx +19 -2
  53. biotite/sequence/align/kmersimilarity.cp310-win_amd64.pyd +0 -0
  54. biotite/sequence/align/kmertable.cp310-win_amd64.pyd +0 -0
  55. biotite/sequence/align/kmertable.pyx +58 -48
  56. biotite/sequence/align/localgapped.cp310-win_amd64.pyd +0 -0
  57. biotite/sequence/align/localgapped.pyx +47 -47
  58. biotite/sequence/align/localungapped.cp310-win_amd64.pyd +0 -0
  59. biotite/sequence/align/localungapped.pyx +10 -10
  60. biotite/sequence/align/matrix.py +284 -57
  61. biotite/sequence/align/matrix_data/3Di.mat +24 -0
  62. biotite/sequence/align/matrix_data/PB.license +21 -0
  63. biotite/sequence/align/matrix_data/PB.mat +18 -0
  64. biotite/sequence/align/multiple.cp310-win_amd64.pyd +0 -0
  65. biotite/sequence/align/pairwise.cp310-win_amd64.pyd +0 -0
  66. biotite/sequence/align/pairwise.pyx +35 -35
  67. biotite/sequence/align/permutation.cp310-win_amd64.pyd +0 -0
  68. biotite/sequence/align/selector.cp310-win_amd64.pyd +0 -0
  69. biotite/sequence/align/selector.pyx +2 -2
  70. biotite/sequence/align/statistics.py +1 -1
  71. biotite/sequence/align/tracetable.cp310-win_amd64.pyd +0 -0
  72. biotite/sequence/alphabet.py +5 -2
  73. biotite/sequence/annotation.py +19 -13
  74. biotite/sequence/codec.cp310-win_amd64.pyd +0 -0
  75. biotite/sequence/codon.py +1 -2
  76. biotite/sequence/graphics/alignment.py +25 -39
  77. biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
  78. biotite/sequence/graphics/color_schemes/pb_flower.json +2 -1
  79. biotite/sequence/graphics/colorschemes.py +44 -11
  80. biotite/sequence/graphics/dendrogram.py +4 -2
  81. biotite/sequence/graphics/features.py +2 -2
  82. biotite/sequence/graphics/logo.py +10 -12
  83. biotite/sequence/io/fasta/convert.py +1 -2
  84. biotite/sequence/io/fasta/file.py +1 -1
  85. biotite/sequence/io/fastq/file.py +3 -3
  86. biotite/sequence/io/genbank/file.py +3 -3
  87. biotite/sequence/io/genbank/sequence.py +2 -0
  88. biotite/sequence/io/gff/convert.py +1 -1
  89. biotite/sequence/io/gff/file.py +1 -2
  90. biotite/sequence/phylo/nj.cp310-win_amd64.pyd +0 -0
  91. biotite/sequence/phylo/tree.cp310-win_amd64.pyd +0 -0
  92. biotite/sequence/phylo/upgma.cp310-win_amd64.pyd +0 -0
  93. biotite/sequence/profile.py +105 -29
  94. biotite/sequence/search.py +0 -1
  95. biotite/sequence/seqtypes.py +136 -8
  96. biotite/sequence/sequence.py +1 -2
  97. biotite/setup_ccd.py +197 -0
  98. biotite/structure/__init__.py +6 -3
  99. biotite/structure/alphabet/__init__.py +25 -0
  100. biotite/structure/alphabet/encoder.py +332 -0
  101. biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
  102. biotite/structure/alphabet/i3d.py +109 -0
  103. biotite/structure/alphabet/layers.py +86 -0
  104. biotite/structure/alphabet/pb.license +21 -0
  105. biotite/structure/alphabet/pb.py +170 -0
  106. biotite/structure/alphabet/unkerasify.py +128 -0
  107. biotite/structure/atoms.py +163 -66
  108. biotite/structure/basepairs.py +26 -26
  109. biotite/structure/bonds.cp310-win_amd64.pyd +0 -0
  110. biotite/structure/bonds.pyx +79 -25
  111. biotite/structure/box.py +19 -21
  112. biotite/structure/celllist.cp310-win_amd64.pyd +0 -0
  113. biotite/structure/celllist.pyx +83 -67
  114. biotite/structure/chains.py +5 -37
  115. biotite/structure/charges.cp310-win_amd64.pyd +0 -0
  116. biotite/structure/compare.py +420 -13
  117. biotite/structure/density.py +1 -1
  118. biotite/structure/dotbracket.py +27 -28
  119. biotite/structure/filter.py +8 -8
  120. biotite/structure/geometry.py +74 -127
  121. biotite/structure/hbond.py +17 -19
  122. biotite/structure/info/__init__.py +1 -0
  123. biotite/structure/info/atoms.py +24 -15
  124. biotite/structure/info/bonds.py +12 -6
  125. biotite/structure/info/ccd.py +125 -34
  126. biotite/structure/info/{ccd/components.bcif → components.bcif} +0 -0
  127. biotite/structure/info/groups.py +62 -19
  128. biotite/structure/info/masses.py +9 -6
  129. biotite/structure/info/misc.py +15 -22
  130. biotite/structure/info/radii.py +92 -22
  131. biotite/structure/info/standardize.py +4 -4
  132. biotite/structure/integrity.py +4 -6
  133. biotite/structure/io/general.py +2 -2
  134. biotite/structure/io/gro/file.py +8 -9
  135. biotite/structure/io/mol/convert.py +1 -1
  136. biotite/structure/io/mol/ctab.py +33 -28
  137. biotite/structure/io/mol/mol.py +1 -1
  138. biotite/structure/io/mol/sdf.py +80 -53
  139. biotite/structure/io/pdb/convert.py +4 -3
  140. biotite/structure/io/pdb/file.py +85 -25
  141. biotite/structure/io/pdb/hybrid36.cp310-win_amd64.pyd +0 -0
  142. biotite/structure/io/pdbqt/file.py +36 -36
  143. biotite/structure/io/pdbx/__init__.py +1 -0
  144. biotite/structure/io/pdbx/bcif.py +54 -15
  145. biotite/structure/io/pdbx/cif.py +92 -66
  146. biotite/structure/io/pdbx/component.py +15 -4
  147. biotite/structure/io/pdbx/compress.py +321 -0
  148. biotite/structure/io/pdbx/convert.py +410 -75
  149. biotite/structure/io/pdbx/encoding.cp310-win_amd64.pyd +0 -0
  150. biotite/structure/io/pdbx/encoding.pyx +98 -17
  151. biotite/structure/io/trajfile.py +9 -6
  152. biotite/structure/io/util.py +38 -0
  153. biotite/structure/mechanics.py +0 -1
  154. biotite/structure/molecules.py +141 -156
  155. biotite/structure/pseudoknots.py +7 -13
  156. biotite/structure/repair.py +2 -4
  157. biotite/structure/residues.py +13 -24
  158. biotite/structure/rings.py +335 -0
  159. biotite/structure/sasa.cp310-win_amd64.pyd +0 -0
  160. biotite/structure/sasa.pyx +2 -1
  161. biotite/structure/segments.py +69 -11
  162. biotite/structure/sequence.py +0 -1
  163. biotite/structure/sse.py +0 -2
  164. biotite/structure/superimpose.py +74 -62
  165. biotite/structure/tm.py +581 -0
  166. biotite/structure/transform.py +12 -25
  167. biotite/structure/util.py +76 -4
  168. biotite/version.py +9 -4
  169. biotite/visualize.py +111 -1
  170. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/METADATA +6 -2
  171. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/RECORD +173 -143
  172. biotite/structure/info/ccd/README.rst +0 -8
  173. biotite/structure/info/ccd/amino_acids.txt +0 -1663
  174. biotite/structure/info/ccd/carbohydrates.txt +0 -1135
  175. biotite/structure/info/ccd/nucleotides.txt +0 -798
  176. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/WHEEL +0 -0
  177. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/licenses/LICENSE.rst +0 -0
@@ -0,0 +1,335 @@
1
+ # This source code is part of the Biotite package and is distributed
2
+ # under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
3
+ # information.
4
+
5
+ """
6
+ This module provides functions related to aromatic rings.
7
+ """
8
+
9
+ __name__ = "biotite.structure"
10
+ __author__ = "Patrick Kunzmann"
11
+ __all__ = ["find_aromatic_rings", "find_stacking_interactions", "PiStacking"]
12
+
13
+
14
+ from enum import IntEnum
15
+ import networkx as nx
16
+ import numpy as np
17
+ from biotite.structure.bonds import BondType
18
+ from biotite.structure.error import BadStructureError
19
+ from biotite.structure.geometry import displacement
20
+ from biotite.structure.util import norm_vector, vector_dot
21
+
22
+
23
+ class PiStacking(IntEnum):
24
+ """
25
+ The type of pi-stacking interaction.
26
+
27
+ - ``PARALLEL``: parallel pi-stacking (also called *staggered* or *Sandwich*)
28
+ - ``PERPENDICULAR``: perpendicular pi-stacking (also called *T-shaped*)
29
+ """
30
+
31
+ PARALLEL = 0
32
+ PERPENDICULAR = 1
33
+
34
+
35
+ def find_aromatic_rings(atoms):
36
+ """
37
+ Find (anti-)aromatic rings in a structure.
38
+
39
+ Parameters
40
+ ----------
41
+ atoms : AtomArray or AtomArrayStack
42
+ The atoms to be searched for aromatic rings.
43
+ Requires an associated :class:`BondList`.
44
+
45
+ Returns
46
+ -------
47
+ rings : list of ndarray
48
+ The indices of the atoms that form aromatic rings.
49
+ Each ring is represented by a list of indices.
50
+ Only rings with minimum size are returned, i.e. two connected rings
51
+ (e.g. in tryptophan) are reported as separate rings.
52
+
53
+ Notes
54
+ -----
55
+ This function does not distinguish between aromatic and antiaromatic rings.
56
+ All cycles containing atoms that are completely connected by aromatic bonds
57
+ are considered aromatic rings.
58
+
59
+ The PDB *Chemical Component Dictionary* (CCD) does not identify aromatic rings in
60
+ all compounds as such.
61
+ Prominent examples are the nucleobases, where the 6-membered rings are not
62
+ flagged as aromatic.
63
+
64
+ Examples
65
+ --------
66
+
67
+ >>> nad = residue("NAD")
68
+ >>> rings = find_aromatic_rings(nad)
69
+ >>> print(rings)
70
+ [array([41, 37, 36, 35, 43, 42]), array([19, 18, 16, 15, 21, 20]), array([12, 13, 14, 15, 21])]
71
+ >>> for atom_indices in rings:
72
+ ... print(np.sort(nad.atom_name[atom_indices]))
73
+ ['C2N' 'C3N' 'C4N' 'C5N' 'C6N' 'N1N']
74
+ ['C2A' 'C4A' 'C5A' 'C6A' 'N1A' 'N3A']
75
+ ['C4A' 'C5A' 'C8A' 'N7A' 'N9A']
76
+ """
77
+ if atoms.bonds is None:
78
+ raise BadStructureError("Structure must have an associated BondList")
79
+ bond_array = atoms.bonds.as_array()
80
+ # To detect aromatic rings, only keep bonds that are aromatic
81
+ aromatic_bond_array = bond_array[
82
+ np.isin(
83
+ bond_array[:, 2],
84
+ [
85
+ BondType.AROMATIC,
86
+ BondType.AROMATIC_SINGLE,
87
+ BondType.AROMATIC_DOUBLE,
88
+ BondType.AROMATIC_TRIPLE,
89
+ ],
90
+ ),
91
+ # We can omit the bond type now
92
+ :2,
93
+ ]
94
+ aromatic_bond_graph = nx.from_edgelist(aromatic_bond_array.tolist())
95
+ # Find the cycles with minimum size -> cycle basis
96
+ rings = nx.cycle_basis(aromatic_bond_graph)
97
+ return [np.array(ring, dtype=int) for ring in rings]
98
+
99
+
100
+ def find_stacking_interactions(
101
+ atoms,
102
+ centroid_cutoff=6.5,
103
+ plane_angle_tol=np.deg2rad(30.0),
104
+ shift_angle_tol=np.deg2rad(30.0),
105
+ ):
106
+ """
107
+ Find pi-stacking interactions between aromatic rings.
108
+
109
+ Parameters
110
+ ----------
111
+ atoms : AtomArray
112
+ The atoms to be searched for aromatic rings.
113
+ Requires an associated :class:`BondList`.
114
+ centroid_cutoff : float
115
+ The cutoff distance for ring centroids.
116
+ plane_angle_tol : float
117
+ The tolerance for the angle between ring planes that must be either
118
+ parallel or perpendicular.
119
+ Given in radians.
120
+ shift_angle_tol : float
121
+ The tolerance for the angle between the ring plane normals and the
122
+ centroid difference vector.
123
+ Given in radians.
124
+
125
+ Returns
126
+ -------
127
+ interactions : list of tuple(ndarray, ndarray, PiStacking)
128
+ The stacking interactions between aromatic rings.
129
+ Each element in the list represents one stacking interaction.
130
+ The first two elements of each tuple represent atom indices of the stacked
131
+ rings.
132
+ The third element of each tuple is the type of stacking interaction.
133
+
134
+ See Also
135
+ --------
136
+ find_aromatic_rings : Used for finding the aromatic rings in this function.
137
+
138
+ Notes
139
+ -----
140
+ This function does not distinguish between aromatic and antiaromatic rings.
141
+ Furthermore, it does not distinguish between repulsive and attractive stacking:
142
+ Usually, stacking two rings directly above each other is repulsive, as the pi
143
+ orbitals above the rings repel each other, so a slight horizontal shift is
144
+ usually required to make the interaction attractive.
145
+ However, in details this is strongly dependent on heteroatoms and the exact
146
+ orientation of the rings.
147
+ Hence, this function aggregates all stacking interactions to simplify the
148
+ conditions for pi-stacking.
149
+
150
+ The conditions for pi-stacking are :footcite:`Wojcikowski2015` :
151
+
152
+ - The ring centroids must be within cutoff distance (default: 6.5 Å).
153
+ While :footcite:`Wojcikowski2015` uses a cutoff of 5.0 Å, 6.5 Å was
154
+ adopted from :footcite:`Bouysset2021` to better identify perpendicular
155
+ stacking interactions.
156
+ - The planes must be parallel or perpendicular to each other within a default
157
+ tolerance of 30°.
158
+ - The angle between the plane normals and the centroid difference vector must be
159
+ be either 0° or 90° within a default tolerance of 30°, to check for lateral
160
+ shifts.
161
+
162
+ References
163
+ ----------
164
+
165
+ .. footbibliography::
166
+
167
+ Examples
168
+ --------
169
+
170
+ Detect base stacking interactions in a DNA helix
171
+
172
+ >>> from os.path import join
173
+ >>> dna_helix = load_structure(
174
+ ... join(path_to_structures, "base_pairs", "1qxb.cif"), include_bonds=True
175
+ ... )
176
+ >>> interactions = find_stacking_interactions(dna_helix)
177
+ >>> for ring_atom_indices_1, ring_atom_indices_2, stacking_type in interactions:
178
+ ... print(
179
+ ... dna_helix.res_id[ring_atom_indices_1[0]],
180
+ ... dna_helix.res_id[ring_atom_indices_2[0]],
181
+ ... PiStacking(stacking_type).name
182
+ ... )
183
+ 17 18 PARALLEL
184
+ 17 18 PARALLEL
185
+ 5 6 PARALLEL
186
+ 5 6 PARALLEL
187
+ 5 6 PARALLEL
188
+ """
189
+ rings = find_aromatic_rings(atoms)
190
+ if len(rings) == 0:
191
+ return []
192
+
193
+ ring_centroids = np.array(
194
+ [atoms.coord[atom_indices].mean(axis=0) for atom_indices in rings]
195
+ )
196
+ ring_normals = np.array(
197
+ [_get_ring_normal(atoms.coord[atom_indices]) for atom_indices in rings]
198
+ )
199
+
200
+ # Create an index array that contains the Cartesian product of all rings
201
+ indices = np.stack(
202
+ [
203
+ np.repeat(np.arange(len(rings)), len(rings)),
204
+ np.tile(np.arange(len(rings)), len(rings)),
205
+ ],
206
+ axis=-1,
207
+ )
208
+ # Do not include duplicate pairs
209
+ indices = indices[indices[:, 0] > indices[:, 1]]
210
+
211
+ ## Condition 1: Ring centroids are close enough to each other
212
+ diff = displacement(ring_centroids[indices[:, 0]], ring_centroids[indices[:, 1]])
213
+ # Use squared distance to avoid time consuming sqrt computation
214
+ sq_distance = vector_dot(diff, diff)
215
+ is_interacting = sq_distance < centroid_cutoff**2
216
+ indices = indices[is_interacting]
217
+
218
+ ## Condition 2: Ring planes are parallel or perpendicular
219
+ plane_angles = _minimum_angle(
220
+ ring_normals[indices[:, 0]], ring_normals[indices[:, 1]]
221
+ )
222
+ is_parallel = _is_within_tolerance(plane_angles, 0, plane_angle_tol)
223
+ is_perpendicular = _is_within_tolerance(plane_angles, np.pi / 2, plane_angle_tol)
224
+ is_interacting = is_parallel | is_perpendicular
225
+ indices = indices[is_interacting]
226
+ # Keep in sync with the shape of the filtered indices,
227
+ # i.e. after filtering, `is_parallel==False` means a perpendicular interaction
228
+ is_parallel = is_parallel[is_interacting]
229
+
230
+ ## Condition 3: The ring centroids are not shifted too much
231
+ ## (in terms of normal-centroid angle)
232
+ diff = displacement(ring_centroids[indices[:, 0]], ring_centroids[indices[:, 1]])
233
+ norm_vector(diff)
234
+ angles = np.stack(
235
+ [_minimum_angle(ring_normals[indices[:, i]], diff) for i in range(2)]
236
+ )
237
+ is_interacting = (
238
+ # For parallel stacking, the lateral shift may not exceed the tolerance
239
+ (is_parallel & np.any(_is_within_tolerance(angles, 0, shift_angle_tol), axis=0))
240
+ # For perpendicular stacking, one ring must be above the other,
241
+ # but from the perspective of the other ring, the first ring is approximately
242
+ # in the same plane
243
+ | (
244
+ ~is_parallel
245
+ & (
246
+ (
247
+ _is_within_tolerance(angles[0], 0, shift_angle_tol)
248
+ & _is_within_tolerance(angles[1], np.pi / 2, shift_angle_tol)
249
+ )
250
+ | (
251
+ _is_within_tolerance(angles[0], np.pi / 2, shift_angle_tol)
252
+ & _is_within_tolerance(angles[1], 0, shift_angle_tol)
253
+ )
254
+ )
255
+ )
256
+ )
257
+ indices = indices[is_interacting]
258
+ is_parallel = is_parallel[is_interacting]
259
+
260
+ # Only return pairs of rings where all conditions were fulfilled
261
+ return [
262
+ (
263
+ rings[ring_i],
264
+ rings[ring_j],
265
+ PiStacking.PARALLEL if is_parallel[i] else PiStacking.PERPENDICULAR,
266
+ )
267
+ for i, (ring_i, ring_j) in enumerate(indices)
268
+ ]
269
+
270
+
271
+ def _get_ring_normal(ring_coord):
272
+ """
273
+ Get the normal vector perpendicular to the ring plane.
274
+
275
+ Parameters
276
+ ----------
277
+ ring_coord : ndarray
278
+ The coordinates of the atoms in the ring.
279
+
280
+ Returns
281
+ -------
282
+ normal : ndarray
283
+ The normal vector of the ring plane.
284
+ """
285
+ # Simply use any three atoms in the ring to calculate the normal vector
286
+ # We can also safely assume that there are at least three atoms in the ring,
287
+ # as otherwise it would not be a ring
288
+ normal = np.cross(ring_coord[1] - ring_coord[0], ring_coord[2] - ring_coord[0])
289
+ norm_vector(normal)
290
+ return normal
291
+
292
+
293
+ def _minimum_angle(v1, v2):
294
+ """
295
+ Get the minimum angle between two vectors, i.e. the possible angle range is
296
+ ``[0, pi/2]``.
297
+
298
+ Parameters
299
+ ----------
300
+ v1, v2 : ndarray, shape=(n,3), dtype=float
301
+ The vectors to measure the angle between.
302
+
303
+ Returns
304
+ -------
305
+ angle : ndarray, shape=(n,), dtype=float
306
+ The minimum angle between the two vectors.
307
+
308
+ Notes
309
+ -----
310
+ This restriction is added here as the normal vectors of the ring planes
311
+ have no 'preferred side'.
312
+ """
313
+ # Do not distinguish between the 'sides' of the rings -> take absolute of cosine
314
+ return np.arccos(np.abs(vector_dot(v1, v2)))
315
+
316
+
317
+ def _is_within_tolerance(angles, expected_angle, tolerance):
318
+ """
319
+ Check if the angles are within a certain tolerance.
320
+
321
+ Parameters
322
+ ----------
323
+ angles : ndarray, shape=x, dtype=float
324
+ The angles to check.
325
+ expected_angle : float
326
+ The expected angle.
327
+ tolerance : float
328
+ The tolerance.
329
+
330
+ Returns
331
+ -------
332
+ is_within_tolerance : ndarray, shape=x, dtype=bool
333
+ True if the angles are within the tolerance, False otherwise.
334
+ """
335
+ return np.abs(angles - expected_angle) < tolerance
Binary file
@@ -83,7 +83,8 @@ def sasa(array, float probe_radius=1.4, np.ndarray atom_filter=None,
83
83
  - **Single** - A set, which uses a defined VdW radius for
84
84
  every single atom, therefore hydrogen atoms are required
85
85
  in the model (e.g. NMR elucidated structures).
86
- :footcite:`Bondi1964`
86
+ Values for main group elements are taken from :footcite:`Mantina2009`,
87
+ and for relevant transition metals from the :footcite:`RDKit`.
87
88
 
88
89
  By default *ProtOr* is used.
89
90
 
@@ -16,7 +16,7 @@ __all__ = [
16
16
  import numpy as np
17
17
 
18
18
 
19
- def apply_segment_wise(starts, data, function, axis):
19
+ def apply_segment_wise(starts, data, function, axis=None):
20
20
  """
21
21
  Generalized version of :func:`apply_residue_wise()` for
22
22
  residues and chains.
@@ -27,6 +27,22 @@ def apply_segment_wise(starts, data, function, axis):
27
27
  The sorted start indices of segments.
28
28
  Includes exclusive stop, i.e. the length of the corresponding
29
29
  atom array.
30
+ data : ndarray
31
+ The data, whose intervals are the parameter for `function`.
32
+ Must have same length as `array`.
33
+ function : function
34
+ The `function` must have either the form *f(data)* or
35
+ *f(data, axis)* in case `axis` is given. Every `function` call
36
+ must return a value with the same shape and data type.
37
+ axis : int, optional
38
+ This value is given to the `axis` parameter of `function`.
39
+
40
+ Returns
41
+ -------
42
+ processed_data : ndarray
43
+ Segment-wise evaluation of `data` by `function`.
44
+ The size of the first dimension of this array is equal to the amount of
45
+ residues.
30
46
  """
31
47
  # The result array
32
48
  processed_data = None
@@ -36,7 +52,6 @@ def apply_segment_wise(starts, data, function, axis):
36
52
  value = function(segment)
37
53
  else:
38
54
  value = function(segment, axis=axis)
39
- value = function(segment, axis=axis)
40
55
  # Identify the shape of the resulting array by evaluation
41
56
  # of the function return value for the first segment
42
57
  if processed_data is None:
@@ -66,13 +81,19 @@ def spread_segment_wise(starts, input_data):
66
81
  The sorted start indices of segments.
67
82
  Includes exclusive stop, i.e. the length of the corresponding
68
83
  atom array.
84
+ input_data : ndarray
85
+ The data to be spread.
86
+ The length of the 0-th axis must be equal to the amount of different residue IDs
87
+ in `array`.
88
+
89
+ Returns
90
+ -------
91
+ output_data : ndarray
92
+ Segment-wise spread `input_data`.
93
+ Length is the same as `array_length()` of `array`.
69
94
  """
70
- output_data = np.zeros(starts[-1], dtype=input_data.dtype)
71
- for i in range(len(starts) - 1):
72
- start = starts[i]
73
- stop = starts[i + 1]
74
- output_data[start:stop] = input_data[i]
75
- return output_data
95
+ seg_lens = starts[1:] - starts[:-1]
96
+ return np.repeat(input_data, seg_lens, axis=0)
76
97
 
77
98
 
78
99
  def get_segment_masks(starts, indices):
@@ -86,6 +107,17 @@ def get_segment_masks(starts, indices):
86
107
  The sorted start indices of segments.
87
108
  Includes exclusive stop, i.e. the length of the corresponding
88
109
  atom array.
110
+ indices : ndarray, dtype=int, shape=(k,)
111
+ These indices indicate the atoms to get the corresponding
112
+ segments for.
113
+ Negative indices are not allowed.
114
+
115
+ Returns
116
+ -------
117
+ residues_masks : ndarray, dtype=bool, shape=(k,n)
118
+ Multiple boolean masks, one for each given index in `indices`.
119
+ Each array masks the atoms that belong to the same segment as
120
+ the atom at the given index.
89
121
  """
90
122
  indices = np.asarray(indices)
91
123
  length = starts[-1]
@@ -96,7 +128,7 @@ def get_segment_masks(starts, indices):
96
128
  if (indices >= length).any():
97
129
  index = np.min(np.where(indices >= length)[0])
98
130
  raise ValueError(
99
- f"Index {index} is out of range for " f"an atom array with length {length}"
131
+ f"Index {index} is out of range for an atom array with length {length}"
100
132
  )
101
133
 
102
134
  insertion_points = np.searchsorted(starts, indices, side="right") - 1
@@ -117,6 +149,16 @@ def get_segment_starts_for(starts, indices):
117
149
  The sorted start indices of segments.
118
150
  Includes exclusive stop, i.e. the length of the corresponding
119
151
  atom array.
152
+ indices : ndarray, dtype=int, shape=(k,)
153
+ These indices point to the atoms to get the corresponding
154
+ segment starts for.
155
+ Negative indices are not allowed.
156
+
157
+ Returns
158
+ -------
159
+ start_indices : ndarray, dtype=int, shape=(k,)
160
+ The indices that point to the segment starts for the input
161
+ `indices`.
120
162
  """
121
163
  indices = np.asarray(indices)
122
164
  length = starts[-1]
@@ -128,7 +170,7 @@ def get_segment_starts_for(starts, indices):
128
170
  if (indices >= length).any():
129
171
  index = np.min(np.where(indices >= length)[0])
130
172
  raise ValueError(
131
- f"Index {index} is out of range for " f"an atom array with length {length}"
173
+ f"Index {index} is out of range for an atom array with length {length}"
132
174
  )
133
175
 
134
176
  insertion_points = np.searchsorted(starts, indices, side="right") - 1
@@ -146,6 +188,15 @@ def get_segment_positions(starts, indices):
146
188
  The sorted start indices of segments.
147
189
  Includes exclusive stop, i.e. the length of the corresponding
148
190
  atom array.
191
+ indices : ndarray, shape=(k,)
192
+ These indices point to the atoms to get the corresponding
193
+ residue positions for.
194
+ Negative indices are not allowed.
195
+
196
+ Returns
197
+ -------
198
+ segment_indices : ndarray, shape=(k,)
199
+ The indices that point to the position of the segments.
149
200
  """
150
201
  indices = np.asarray(indices)
151
202
  length = starts[-1]
@@ -157,7 +208,7 @@ def get_segment_positions(starts, indices):
157
208
  if (indices >= length).any():
158
209
  index = np.min(np.where(indices >= length)[0])
159
210
  raise ValueError(
160
- f"Index {index} is out of range for " f"an atom array with length {length}"
211
+ f"Index {index} is out of range for an atom array with length {length}"
161
212
  )
162
213
 
163
214
  return np.searchsorted(starts, indices, side="right") - 1
@@ -170,10 +221,17 @@ def segment_iter(array, starts):
170
221
 
171
222
  Parameters
172
223
  ----------
224
+ array : AtomArray or AtomArrayStack
225
+ The structure to iterate over.
173
226
  starts : ndarray, dtype=int
174
227
  The sorted start indices of segments.
175
228
  Includes exclusive stop, i.e. the length of the corresponding
176
229
  atom array.
230
+
231
+ Yields
232
+ ------
233
+ segment : AtomArray or AtomArrayStack
234
+ Each residue or chain of the structure.
177
235
  """
178
236
  for i in range(len(starts) - 1):
179
237
  yield array[..., starts[i] : starts[i + 1]]
@@ -58,7 +58,6 @@ def to_sequence(atoms, allow_hetero=False):
58
58
  >>> sequences, chain_starts = to_sequence(atom_array)
59
59
  >>> print(sequences)
60
60
  [ProteinSequence("NLYIQWLKDGGPSSGRPPPS")]
61
-
62
61
  """
63
62
  sequences = []
64
63
  chain_start_indices = get_chain_starts(atoms, add_exclusive_stop=True)
biotite/structure/sse.py CHANGED
@@ -48,7 +48,6 @@ def annotate_sse(atom_array):
48
48
  Non-peptide residues are also allowed and obtain a ``''``
49
49
  SSE.
50
50
 
51
-
52
51
  Returns
53
52
  -------
54
53
  sse : ndarray
@@ -81,7 +80,6 @@ def annotate_sse(atom_array):
81
80
  >>> print(sse)
82
81
  ['c' 'a' 'a' 'a' 'a' 'a' 'a' 'a' 'a' 'c' 'c' 'c' 'c' 'c' 'c' 'c' 'c' 'c'
83
82
  'c' 'c']
84
-
85
83
  """
86
84
  residue_starts = get_residue_starts(atom_array)
87
85
  # Sort CA coord into the coord array at the respective residue index