biotite 1.1.0__cp313-cp313-win_amd64.whl → 1.3.0__cp313-cp313-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 (160) 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/localapp.py +2 -2
  6. biotite/application/msaapp.py +10 -10
  7. biotite/application/muscle/app3.py +3 -3
  8. biotite/application/muscle/app5.py +3 -3
  9. biotite/application/sra/app.py +0 -5
  10. biotite/application/util.py +21 -1
  11. biotite/application/viennarna/rnaalifold.py +8 -8
  12. biotite/application/viennarna/rnaplot.py +10 -8
  13. biotite/application/viennarna/util.py +1 -1
  14. biotite/application/webapp.py +1 -1
  15. biotite/database/afdb/__init__.py +12 -0
  16. biotite/database/afdb/download.py +191 -0
  17. biotite/database/entrez/dbnames.py +10 -0
  18. biotite/database/entrez/download.py +9 -10
  19. biotite/database/entrez/key.py +1 -1
  20. biotite/database/entrez/query.py +5 -4
  21. biotite/database/pubchem/download.py +6 -6
  22. biotite/database/pubchem/error.py +10 -0
  23. biotite/database/pubchem/query.py +12 -23
  24. biotite/database/rcsb/download.py +3 -2
  25. biotite/database/rcsb/query.py +2 -3
  26. biotite/database/uniprot/check.py +2 -2
  27. biotite/database/uniprot/download.py +2 -5
  28. biotite/database/uniprot/query.py +3 -4
  29. biotite/file.py +14 -2
  30. biotite/interface/__init__.py +19 -0
  31. biotite/interface/openmm/__init__.py +20 -0
  32. biotite/interface/openmm/state.py +93 -0
  33. biotite/interface/openmm/system.py +227 -0
  34. biotite/interface/pymol/__init__.py +201 -0
  35. biotite/interface/pymol/cgo.py +346 -0
  36. biotite/interface/pymol/convert.py +185 -0
  37. biotite/interface/pymol/display.py +267 -0
  38. biotite/interface/pymol/object.py +1226 -0
  39. biotite/interface/pymol/shapes.py +178 -0
  40. biotite/interface/pymol/startup.py +169 -0
  41. biotite/interface/rdkit/__init__.py +19 -0
  42. biotite/interface/rdkit/mol.py +490 -0
  43. biotite/interface/version.py +94 -0
  44. biotite/interface/warning.py +19 -0
  45. biotite/sequence/align/__init__.py +0 -4
  46. biotite/sequence/align/alignment.py +33 -11
  47. biotite/sequence/align/banded.cp313-win_amd64.pyd +0 -0
  48. biotite/sequence/align/banded.pyx +22 -22
  49. biotite/sequence/align/cigar.py +2 -2
  50. biotite/sequence/align/kmeralphabet.cp313-win_amd64.pyd +0 -0
  51. biotite/sequence/align/kmeralphabet.pyx +2 -2
  52. biotite/sequence/align/kmersimilarity.cp313-win_amd64.pyd +0 -0
  53. biotite/sequence/align/kmertable.cp313-win_amd64.pyd +0 -0
  54. biotite/sequence/align/kmertable.pyx +6 -6
  55. biotite/sequence/align/localgapped.cp313-win_amd64.pyd +0 -0
  56. biotite/sequence/align/localgapped.pyx +47 -47
  57. biotite/sequence/align/localungapped.cp313-win_amd64.pyd +0 -0
  58. biotite/sequence/align/localungapped.pyx +10 -10
  59. biotite/sequence/align/matrix.py +12 -3
  60. biotite/sequence/align/multiple.cp313-win_amd64.pyd +0 -0
  61. biotite/sequence/align/multiple.pyx +1 -2
  62. biotite/sequence/align/pairwise.cp313-win_amd64.pyd +0 -0
  63. biotite/sequence/align/pairwise.pyx +37 -39
  64. biotite/sequence/align/permutation.cp313-win_amd64.pyd +0 -0
  65. biotite/sequence/align/selector.cp313-win_amd64.pyd +0 -0
  66. biotite/sequence/align/selector.pyx +2 -2
  67. biotite/sequence/align/statistics.py +1 -1
  68. biotite/sequence/align/tracetable.cp313-win_amd64.pyd +0 -0
  69. biotite/sequence/alphabet.py +2 -2
  70. biotite/sequence/annotation.py +19 -13
  71. biotite/sequence/codec.cp313-win_amd64.pyd +0 -0
  72. biotite/sequence/codon.py +1 -2
  73. biotite/sequence/graphics/alignment.py +25 -39
  74. biotite/sequence/graphics/dendrogram.py +4 -2
  75. biotite/sequence/graphics/features.py +2 -2
  76. biotite/sequence/graphics/logo.py +10 -12
  77. biotite/sequence/io/fasta/convert.py +1 -2
  78. biotite/sequence/io/fasta/file.py +1 -1
  79. biotite/sequence/io/fastq/file.py +3 -3
  80. biotite/sequence/io/genbank/file.py +3 -3
  81. biotite/sequence/io/genbank/sequence.py +2 -0
  82. biotite/sequence/io/gff/convert.py +1 -1
  83. biotite/sequence/io/gff/file.py +1 -2
  84. biotite/sequence/phylo/nj.cp313-win_amd64.pyd +0 -0
  85. biotite/sequence/phylo/tree.cp313-win_amd64.pyd +0 -0
  86. biotite/sequence/phylo/upgma.cp313-win_amd64.pyd +0 -0
  87. biotite/sequence/profile.py +19 -25
  88. biotite/sequence/search.py +0 -1
  89. biotite/sequence/seqtypes.py +12 -5
  90. biotite/sequence/sequence.py +1 -2
  91. biotite/structure/__init__.py +2 -0
  92. biotite/structure/alphabet/i3d.py +1 -2
  93. biotite/structure/alphabet/pb.py +1 -2
  94. biotite/structure/alphabet/unkerasify.py +8 -2
  95. biotite/structure/atoms.py +35 -27
  96. biotite/structure/basepairs.py +39 -40
  97. biotite/structure/bonds.cp313-win_amd64.pyd +0 -0
  98. biotite/structure/bonds.pyx +8 -5
  99. biotite/structure/box.py +159 -23
  100. biotite/structure/celllist.cp313-win_amd64.pyd +0 -0
  101. biotite/structure/celllist.pyx +83 -68
  102. biotite/structure/chains.py +17 -55
  103. biotite/structure/charges.cp313-win_amd64.pyd +0 -0
  104. biotite/structure/compare.py +420 -13
  105. biotite/structure/density.py +1 -1
  106. biotite/structure/dotbracket.py +31 -32
  107. biotite/structure/filter.py +8 -8
  108. biotite/structure/geometry.py +15 -15
  109. biotite/structure/graphics/rna.py +19 -16
  110. biotite/structure/hbond.py +18 -21
  111. biotite/structure/info/atoms.py +11 -2
  112. biotite/structure/info/ccd.py +0 -2
  113. biotite/structure/info/components.bcif +0 -0
  114. biotite/structure/info/groups.py +0 -3
  115. biotite/structure/info/misc.py +0 -1
  116. biotite/structure/info/radii.py +92 -22
  117. biotite/structure/info/standardize.py +1 -2
  118. biotite/structure/integrity.py +4 -6
  119. biotite/structure/io/general.py +2 -2
  120. biotite/structure/io/gro/file.py +8 -9
  121. biotite/structure/io/mol/convert.py +1 -1
  122. biotite/structure/io/mol/ctab.py +33 -28
  123. biotite/structure/io/mol/mol.py +1 -1
  124. biotite/structure/io/mol/sdf.py +39 -13
  125. biotite/structure/io/pdb/convert.py +86 -5
  126. biotite/structure/io/pdb/file.py +90 -24
  127. biotite/structure/io/pdb/hybrid36.cp313-win_amd64.pyd +0 -0
  128. biotite/structure/io/pdbqt/file.py +4 -4
  129. biotite/structure/io/pdbx/bcif.py +22 -7
  130. biotite/structure/io/pdbx/cif.py +20 -7
  131. biotite/structure/io/pdbx/component.py +6 -0
  132. biotite/structure/io/pdbx/compress.py +71 -34
  133. biotite/structure/io/pdbx/convert.py +429 -77
  134. biotite/structure/io/pdbx/encoding.cp313-win_amd64.pyd +0 -0
  135. biotite/structure/io/pdbx/encoding.pyx +39 -23
  136. biotite/structure/io/trajfile.py +9 -6
  137. biotite/structure/io/util.py +38 -0
  138. biotite/structure/mechanics.py +0 -1
  139. biotite/structure/molecules.py +0 -15
  140. biotite/structure/pseudoknots.py +13 -19
  141. biotite/structure/repair.py +2 -4
  142. biotite/structure/residues.py +20 -48
  143. biotite/structure/rings.py +335 -0
  144. biotite/structure/sasa.cp313-win_amd64.pyd +0 -0
  145. biotite/structure/sasa.pyx +30 -30
  146. biotite/structure/segments.py +123 -9
  147. biotite/structure/sequence.py +0 -1
  148. biotite/structure/spacegroups.json +1567 -0
  149. biotite/structure/spacegroups.license +26 -0
  150. biotite/structure/sse.py +0 -2
  151. biotite/structure/superimpose.py +75 -253
  152. biotite/structure/tm.py +581 -0
  153. biotite/structure/transform.py +232 -26
  154. biotite/structure/util.py +3 -3
  155. biotite/version.py +9 -4
  156. biotite/visualize.py +111 -1
  157. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/METADATA +8 -36
  158. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/RECORD +160 -138
  159. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/WHEEL +1 -1
  160. {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/licenses/LICENSE.rst +0 -0
@@ -10,6 +10,7 @@ that can be applied on structures.
10
10
  __name__ = "biotite.structure"
11
11
  __author__ = "Patrick Kunzmann", "Claude J. Rogers"
12
12
  __all__ = [
13
+ "AffineTransformation",
13
14
  "translate",
14
15
  "rotate",
15
16
  "rotate_centered",
@@ -20,10 +21,215 @@ __all__ = [
20
21
 
21
22
  import numpy as np
22
23
  from biotite.structure.atoms import Atom, AtomArray, AtomArrayStack, coord
23
- from biotite.structure.geometry import centroid
24
24
  from biotite.structure.util import matrix_rotate, norm_vector, vector_dot
25
25
 
26
26
 
27
+ class AffineTransformation:
28
+ """
29
+ An affine transformation, consisting of translations and a rotation.
30
+
31
+ Parameters
32
+ ----------
33
+ center_translation : ndarray, shape=(3,) or shape=(m,3), dtype=float
34
+ The translation vector for moving the centroid into the
35
+ origin.
36
+ rotation : ndarray, shape=(3,3) or shape=(m,3,3), dtype=float
37
+ The rotation matrix.
38
+ target_translation : ndarray, shape=(m,3), dtype=float
39
+ The translation vector for moving the structure onto the
40
+ fixed one.
41
+
42
+ Attributes
43
+ ----------
44
+ center_translation, rotation, target_translation : ndarray
45
+ Same as the parameters.
46
+ The dimensions are always expanded to *(m,3)* or *(m,3,3)*,
47
+ respectively.
48
+ """
49
+
50
+ def __init__(self, center_translation, rotation, target_translation):
51
+ self.center_translation = _expand_dims(center_translation, 2)
52
+ self.rotation = _expand_dims(rotation, 3)
53
+ self.target_translation = _expand_dims(target_translation, 2)
54
+
55
+ def apply(self, atoms):
56
+ """
57
+ Apply this transformation on the given structure.
58
+
59
+ Parameters
60
+ ----------
61
+ atoms : AtomArray or AtomArrayStack or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
62
+ The structure to apply the transformation on.
63
+
64
+ Returns
65
+ -------
66
+ transformed : AtomArray or AtomArrayStack or ndarray, shape(n,), dtype=float or ndarray, shape(m,n), dtype=float
67
+ A copy of the `atoms` structure, with transformations applied.
68
+ Only coordinates are returned, if coordinates were given in `atoms`.
69
+
70
+ Examples
71
+ --------
72
+
73
+ >>> coord = np.arange(15).reshape(5,3)
74
+ >>> print(coord)
75
+ [[ 0 1 2]
76
+ [ 3 4 5]
77
+ [ 6 7 8]
78
+ [ 9 10 11]
79
+ [12 13 14]]
80
+ >>> # Rotates 90 degrees around the z-axis
81
+ >>> transform = AffineTransformation(
82
+ ... center_translation=np.array([0,0,0]),
83
+ ... rotation=np.array([
84
+ ... [0, -1, 0],
85
+ ... [1, 0, 0],
86
+ ... [0, 0, 1]
87
+ ... ]),
88
+ ... target_translation=np.array([0,0,0])
89
+ ... )
90
+ >>> print(transform.apply(coord))
91
+ [[ -1. 0. 2.]
92
+ [ -4. 3. 5.]
93
+ [ -7. 6. 8.]
94
+ [-10. 9. 11.]
95
+ [-13. 12. 14.]]
96
+ """
97
+ mobile_coord = coord(atoms)
98
+ original_shape = mobile_coord.shape
99
+ mobile_coord = _reshape_to_3d(mobile_coord)
100
+ if (
101
+ self.rotation.shape[0] != 1
102
+ and mobile_coord.shape[0] != self.rotation.shape[0]
103
+ ):
104
+ raise IndexError(
105
+ f"Number of transformations is {self.rotation.shape[0]}, "
106
+ f"but number of structure models is {mobile_coord.shape[0]}"
107
+ )
108
+
109
+ superimposed_coord = mobile_coord.copy()
110
+ superimposed_coord += self.center_translation[:, np.newaxis, :]
111
+ superimposed_coord = _multi_matmul(self.rotation, superimposed_coord)
112
+ superimposed_coord += self.target_translation[:, np.newaxis, :]
113
+
114
+ superimposed_coord = superimposed_coord.reshape(original_shape)
115
+ if isinstance(atoms, np.ndarray):
116
+ return superimposed_coord
117
+ else:
118
+ superimposed = atoms.copy()
119
+ superimposed.coord = superimposed_coord
120
+ return superimposed
121
+
122
+ def as_matrix(self):
123
+ """
124
+ Get the translations and rotation as a combined 4x4
125
+ transformation matrix.
126
+
127
+ Multiplying this matrix with coordinates in the form
128
+ *(x, y, z, 1)* will apply the same transformation as
129
+ :meth:`apply()` to coordinates in the form *(x, y, z)*.
130
+
131
+ Returns
132
+ -------
133
+ transformation_matrix : ndarray, shape=(m,4,4), dtype=float
134
+ The transformation matrix.
135
+ *m* is the number of models in the transformation.
136
+
137
+ Examples
138
+ --------
139
+
140
+ >>> coord = np.arange(15).reshape(5,3)
141
+ >>> print(coord)
142
+ [[ 0 1 2]
143
+ [ 3 4 5]
144
+ [ 6 7 8]
145
+ [ 9 10 11]
146
+ [12 13 14]]
147
+ >>> # Rotates 90 degrees around the z-axis
148
+ >>> transform = AffineTransformation(
149
+ ... center_translation=np.array([0,0,0]),
150
+ ... rotation=np.array([
151
+ ... [0, -1, 0],
152
+ ... [1, 0, 0],
153
+ ... [0, 0, 1]
154
+ ... ]),
155
+ ... target_translation=np.array([0,0,0])
156
+ ... )
157
+ >>> print(transform.apply(coord))
158
+ [[ -1. 0. 2.]
159
+ [ -4. 3. 5.]
160
+ [ -7. 6. 8.]
161
+ [-10. 9. 11.]
162
+ [-13. 12. 14.]]
163
+ >>> # Use a 4x4 matrix for transformation as alternative
164
+ >>> coord_4 = np.concatenate([coord, np.ones((len(coord), 1))], axis=-1)
165
+ >>> print(coord_4)
166
+ [[ 0. 1. 2. 1.]
167
+ [ 3. 4. 5. 1.]
168
+ [ 6. 7. 8. 1.]
169
+ [ 9. 10. 11. 1.]
170
+ [12. 13. 14. 1.]]
171
+ >>> print((transform.as_matrix()[0] @ coord_4.T).T)
172
+ [[ -1. 0. 2. 1.]
173
+ [ -4. 3. 5. 1.]
174
+ [ -7. 6. 8. 1.]
175
+ [-10. 9. 11. 1.]
176
+ [-13. 12. 14. 1.]]
177
+ """
178
+ n_models = self.rotation.shape[0]
179
+ rotation_mat = _3d_identity(n_models, 4)
180
+ rotation_mat[:, :3, :3] = self.rotation
181
+ center_translation_mat = _3d_identity(n_models, 4)
182
+ center_translation_mat[:, :3, 3] = self.center_translation
183
+ target_translation_mat = _3d_identity(n_models, 4)
184
+ target_translation_mat[:, :3, 3] = self.target_translation
185
+ return target_translation_mat @ rotation_mat @ center_translation_mat
186
+
187
+ def __eq__(self, other):
188
+ if not isinstance(other, AffineTransformation):
189
+ return False
190
+ if not np.array_equal(self.center_translation, other.center_translation):
191
+ return False
192
+ if not np.array_equal(self.rotation, other.rotation):
193
+ return False
194
+ if not np.array_equal(self.target_translation, other.target_translation):
195
+ return False
196
+ return True
197
+
198
+
199
+ def _expand_dims(array, n_dims):
200
+ """
201
+ Expand the dimensions of an `ndarray` to a certain number of
202
+ dimensions.
203
+ """
204
+ while array.ndim < n_dims:
205
+ array = array[np.newaxis, ...]
206
+ return array
207
+
208
+
209
+ def _3d_identity(m, n):
210
+ """
211
+ Create an array of *m* identity matrices of shape *(n, n)*
212
+ """
213
+ matrices = np.zeros((m, n, n), dtype=float)
214
+ indices = np.arange(n)
215
+ matrices[:, indices, indices] = 1
216
+ return matrices
217
+
218
+
219
+ def _reshape_to_3d(coord):
220
+ """
221
+ Reshape the coordinate array to 3D, if it is 2D.
222
+ """
223
+ if coord.ndim < 2:
224
+ raise ValueError("Coordinates must be at least two-dimensional")
225
+ if coord.ndim == 2:
226
+ return coord[np.newaxis, ...]
227
+ elif coord.ndim == 3:
228
+ return coord
229
+ else:
230
+ raise ValueError("Coordinates must be at most three-dimensional")
231
+
232
+
27
233
  def translate(atoms, vector):
28
234
  """
29
235
  Translate the given atoms or coordinates by a given vector.
@@ -33,7 +239,7 @@ def translate(atoms, vector):
33
239
  atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
34
240
  The atoms of which the coordinates are transformed.
35
241
  The coordinates can be directly provided as :class:`ndarray`.
36
- vector: array-like, shape=(3,) or shape=(n,3) or shape=(m,n,3)
242
+ vector : array-like, shape=(3,) or shape=(n,3) or shape=(m,n,3)
37
243
  The translation vector :math:`(x, y, z)`.
38
244
 
39
245
  Returns
@@ -64,7 +270,7 @@ def rotate(atoms, angles):
64
270
  atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
65
271
  The atoms of which the coordinates are transformed.
66
272
  The coordinates can be directly provided as :class:`ndarray`.
67
- angles: array-like, length=3
273
+ angles : array-like, length=3
68
274
  The rotation angles in radians around *x*, *y* and *z*.
69
275
 
70
276
  Returns
@@ -75,8 +281,8 @@ def rotate(atoms, angles):
75
281
 
76
282
  See Also
77
283
  --------
78
- rotate_centered
79
- rotate_about_axis
284
+ rotate_centered : Rotate atoms about the centroid.
285
+ rotate_about_axis : Rotate atoms about a given axis.
80
286
 
81
287
  Examples
82
288
  --------
@@ -136,7 +342,7 @@ def rotate_centered(atoms, angles):
136
342
  atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
137
343
  The atoms of which the coordinates are transformed.
138
344
  The coordinates can be directly provided as :class:`ndarray`.
139
- angles: array-like, length=3
345
+ angles : array-like, length=3
140
346
  The rotation angles in radians around axes *x*, *y* and *z*.
141
347
 
142
348
  Returns
@@ -147,9 +353,12 @@ def rotate_centered(atoms, angles):
147
353
 
148
354
  See Also
149
355
  --------
150
- rotate
151
- rotate_about_axis
356
+ rotate : Rotate atoms about the origin.
357
+ rotate_about_axis : Rotate atoms about a given axis.
152
358
  """
359
+ # Avoid circular import
360
+ from biotite.structure.geometry import centroid
361
+
153
362
  if len(coord(atoms).shape) == 1:
154
363
  # Single value -> centered rotation does not change coordinates
155
364
  return atoms.copy()
@@ -193,8 +402,8 @@ def rotate_about_axis(atoms, axis, angle, support=None):
193
402
 
194
403
  See Also
195
404
  --------
196
- rotate
197
- rotate_centered
405
+ rotate : Rotate atoms about the origin.
406
+ rotate_centered : Rotate atoms about the centroid.
198
407
 
199
408
  Examples
200
409
  --------
@@ -293,11 +502,6 @@ def orient_principal_components(atoms, order=None):
293
502
  The atoms with coordinates centered at the orgin and aligned with
294
503
  xyz axes.
295
504
 
296
- See Also
297
- --------
298
- rotate_centered
299
- rotate_about_axis
300
-
301
505
  Examples
302
506
  --------
303
507
  Align principal components to xyz axes (default), or specify the order
@@ -321,8 +525,7 @@ def orient_principal_components(atoms, order=None):
321
525
  row, col = coords.shape
322
526
  if (row < 3) or (col != 3):
323
527
  raise ValueError(
324
- f"Expected at least 3 entries, {row} given,"
325
- f" and 3 dimensions, {col} given."
528
+ f"Expected at least 3 entries, {row} given, and 3 dimensions, {col} given."
326
529
  )
327
530
  if order is None:
328
531
  order = np.array([0, 1, 2])
@@ -400,11 +603,6 @@ def align_vectors(
400
603
  A copy of the input atoms or coordinates with the applied
401
604
  transformation.
402
605
 
403
- See Also
404
- --------
405
- rotate
406
- rotate_centered
407
-
408
606
  Examples
409
607
  --------
410
608
  Align two different residues at their CA-CB bond, i.e. the CA and CB
@@ -467,13 +665,11 @@ def align_vectors(
467
665
  # check that original and target direction are vectors of shape (3,)
468
666
  if origin_direction.shape != (3,):
469
667
  raise ValueError(
470
- f"Expected origin vector to have shape (3,), "
471
- f"got {origin_direction.shape}"
668
+ f"Expected origin vector to have shape (3,), got {origin_direction.shape}"
472
669
  )
473
670
  if target_direction.shape != (3,):
474
671
  raise ValueError(
475
- f"Expected target vector to have shape (3,), "
476
- f"got {target_direction.shape}"
672
+ f"Expected target vector to have shape (3,), got {target_direction.shape}"
477
673
  )
478
674
  if np.linalg.norm(origin_direction) == 0:
479
675
  raise ValueError("Length of the origin vector is 0")
@@ -528,3 +724,13 @@ def _put_back(input_atoms, transformed):
528
724
  return moved_atoms
529
725
  else:
530
726
  return transformed
727
+
728
+
729
+ def _multi_matmul(matrices, vectors):
730
+ """
731
+ Calculate the matrix multiplication of m matrices
732
+ with m x n vectors.
733
+ """
734
+ return np.transpose(
735
+ np.matmul(matrices, np.transpose(vectors, axes=(0, 2, 1))), axes=(0, 2, 1)
736
+ )
biotite/structure/util.py CHANGED
@@ -3,7 +3,7 @@
3
3
  # information.
4
4
 
5
5
  """
6
- Utility functions for in internal use in `Bio.Structure` package
6
+ Utility functions for in internal use in `Bio.Structure` package.
7
7
  """
8
8
 
9
9
  __name__ = "biotite.structure"
@@ -28,7 +28,7 @@ def vector_dot(v1, v2):
28
28
 
29
29
  Parameters
30
30
  ----------
31
- v1,v2 : ndarray
31
+ v1, v2 : ndarray
32
32
  The arrays to calculate the product from.
33
33
  The vectors are represented by the last axis.
34
34
 
@@ -63,7 +63,7 @@ def distance(v1, v2):
63
63
 
64
64
  Parameters
65
65
  ----------
66
- v1,v2 : ndarray
66
+ v1, v2 : ndarray
67
67
  The arrays to calculate the product from.
68
68
  The vectors are represented by the last axis.
69
69
 
biotite/version.py CHANGED
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '1.1.0'
16
- __version_tuple__ = version_tuple = (1, 1, 0)
20
+ __version__ = version = '1.3.0'
21
+ __version_tuple__ = version_tuple = (1, 3, 0)
biotite/visualize.py CHANGED
@@ -4,12 +4,16 @@
4
4
 
5
5
  __name__ = "biotite"
6
6
  __author__ = "Patrick Kunzmann"
7
- __all__ = ["colors", "set_font_size_in_coord", "AdaptiveFancyArrow"]
7
+ __all__ = ["colors", "plot_scaled_text", "set_font_size_in_coord", "AdaptiveFancyArrow"]
8
8
 
9
+ import warnings
9
10
  from collections import OrderedDict
10
11
  import numpy as np
11
12
  from numpy.linalg import norm
12
13
 
14
+ _FONT_PROPERTY_KEYS = ["family", "style", "variant", "weight", "stretch", "size"]
15
+
16
+
13
17
  # Biotite themed colors
14
18
  colors = OrderedDict(
15
19
  [
@@ -27,6 +31,105 @@ colors = OrderedDict(
27
31
  )
28
32
 
29
33
 
34
+ def plot_scaled_text(
35
+ axes, text, x, y, width=None, height=None, mode="unlocked", **kwargs
36
+ ):
37
+ """
38
+ Create a :class:`matplotlib.textpath.TextPath`, whose text size is given in
39
+ coordinates instead of font size.
40
+
41
+ Parameters
42
+ ----------
43
+ axes : Axes
44
+ The axes to draw the text on.
45
+ text : str
46
+ The text to be drawn.
47
+ x, y : float
48
+ The lower left position of the text.
49
+ width, height : float, optional
50
+ The width/height `text` should have in its reference coordinate system.
51
+ At least one value must be supplied.
52
+ mode : {'proportional', 'unlocked', 'maximum', 'minimum'}, optional
53
+ Defines how the text size is scaled.
54
+ The scaling mode:
55
+
56
+ - *proportional* - The width and height are scaled by the
57
+ same extent.
58
+ Either `width` or `height` must be set for this mode.
59
+ - *unlocked* - The width and the height are scaled by
60
+ different extents, changing the aspect ratio of the text.
61
+ Both `width` and `height` must be set for this mode.
62
+ - *maximum* - The width and the height are scaled by
63
+ the same extent, so that they are at maximum as large
64
+ as the supplied `width`/`height`.
65
+ Both `width` and `height` must be set for this mode.
66
+ - *minimum* - The width and the height are scaled by
67
+ the same extent, so that they are at minimum as large
68
+ as the supplied `width`/`height`.
69
+ Both `width` and `height` must be set for this mode.
70
+
71
+ **kwargs
72
+ Additional parameters for the :class:`matplotlib.font_manager.FontProperties`
73
+ of the text or the created :class:`matplotlib.patches.PathPatch`.
74
+
75
+ Returns
76
+ -------
77
+ patch : matplotlib.patches.PathPatch
78
+ The patch that represents the text.
79
+ """
80
+ from matplotlib.patches import PathPatch
81
+ from matplotlib.textpath import TextPath
82
+ from matplotlib.transforms import Affine2D
83
+
84
+ # The larger the size, the more there is an offset at the x-axis
85
+ # -> Keep font size small to reduce this error to a minimum
86
+ # The size is transformed to the desired size afterwards anyway
87
+ font_property_kwargs = {
88
+ key: kwargs.pop(key) for key in _FONT_PROPERTY_KEYS if key in kwargs
89
+ }
90
+ path = TextPath((x, y), text, size=1e-3, prop=font_property_kwargs)
91
+ bbox = path.get_extents()
92
+
93
+ if mode == "proportional":
94
+ if width is None:
95
+ # Proportional scaling based on height
96
+ scale_y = height / bbox.height
97
+ scale_x = scale_y
98
+ elif height is None:
99
+ # Proportional scaling based on width
100
+ scale_x = width / bbox.width
101
+ scale_y = scale_x
102
+ else:
103
+ raise ValueError(
104
+ "width or height are mutually exclusive in 'proportional' mode"
105
+ )
106
+ elif mode == "unlocked":
107
+ scale_x = width / bbox.width
108
+ scale_y = height / bbox.height
109
+ elif mode == "minimum":
110
+ scale_x = width / bbox.width
111
+ scale_y = height / bbox.height
112
+ scale = max(scale_x, scale_y)
113
+ scale_x, scale_y = scale, scale
114
+ elif mode == "maximum":
115
+ scale_x = width / bbox.width
116
+ scale_y = height / bbox.height
117
+ scale = min(scale_x, scale_y)
118
+ scale_x, scale_y = scale, scale
119
+
120
+ path = (
121
+ Affine2D()
122
+ .translate(-bbox.x0, -bbox.y0)
123
+ .scale(scale_x, scale_y)
124
+ .translate(bbox.x0, bbox.y0)
125
+ .transform_path(path)
126
+ )
127
+ patch = PathPatch(path, **kwargs)
128
+ axes.add_patch(patch)
129
+
130
+ return patch
131
+
132
+
30
133
  def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
31
134
  """
32
135
  Specifiy the font size of an existing `Text` object in coordinates
@@ -38,6 +141,8 @@ def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
38
141
  The scaling can be proportional or non-proportional, depending
39
142
  the `mode`.
40
143
 
144
+ DEPRECATED: Use :func:`plot_scaled_text()` instead.
145
+
41
146
  Parameters
42
147
  ----------
43
148
  text : Text:
@@ -125,6 +230,11 @@ def set_font_size_in_coord(text, width=None, height=None, mode="unlocked"):
125
230
  affine = Affine2D().scale(scale_x, scale_y) + affine
126
231
  renderer.draw_path(gc, tpath, affine, rgbFace)
127
232
 
233
+ warnings.warn(
234
+ "Deprecated, use 'biotite.graphics.text.plot_scaled_text()' instead.",
235
+ DeprecationWarning,
236
+ )
237
+
128
238
  if mode in ["unlocked", "minimum", "maximum"]:
129
239
  if width is None or height is None:
130
240
  raise TypeError(f"Width and height must be set in '{mode}' mode")
@@ -1,46 +1,16 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: biotite
3
- Version: 1.1.0
3
+ Version: 1.3.0
4
4
  Summary: A comprehensive library for computational molecular biology
5
5
  Project-URL: homepage, https://www.biotite-python.org
6
6
  Project-URL: repository, https://github.com/biotite-dev/biotite
7
7
  Project-URL: documentation, https://www.biotite-python.org
8
8
  Author: The Biotite contributors
9
- License: BSD 3-Clause License
10
- --------------------
11
-
12
- Copyright 2017, The Biotite contributors
13
- All rights reserved.
14
-
15
- Redistribution and use in source and binary forms, with or without modification,
16
- are permitted provided that the following conditions are met:
17
-
18
- 1. Redistributions of source code must retain the above copyright notice, this
19
- list of conditions and the following disclaimer.
20
-
21
- 2. Redistributions in binary form must reproduce the above copyright notice,
22
- this list of conditions and the following disclaimer in the documentation and/or
23
- other materials provided with the distribution.
24
-
25
- 3. Neither the name of the copyright holder nor the names of its contributors
26
- may be used to endorse or promote products derived from this software without
27
- specific prior written permission.
28
-
29
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
33
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
36
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9
+ License-Expression: BSD-3-Clause
39
10
  License-File: LICENSE.rst
40
11
  Classifier: Development Status :: 5 - Production/Stable
41
12
  Classifier: Intended Audience :: Developers
42
13
  Classifier: Intended Audience :: Science/Research
43
- Classifier: License :: OSI Approved :: BSD License
44
14
  Classifier: Natural Language :: English
45
15
  Classifier: Operating System :: MacOS
46
16
  Classifier: Operating System :: Microsoft :: Windows
@@ -48,14 +18,16 @@ Classifier: Operating System :: POSIX :: Linux
48
18
  Classifier: Programming Language :: Python :: 3
49
19
  Classifier: Programming Language :: Python :: Implementation :: CPython
50
20
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
51
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.11
52
22
  Requires-Dist: biotraj<2.0,>=1.0
53
23
  Requires-Dist: msgpack>=0.5.6
54
24
  Requires-Dist: networkx>=2.0
55
25
  Requires-Dist: numpy>=1.25
26
+ Requires-Dist: packaging>=24.0
56
27
  Requires-Dist: requests>=2.12
57
28
  Provides-Extra: lint
58
- Requires-Dist: ruff==0.6.9; extra == 'lint'
29
+ Requires-Dist: numpydoc==1.8.0; extra == 'lint'
30
+ Requires-Dist: ruff==0.9.7; extra == 'lint'
59
31
  Provides-Extra: test
60
32
  Requires-Dist: pytest; extra == 'test'
61
33
  Requires-Dist: pytest-codspeed; extra == 'test'
@@ -186,5 +158,5 @@ Contribution
186
158
 
187
159
  Interested in improving *Biotite*?
188
160
  Have a look at the
189
- `contribution guidelines <https://www.biotite-python.org/contribute.html>`_.
161
+ `contribution guidelines <https://www.biotite-python.org/latest/contribution/index.html>`_.
190
162
  Feel free to join our community chat on `Discord <https://discord.gg/cUjDguF>`_.