biotite 0.41.2__cp312-cp312-macosx_11_0_arm64.whl → 1.0.0__cp312-cp312-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.

Files changed (205) hide show
  1. biotite/__init__.py +2 -3
  2. biotite/application/__init__.py +1 -1
  3. biotite/application/application.py +20 -10
  4. biotite/application/autodock/__init__.py +1 -1
  5. biotite/application/autodock/app.py +74 -79
  6. biotite/application/blast/__init__.py +1 -1
  7. biotite/application/blast/alignment.py +19 -10
  8. biotite/application/blast/webapp.py +92 -85
  9. biotite/application/clustalo/__init__.py +1 -1
  10. biotite/application/clustalo/app.py +46 -61
  11. biotite/application/dssp/__init__.py +1 -1
  12. biotite/application/dssp/app.py +8 -11
  13. biotite/application/localapp.py +62 -60
  14. biotite/application/mafft/__init__.py +1 -1
  15. biotite/application/mafft/app.py +16 -22
  16. biotite/application/msaapp.py +78 -89
  17. biotite/application/muscle/__init__.py +1 -1
  18. biotite/application/muscle/app3.py +50 -64
  19. biotite/application/muscle/app5.py +23 -31
  20. biotite/application/sra/__init__.py +1 -1
  21. biotite/application/sra/app.py +64 -68
  22. biotite/application/tantan/__init__.py +1 -1
  23. biotite/application/tantan/app.py +22 -45
  24. biotite/application/util.py +7 -9
  25. biotite/application/viennarna/rnaalifold.py +34 -28
  26. biotite/application/viennarna/rnafold.py +24 -39
  27. biotite/application/viennarna/rnaplot.py +36 -21
  28. biotite/application/viennarna/util.py +17 -12
  29. biotite/application/webapp.py +13 -14
  30. biotite/copyable.py +13 -13
  31. biotite/database/__init__.py +1 -1
  32. biotite/database/entrez/__init__.py +1 -1
  33. biotite/database/entrez/check.py +2 -3
  34. biotite/database/entrez/dbnames.py +7 -5
  35. biotite/database/entrez/download.py +55 -49
  36. biotite/database/entrez/key.py +1 -1
  37. biotite/database/entrez/query.py +62 -23
  38. biotite/database/error.py +2 -1
  39. biotite/database/pubchem/__init__.py +1 -1
  40. biotite/database/pubchem/download.py +43 -45
  41. biotite/database/pubchem/error.py +2 -2
  42. biotite/database/pubchem/query.py +34 -31
  43. biotite/database/pubchem/throttle.py +3 -4
  44. biotite/database/rcsb/__init__.py +1 -1
  45. biotite/database/rcsb/download.py +44 -52
  46. biotite/database/rcsb/query.py +85 -80
  47. biotite/database/uniprot/check.py +6 -3
  48. biotite/database/uniprot/download.py +6 -11
  49. biotite/database/uniprot/query.py +115 -31
  50. biotite/file.py +12 -31
  51. biotite/sequence/__init__.py +3 -3
  52. biotite/sequence/align/__init__.py +2 -2
  53. biotite/sequence/align/alignment.py +99 -90
  54. biotite/sequence/align/banded.cpython-312-darwin.so +0 -0
  55. biotite/sequence/align/buckets.py +12 -10
  56. biotite/sequence/align/cigar.py +43 -52
  57. biotite/sequence/align/kmeralphabet.cpython-312-darwin.so +0 -0
  58. biotite/sequence/align/kmeralphabet.pyx +55 -51
  59. biotite/sequence/align/kmersimilarity.cpython-312-darwin.so +0 -0
  60. biotite/sequence/align/kmertable.cpython-312-darwin.so +0 -0
  61. biotite/sequence/align/kmertable.pyx +3 -2
  62. biotite/sequence/align/localgapped.cpython-312-darwin.so +0 -0
  63. biotite/sequence/align/localungapped.cpython-312-darwin.so +0 -0
  64. biotite/sequence/align/matrix.py +81 -82
  65. biotite/sequence/align/multiple.cpython-312-darwin.so +0 -0
  66. biotite/sequence/align/multiple.pyx +1 -1
  67. biotite/sequence/align/pairwise.cpython-312-darwin.so +0 -0
  68. biotite/sequence/align/permutation.cpython-312-darwin.so +0 -0
  69. biotite/sequence/align/permutation.pyx +12 -4
  70. biotite/sequence/align/selector.cpython-312-darwin.so +0 -0
  71. biotite/sequence/align/selector.pyx +52 -54
  72. biotite/sequence/align/statistics.py +32 -33
  73. biotite/sequence/align/tracetable.cpython-312-darwin.so +0 -0
  74. biotite/sequence/alphabet.py +51 -65
  75. biotite/sequence/annotation.py +78 -77
  76. biotite/sequence/codec.cpython-312-darwin.so +0 -0
  77. biotite/sequence/codon.py +90 -79
  78. biotite/sequence/graphics/__init__.py +1 -1
  79. biotite/sequence/graphics/alignment.py +184 -103
  80. biotite/sequence/graphics/colorschemes.py +10 -12
  81. biotite/sequence/graphics/dendrogram.py +79 -34
  82. biotite/sequence/graphics/features.py +133 -99
  83. biotite/sequence/graphics/logo.py +22 -28
  84. biotite/sequence/graphics/plasmid.py +229 -178
  85. biotite/sequence/io/fasta/__init__.py +1 -1
  86. biotite/sequence/io/fasta/convert.py +44 -33
  87. biotite/sequence/io/fasta/file.py +42 -55
  88. biotite/sequence/io/fastq/__init__.py +1 -1
  89. biotite/sequence/io/fastq/convert.py +11 -14
  90. biotite/sequence/io/fastq/file.py +68 -112
  91. biotite/sequence/io/genbank/__init__.py +2 -2
  92. biotite/sequence/io/genbank/annotation.py +12 -20
  93. biotite/sequence/io/genbank/file.py +74 -76
  94. biotite/sequence/io/genbank/metadata.py +74 -62
  95. biotite/sequence/io/genbank/sequence.py +13 -14
  96. biotite/sequence/io/general.py +39 -30
  97. biotite/sequence/io/gff/__init__.py +2 -2
  98. biotite/sequence/io/gff/convert.py +10 -15
  99. biotite/sequence/io/gff/file.py +81 -65
  100. biotite/sequence/phylo/__init__.py +1 -1
  101. biotite/sequence/phylo/nj.cpython-312-darwin.so +0 -0
  102. biotite/sequence/phylo/tree.cpython-312-darwin.so +0 -0
  103. biotite/sequence/phylo/upgma.cpython-312-darwin.so +0 -0
  104. biotite/sequence/profile.py +57 -28
  105. biotite/sequence/search.py +17 -15
  106. biotite/sequence/seqtypes.py +200 -164
  107. biotite/sequence/sequence.py +15 -17
  108. biotite/structure/__init__.py +3 -3
  109. biotite/structure/atoms.py +221 -235
  110. biotite/structure/basepairs.py +260 -271
  111. biotite/structure/bonds.cpython-312-darwin.so +0 -0
  112. biotite/structure/bonds.pyx +29 -32
  113. biotite/structure/box.py +67 -71
  114. biotite/structure/celllist.cpython-312-darwin.so +0 -0
  115. biotite/structure/chains.py +55 -39
  116. biotite/structure/charges.cpython-312-darwin.so +0 -0
  117. biotite/structure/compare.py +32 -32
  118. biotite/structure/density.py +13 -18
  119. biotite/structure/dotbracket.py +20 -22
  120. biotite/structure/error.py +10 -2
  121. biotite/structure/filter.py +82 -77
  122. biotite/structure/geometry.py +130 -119
  123. biotite/structure/graphics/atoms.py +60 -43
  124. biotite/structure/graphics/rna.py +81 -68
  125. biotite/structure/hbond.py +112 -93
  126. biotite/structure/info/__init__.py +0 -2
  127. biotite/structure/info/atoms.py +10 -11
  128. biotite/structure/info/bonds.py +41 -43
  129. biotite/structure/info/ccd.py +4 -5
  130. biotite/structure/info/groups.py +1 -3
  131. biotite/structure/info/masses.py +5 -10
  132. biotite/structure/info/misc.py +1 -1
  133. biotite/structure/info/radii.py +20 -20
  134. biotite/structure/info/standardize.py +15 -26
  135. biotite/structure/integrity.py +18 -71
  136. biotite/structure/io/__init__.py +3 -4
  137. biotite/structure/io/dcd/__init__.py +1 -1
  138. biotite/structure/io/dcd/file.py +22 -20
  139. biotite/structure/io/general.py +47 -61
  140. biotite/structure/io/gro/__init__.py +1 -1
  141. biotite/structure/io/gro/file.py +73 -72
  142. biotite/structure/io/mol/__init__.py +1 -1
  143. biotite/structure/io/mol/convert.py +8 -11
  144. biotite/structure/io/mol/ctab.py +37 -36
  145. biotite/structure/io/mol/header.py +14 -10
  146. biotite/structure/io/mol/mol.py +9 -53
  147. biotite/structure/io/mol/sdf.py +47 -50
  148. biotite/structure/io/netcdf/__init__.py +1 -1
  149. biotite/structure/io/netcdf/file.py +24 -23
  150. biotite/structure/io/pdb/__init__.py +1 -1
  151. biotite/structure/io/pdb/convert.py +32 -20
  152. biotite/structure/io/pdb/file.py +151 -172
  153. biotite/structure/io/pdb/hybrid36.cpython-312-darwin.so +0 -0
  154. biotite/structure/io/pdbqt/__init__.py +1 -1
  155. biotite/structure/io/pdbqt/convert.py +17 -11
  156. biotite/structure/io/pdbqt/file.py +128 -80
  157. biotite/structure/io/pdbx/__init__.py +1 -2
  158. biotite/structure/io/pdbx/bcif.py +36 -44
  159. biotite/structure/io/pdbx/cif.py +64 -62
  160. biotite/structure/io/pdbx/component.py +10 -16
  161. biotite/structure/io/pdbx/convert.py +235 -246
  162. biotite/structure/io/pdbx/encoding.cpython-312-darwin.so +0 -0
  163. biotite/structure/io/trajfile.py +76 -93
  164. biotite/structure/io/trr/__init__.py +1 -1
  165. biotite/structure/io/trr/file.py +12 -15
  166. biotite/structure/io/xtc/__init__.py +1 -1
  167. biotite/structure/io/xtc/file.py +11 -14
  168. biotite/structure/mechanics.py +9 -11
  169. biotite/structure/molecules.py +3 -4
  170. biotite/structure/pseudoknots.py +53 -67
  171. biotite/structure/rdf.py +23 -21
  172. biotite/structure/repair.py +137 -86
  173. biotite/structure/residues.py +26 -16
  174. biotite/structure/sasa.cpython-312-darwin.so +0 -0
  175. biotite/structure/{resutil.py → segments.py} +24 -23
  176. biotite/structure/sequence.py +10 -11
  177. biotite/structure/sse.py +100 -119
  178. biotite/structure/superimpose.py +39 -77
  179. biotite/structure/transform.py +97 -71
  180. biotite/structure/util.py +11 -13
  181. biotite/version.py +2 -2
  182. biotite/visualize.py +69 -55
  183. {biotite-0.41.2.dist-info → biotite-1.0.0.dist-info}/METADATA +5 -5
  184. biotite-1.0.0.dist-info/RECORD +322 -0
  185. biotite/structure/io/ctab.py +0 -72
  186. biotite/structure/io/mmtf/__init__.py +0 -21
  187. biotite/structure/io/mmtf/assembly.py +0 -214
  188. biotite/structure/io/mmtf/convertarray.cpython-312-darwin.so +0 -0
  189. biotite/structure/io/mmtf/convertarray.pyx +0 -341
  190. biotite/structure/io/mmtf/convertfile.cpython-312-darwin.so +0 -0
  191. biotite/structure/io/mmtf/convertfile.pyx +0 -501
  192. biotite/structure/io/mmtf/decode.cpython-312-darwin.so +0 -0
  193. biotite/structure/io/mmtf/decode.pyx +0 -152
  194. biotite/structure/io/mmtf/encode.cpython-312-darwin.so +0 -0
  195. biotite/structure/io/mmtf/encode.pyx +0 -183
  196. biotite/structure/io/mmtf/file.py +0 -233
  197. biotite/structure/io/npz/__init__.py +0 -20
  198. biotite/structure/io/npz/file.py +0 -152
  199. biotite/structure/io/pdbx/legacy.py +0 -267
  200. biotite/structure/io/tng/__init__.py +0 -13
  201. biotite/structure/io/tng/file.py +0 -46
  202. biotite/temp.py +0 -86
  203. biotite-0.41.2.dist-info/RECORD +0 -340
  204. {biotite-0.41.2.dist-info → biotite-1.0.0.dist-info}/WHEEL +0 -0
  205. {biotite-0.41.2.dist-info → biotite-1.0.0.dist-info}/licenses/LICENSE.rst +0 -0
@@ -4,19 +4,27 @@
4
4
 
5
5
  """
6
6
  This module contains the main types of the ``structure`` subpackage:
7
- :class:`Atom`, :class:`AtomArray` and :class:`AtomArrayStack`.
7
+ :class:`Atom`, :class:`AtomArray` and :class:`AtomArrayStack`.
8
8
  """
9
9
 
10
10
  __name__ = "biotite.structure"
11
11
  __author__ = "Patrick Kunzmann"
12
- __all__ = ["Atom", "AtomArray", "AtomArrayStack",
13
- "array", "stack", "repeat", "from_template", "coord"]
12
+ __all__ = [
13
+ "Atom",
14
+ "AtomArray",
15
+ "AtomArrayStack",
16
+ "array",
17
+ "stack",
18
+ "repeat",
19
+ "from_template",
20
+ "coord",
21
+ ]
14
22
 
15
- import numbers
16
23
  import abc
24
+ import numbers
17
25
  import numpy as np
18
- from .bonds import BondList
19
- from ..copyable import Copyable
26
+ from biotite.copyable import Copyable
27
+ from biotite.structure.bonds import BondList
20
28
 
21
29
 
22
30
  class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
@@ -26,7 +34,7 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
26
34
  It implements functionality for annotation arrays and also
27
35
  rudimentarily for coordinates.
28
36
  """
29
-
37
+
30
38
  def __init__(self, length):
31
39
  """
32
40
  Create the annotation arrays
@@ -43,14 +51,14 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
43
51
  self.add_annotation("hetero", dtype=bool)
44
52
  self.add_annotation("atom_name", dtype="U6")
45
53
  self.add_annotation("element", dtype="U2")
46
-
54
+
47
55
  def array_length(self):
48
56
  """
49
57
  Get the length of the atom array.
50
-
58
+
51
59
  This value is equivalent to the length of each annotation array.
52
60
  For :class:`AtomArray` it is the same as ``len(array)``.
53
-
61
+
54
62
  Returns
55
63
  -------
56
64
  length : int
@@ -71,15 +79,15 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
71
79
  shape : tuple of int
72
80
  Shape of the object.
73
81
  """
74
- return
75
-
82
+ return
83
+
76
84
  def add_annotation(self, category, dtype):
77
85
  """
78
86
  Add an annotation category, if not already existing.
79
-
87
+
80
88
  Initially the new annotation is filled with the *zero*
81
89
  representation of the given type.
82
-
90
+
83
91
  Parameters
84
92
  ----------
85
93
  category : str
@@ -87,19 +95,18 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
87
95
  dtype : type or str
88
96
  A type instance or a valid *NumPy* *dtype* string.
89
97
  Defines the type of the annotation
90
-
98
+
91
99
  See Also
92
100
  --------
93
101
  set_annotation
94
102
  """
95
103
  if category not in self._annot:
96
- self._annot[str(category)] = np.zeros(self._array_length,
97
- dtype=dtype)
98
-
104
+ self._annot[str(category)] = np.zeros(self._array_length, dtype=dtype)
105
+
99
106
  def del_annotation(self, category):
100
107
  """
101
108
  Removes an annotation category.
102
-
109
+
103
110
  Parameters
104
111
  ----------
105
112
  category : str
@@ -107,32 +114,30 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
107
114
  """
108
115
  if category in self._annot:
109
116
  del self._annot[str(category)]
110
-
117
+
111
118
  def get_annotation(self, category):
112
119
  """
113
120
  Return an annotation array.
114
-
121
+
115
122
  Parameters
116
123
  ----------
117
124
  category : str
118
125
  The annotation category to be returned.
119
-
126
+
120
127
  Returns
121
128
  -------
122
129
  array : ndarray
123
130
  The annotation array.
124
131
  """
125
132
  if category not in self._annot:
126
- raise ValueError(
127
- f"Annotation category '{category}' is not existing"
128
- )
133
+ raise ValueError(f"Annotation category '{category}' is not existing")
129
134
  return self._annot[category]
130
-
135
+
131
136
  def set_annotation(self, category, array):
132
137
  """
133
138
  Set an annotation array. If the annotation category does not
134
139
  exist yet, the category is created.
135
-
140
+
136
141
  Parameters
137
142
  ----------
138
143
  category : str
@@ -143,28 +148,25 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
143
148
  """
144
149
  if len(array) != self._array_length:
145
150
  raise IndexError(
146
- f"Expected array length {self._array_length}, "
147
- f"but got {len(array)}"
151
+ f"Expected array length {self._array_length}, " f"but got {len(array)}"
148
152
  )
149
153
  if category in self._annot:
150
154
  # Keep the dtype if the annotation already exists
151
- self._annot[category] = np.asarray(
152
- array, dtype=self._annot[category].dtype
153
- )
155
+ self._annot[category] = np.asarray(array, dtype=self._annot[category].dtype)
154
156
  else:
155
157
  self._annot[category] = np.asarray(array)
156
-
158
+
157
159
  def get_annotation_categories(self):
158
160
  """
159
161
  Return a list containing all annotation array categories.
160
-
162
+
161
163
  Returns
162
164
  -------
163
165
  categories : list
164
166
  The list containing the names of each annotation array.
165
167
  """
166
168
  return list(self._annot.keys())
167
-
169
+
168
170
  def _subarray(self, index):
169
171
  # Index is one dimensional (boolean mask, index array)
170
172
  new_coord = self._coord[..., index, :]
@@ -180,10 +182,9 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
180
182
  if self._box is not None:
181
183
  new_object._box = self._box
182
184
  for annotation in self._annot:
183
- new_object._annot[annotation] = (self._annot[annotation]
184
- .__getitem__(index))
185
+ new_object._annot[annotation] = self._annot[annotation].__getitem__(index)
185
186
  return new_object
186
-
187
+
187
188
  def _set_element(self, index, atom):
188
189
  try:
189
190
  if isinstance(index, (numbers.Integral, np.ndarray)):
@@ -191,12 +192,10 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
191
192
  self._annot[name][index] = atom._annot[name]
192
193
  self._coord[..., index, :] = atom.coord
193
194
  else:
194
- raise TypeError(
195
- f"Index must be integer, not '{type(index).__name__}'"
196
- )
195
+ raise TypeError(f"Index must be integer, not '{type(index).__name__}'")
197
196
  except KeyError:
198
197
  raise KeyError("The annotations of the 'Atom' are incompatible")
199
-
198
+
200
199
  def _del_element(self, index):
201
200
  if isinstance(index, numbers.Integral):
202
201
  for name in self._annot:
@@ -208,20 +207,18 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
208
207
  mask[index] = False
209
208
  self._bonds = self._bonds[mask]
210
209
  else:
211
- raise TypeError(
212
- f"Index must be integer, not '{type(index).__name__}'"
213
- )
214
-
210
+ raise TypeError(f"Index must be integer, not '{type(index).__name__}'")
211
+
215
212
  def equal_annotations(self, item):
216
213
  """
217
214
  Check, if this object shares equal annotation arrays with the
218
215
  given :class:`AtomArray` or :class:`AtomArrayStack`.
219
-
216
+
220
217
  Parameters
221
218
  ----------
222
219
  item : AtomArray or AtomArrayStack
223
220
  The object to compare the annotation arrays with.
224
-
221
+
225
222
  Returns
226
223
  -------
227
224
  equality : bool
@@ -235,24 +232,24 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
235
232
  if not np.array_equal(self._annot[name], item._annot[name]):
236
233
  return False
237
234
  return True
238
-
235
+
239
236
  def equal_annotation_categories(self, item):
240
237
  """
241
238
  Check, if this object shares equal annotation array categories
242
239
  with the given :class:`AtomArray` or :class:`AtomArrayStack`.
243
-
240
+
244
241
  Parameters
245
242
  ----------
246
243
  item : AtomArray or AtomArrayStack
247
244
  The object to compare the annotation arrays with.
248
-
245
+
249
246
  Returns
250
247
  -------
251
248
  equality : bool
252
249
  True, if the annotation array names are equal.
253
250
  """
254
251
  return sorted(self._annot.keys()) == sorted(item._annot.keys())
255
-
252
+
256
253
  def __getattr__(self, attr):
257
254
  """
258
255
  If the attribute is an annotation, the annotation is returned
@@ -273,7 +270,7 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
273
270
  raise AttributeError(
274
271
  f"'{type(self).__name__}' object has no attribute '{attr}'"
275
272
  )
276
-
273
+
277
274
  def __setattr__(self, attr, value):
278
275
  """
279
276
  If the attribute is an annotation, the :attr:`value` is saved
@@ -287,15 +284,13 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
287
284
  if isinstance(self, AtomArray):
288
285
  if value.ndim != 2:
289
286
  raise ValueError(
290
- "A 2-dimensional ndarray is expected "
291
- "for an AtomArray"
292
- )
287
+ "A 2-dimensional ndarray is expected " "for an AtomArray"
288
+ )
293
289
  elif isinstance(self, AtomArrayStack):
294
290
  if value.ndim != 3:
295
291
  raise ValueError(
296
- "A 3-dimensional ndarray is expected "
297
- "for an AtomArrayStack"
298
- )
292
+ "A 3-dimensional ndarray is expected " "for an AtomArrayStack"
293
+ )
299
294
  if value.shape[-2] != self._array_length:
300
295
  raise ValueError(
301
296
  f"Expected array length {self._array_length}, "
@@ -304,7 +299,7 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
304
299
  if value.shape[-1] != 3:
305
300
  raise TypeError("Expected 3 coordinates for each atom")
306
301
  super().__setattr__("_coord", value.astype(np.float32, copy=False))
307
-
302
+
308
303
  elif attr == "bonds":
309
304
  if isinstance(value, BondList):
310
305
  if value.get_atom_count() != self._array_length:
@@ -318,22 +313,21 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
318
313
  super().__setattr__("_bonds", None)
319
314
  else:
320
315
  raise TypeError("Value must be 'BondList'")
321
-
316
+
322
317
  elif attr == "box":
323
318
  if isinstance(value, np.ndarray):
324
319
  if isinstance(self, AtomArray):
325
320
  if value.ndim != 2:
326
321
  raise ValueError(
327
- "A 2-dimensional ndarray is expected "
328
- "for an AtomArray"
329
- )
330
- else: # AtomArrayStack
322
+ "A 2-dimensional ndarray is expected " "for an AtomArray"
323
+ )
324
+ else: # AtomArrayStack
331
325
  if value.ndim != 3:
332
326
  raise ValueError(
333
327
  "A 3-dimensional ndarray is expected "
334
328
  "for an AtomArrayStack"
335
- )
336
- if value.shape[-2:] != (3,3):
329
+ )
330
+ if value.shape[-2:] != (3, 3):
337
331
  raise TypeError("Box must be a 3x3 matrix (three vectors)")
338
332
  box = value.astype(np.float32, copy=False)
339
333
  super().__setattr__("_box", box)
@@ -342,14 +336,14 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
342
336
  super().__setattr__("_box", None)
343
337
  else:
344
338
  raise TypeError("Box must be ndarray of floats or None")
345
-
339
+
346
340
  elif attr == "_annot":
347
341
  super().__setattr__(attr, value)
348
342
  elif attr in self._annot:
349
343
  self.set_annotation(attr, value)
350
344
  else:
351
345
  super().__setattr__(attr, value)
352
-
346
+
353
347
  def __dir__(self):
354
348
  attr = super().__dir__()
355
349
  attr.append("coord")
@@ -358,7 +352,7 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
358
352
  for name in self._annot.keys():
359
353
  attr.append(name)
360
354
  return attr
361
-
355
+
362
356
  def __eq__(self, item):
363
357
  """
364
358
  See Also
@@ -376,30 +370,31 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
376
370
  if not np.array_equal(self._box, item._box):
377
371
  return False
378
372
  return np.array_equal(self._coord, item._coord)
379
-
373
+
380
374
  def __len__(self):
381
375
  """
382
376
  The length of the annotation arrays.
383
-
377
+
384
378
  Returns
385
379
  -------
386
380
  length : int
387
381
  Length of the annotation arrays.
388
382
  """
389
383
  return self._array_length
390
-
384
+
391
385
  def __add__(self, array):
392
- if type(self) != type(array):
386
+ if not isinstance(self, type(array)):
393
387
  raise TypeError("Can only concatenate two arrays or two stacks")
394
388
  # Create either new array or stack, depending of the own type
395
389
  if isinstance(self, AtomArray):
396
- concat = AtomArray(length = self._array_length+array._array_length)
390
+ concat = AtomArray(length=self._array_length + array._array_length)
397
391
  if isinstance(self, AtomArrayStack):
398
- concat = AtomArrayStack(self.stack_depth(),
399
- self._array_length + array._array_length)
400
-
392
+ concat = AtomArrayStack(
393
+ self.stack_depth(), self._array_length + array._array_length
394
+ )
395
+
401
396
  concat._coord = np.concatenate((self._coord, array.coord), axis=-2)
402
-
397
+
403
398
  # Transfer only annotations,
404
399
  # which are existent in both operands
405
400
  arr_categories = list(array._annot.keys())
@@ -407,29 +402,29 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
407
402
  if category in arr_categories:
408
403
  annot = self._annot[category]
409
404
  arr_annot = array._annot[category]
410
- concat._annot[category] = np.concatenate((annot,arr_annot))
411
-
405
+ concat._annot[category] = np.concatenate((annot, arr_annot))
406
+
412
407
  # Concatenate bonds lists,
413
408
  # if at least one of them contains bond information
414
409
  if self._bonds is not None or array._bonds is not None:
415
410
  bonds1 = self._bonds
416
411
  bonds2 = array._bonds
417
412
  if bonds1 is None:
418
- bonds1 = BondList(self._array_length)
413
+ bonds1 = BondList(self._array_length)
419
414
  if bonds2 is None:
420
415
  bonds2 = BondList(array._array_length)
421
416
  concat._bonds = bonds1 + bonds2
422
-
417
+
423
418
  # Copy box
424
419
  if self._box is not None:
425
420
  concat._box = np.copy(self._box)
426
421
  return concat
427
-
422
+
428
423
  def __copy_fill__(self, clone):
429
424
  super().__copy_fill__(clone)
430
425
  self._copy_annotations(clone)
431
426
  clone._coord = np.copy(self._coord)
432
-
427
+
433
428
  def _copy_annotations(self, clone):
434
429
  for name in self._annot:
435
430
  clone._annot[name] = np.copy(self._annot[name])
@@ -437,23 +432,23 @@ class _AtomArrayBase(Copyable, metaclass=abc.ABCMeta):
437
432
  clone._box = np.copy(self._box)
438
433
  if self._bonds is not None:
439
434
  clone._bonds = self._bonds.copy()
440
-
435
+
441
436
 
442
437
  class Atom(Copyable):
443
438
  """
444
439
  A representation of a single atom.
445
-
440
+
446
441
  The coordinates an annotations can be accessed directly.
447
442
  A detailed description of each annotation category can be viewed
448
443
  :doc:`here </apidoc/biotite.structure>`.
449
-
444
+
450
445
  Parameters
451
446
  ----------
452
447
  coord: list or ndarray
453
448
  The x, y and z coordinates.
454
449
  kwargs
455
450
  Atom annotations as key value pair.
456
-
451
+
457
452
  Attributes
458
453
  ----------
459
454
  {annot} : scalar
@@ -463,19 +458,19 @@ class Atom(Copyable):
463
458
  shape : tuple of int
464
459
  Shape of the object.
465
460
  In case of an :class:`Atom`, the tuple is empty.
466
-
461
+
467
462
  Examples
468
463
  --------
469
-
464
+
470
465
  >>> atom = Atom([1,2,3], chain_id="A")
471
466
  >>> atom.atom_name = "CA"
472
467
  >>> print(atom.atom_name)
473
468
  CA
474
469
  >>> print(atom.coord)
475
470
  [1. 2. 3.]
476
-
471
+
477
472
  """
478
-
473
+
479
474
  def __init__(self, coord, **kwargs):
480
475
  self._annot = {}
481
476
  self._annot["chain_id"] = ""
@@ -500,17 +495,17 @@ class Atom(Copyable):
500
495
  """Represent Atom as a string for debugging."""
501
496
  # print out key-value pairs and format strings in quotation marks
502
497
  annot_parts = [
503
- f'{key}="{value}"' if isinstance(value, str) else f'{key}={value}'
498
+ f'{key}="{value}"' if isinstance(value, str) else f"{key}={value}"
504
499
  for key, value in self._annot.items()
505
500
  ]
506
501
 
507
- annot = ', '.join(annot_parts)
508
- return f'Atom(np.{np.array_repr(self.coord)}, {annot})'
502
+ annot = ", ".join(annot_parts)
503
+ return f"Atom(np.{np.array_repr(self.coord)}, {annot})"
509
504
 
510
505
  @property
511
506
  def shape(self):
512
507
  return ()
513
-
508
+
514
509
  def __getattr__(self, attr):
515
510
  if attr in super().__getattribute__("_annot"):
516
511
  return self._annot[attr]
@@ -518,7 +513,7 @@ class Atom(Copyable):
518
513
  raise AttributeError(
519
514
  f"'{type(self).__name__}' object has no attribute '{attr}'"
520
515
  )
521
-
516
+
522
517
  def __setattr__(self, attr, value):
523
518
  if attr == "_annot":
524
519
  super().__setattr__(attr, value)
@@ -526,16 +521,18 @@ class Atom(Copyable):
526
521
  super().__setattr__(attr, value)
527
522
  else:
528
523
  self._annot[attr] = value
529
-
524
+
530
525
  def __str__(self):
531
526
  hetero = "HET" if self.hetero else ""
532
- return f"{hetero:3} {self.chain_id:3} " \
533
- f"{self.res_id:5d}{self.ins_code:1} {self.res_name:3} " \
534
- f"{self.atom_name:6} {self.element:2} " \
535
- f"{self.coord[0]:8.3f} " \
536
- f"{self.coord[1]:8.3f} " \
537
- f"{self.coord[2]:8.3f}"
538
-
527
+ return (
528
+ f"{hetero:3} {self.chain_id:3} "
529
+ f"{self.res_id:5d}{self.ins_code:1} {self.res_name:3} "
530
+ f"{self.atom_name:6} {self.element:2} "
531
+ f"{self.coord[0]:8.3f} "
532
+ f"{self.coord[1]:8.3f} "
533
+ f"{self.coord[2]:8.3f}"
534
+ )
535
+
539
536
  def __eq__(self, item):
540
537
  if not isinstance(item, Atom):
541
538
  return False
@@ -547,18 +544,18 @@ class Atom(Copyable):
547
544
  if self._annot[name] != item._annot[name]:
548
545
  return False
549
546
  return True
550
-
547
+
551
548
  def __ne__(self, item):
552
549
  return not self == item
553
-
550
+
554
551
  def __copy_create__(self):
555
552
  return Atom(self.coord, **self._annot)
556
553
 
557
-
554
+
558
555
  class AtomArray(_AtomArrayBase):
559
556
  """
560
557
  An array representation of a model consisting of multiple atoms.
561
-
558
+
562
559
  An :class:`AtomArray` can be seen as a list of :class:`Atom`
563
560
  instances.
564
561
  Instead of using directly a list, this class uses an *NumPy*
@@ -573,14 +570,14 @@ class AtomArray(_AtomArrayBase):
573
570
  or :func:`set_annotation()`.
574
571
  A detailed description of each annotation category can be viewed
575
572
  :doc:`here </apidoc/biotite.structure>`.
576
-
573
+
577
574
  In order to get an an subarray of an :class:`AtomArray`,
578
575
  *NumPy* style indexing is used.
579
576
  This includes slices, boolean arrays, index arrays and even
580
577
  *Ellipsis* notation.
581
578
  Using a single integer as index returns a single :class:`Atom`
582
579
  instance.
583
-
580
+
584
581
  Inserting or appending an :class:`AtomArray` to another
585
582
  :class:`AtomArray` is done with the '+' operator.
586
583
  Only the annotation categories, which are existing in both arrays,
@@ -611,7 +608,7 @@ class AtomArray(_AtomArrayBase):
611
608
  ----------
612
609
  length : int
613
610
  The fixed amount of atoms in the array.
614
-
611
+
615
612
  Attributes
616
613
  ----------
617
614
  {annot} : ndarray
@@ -629,44 +626,44 @@ class AtomArray(_AtomArrayBase):
629
626
  Shape of the atom array.
630
627
  The single value in the tuple is
631
628
  the length of the atom array.
632
-
629
+
633
630
  Examples
634
631
  --------
635
632
  Creating an atom array from atoms:
636
-
633
+
637
634
  >>> atom1 = Atom([1,2,3], chain_id="A")
638
635
  >>> atom2 = Atom([2,3,4], chain_id="A")
639
636
  >>> atom3 = Atom([3,4,5], chain_id="B")
640
637
  >>> atom_array = array([atom1, atom2, atom3])
641
638
  >>> print(atom_array.array_length())
642
639
  3
643
-
640
+
644
641
  Accessing an annotation array:
645
-
642
+
646
643
  >>> print(atom_array.chain_id)
647
644
  ['A' 'A' 'B']
648
-
645
+
649
646
  Accessing the coordinates:
650
-
647
+
651
648
  >>> print(atom_array.coord)
652
649
  [[1. 2. 3.]
653
650
  [2. 3. 4.]
654
651
  [3. 4. 5.]]
655
-
652
+
656
653
  *NumPy* style filtering:
657
-
654
+
658
655
  >>> atom_array = atom_array[atom_array.chain_id == "A"]
659
656
  >>> print(atom_array.array_length())
660
657
  2
661
-
658
+
662
659
  Inserting an atom array:
663
-
660
+
664
661
  >>> insert = array([Atom([7,8,9], chain_id="C")])
665
662
  >>> atom_array = atom_array[0:1] + insert + atom_array[1:2]
666
663
  >>> print(atom_array.chain_id)
667
664
  ['A' 'C' 'A']
668
665
  """
669
-
666
+
670
667
  def __init__(self, length):
671
668
  super().__init__(length)
672
669
  if length is None:
@@ -676,13 +673,13 @@ class AtomArray(_AtomArrayBase):
676
673
 
677
674
  def __repr__(self):
678
675
  """Represent AtomArray as a string for debugging."""
679
- atoms = ''
676
+ atoms = ""
680
677
  for i in range(0, self.array_length()):
681
678
  if len(atoms) == 0:
682
- atoms = '\n\t' + self.get_atom(i).__repr__()
679
+ atoms = "\n\t" + self.get_atom(i).__repr__()
683
680
  else:
684
- atoms = atoms + ',\n\t' + self.get_atom(i).__repr__()
685
- return f'array([{atoms}\n])'
681
+ atoms = atoms + ",\n\t" + self.get_atom(i).__repr__()
682
+ return f"array([{atoms}\n])"
686
683
 
687
684
  @property
688
685
  def shape(self):
@@ -703,33 +700,33 @@ class AtomArray(_AtomArrayBase):
703
700
  --------
704
701
  array_length
705
702
  """
706
- return self.array_length(),
703
+ return (self.array_length(),)
707
704
 
708
705
  def get_atom(self, index):
709
706
  """
710
707
  Obtain the atom instance of the array at the specified index.
711
-
708
+
712
709
  The same as ``array[index]``, if `index` is an integer.
713
-
710
+
714
711
  Parameters
715
712
  ----------
716
713
  index : int
717
714
  Index of the atom.
718
-
715
+
719
716
  Returns
720
717
  -------
721
718
  atom : Atom
722
- Atom at position `index`.
719
+ Atom at position `index`.
723
720
  """
724
721
  kwargs = {}
725
722
  for name, annotation in self._annot.items():
726
723
  kwargs[name] = annotation[index]
727
- return Atom(coord = self._coord[index], kwargs=kwargs)
728
-
724
+ return Atom(coord=self._coord[index], kwargs=kwargs)
725
+
729
726
  def __iter__(self):
730
727
  """
731
728
  Iterate through the array.
732
-
729
+
733
730
  Yields
734
731
  ------
735
732
  atom : Atom
@@ -738,16 +735,16 @@ class AtomArray(_AtomArrayBase):
738
735
  while i < len(self):
739
736
  yield self.get_atom(i)
740
737
  i += 1
741
-
738
+
742
739
  def __getitem__(self, index):
743
740
  """
744
741
  Obtain a subarray or the atom instance at the specified index.
745
-
742
+
746
743
  Parameters
747
744
  ----------
748
745
  index : object
749
746
  All index types *NumPy* accepts, are valid.
750
-
747
+
751
748
  Returns
752
749
  -------
753
750
  sub_array : Atom or AtomArray
@@ -763,16 +760,14 @@ class AtomArray(_AtomArrayBase):
763
760
  # If first index is "...", just ignore the first index
764
761
  return self.__getitem__(index[1])
765
762
  else:
766
- raise IndexError(
767
- "'AtomArray' does not accept multidimensional indices"
768
- )
763
+ raise IndexError("'AtomArray' does not accept multidimensional indices")
769
764
  else:
770
765
  return self._subarray(index)
771
-
766
+
772
767
  def __setitem__(self, index, atom):
773
768
  """
774
769
  Set the atom at the specified array position.
775
-
770
+
776
771
  Parameters
777
772
  ----------
778
773
  index : int
@@ -781,38 +776,38 @@ class AtomArray(_AtomArrayBase):
781
776
  The atom to be set.
782
777
  """
783
778
  self._set_element(index, atom)
784
-
779
+
785
780
  def __delitem__(self, index):
786
781
  """
787
782
  Deletes the atom at the specified array position.
788
-
783
+
789
784
  Parameters
790
785
  ----------
791
786
  index : int
792
787
  The position where the atom should be deleted.
793
788
  """
794
789
  self._del_element(index)
795
-
790
+
796
791
  def __len__(self):
797
792
  """
798
793
  The length of the array.
799
-
794
+
800
795
  Returns
801
796
  -------
802
797
  length : int
803
798
  Length of the array.
804
799
  """
805
800
  return self.array_length()
806
-
801
+
807
802
  def __eq__(self, item):
808
803
  """
809
804
  Check if the array equals another :class:`AtomArray`.
810
-
805
+
811
806
  Parameters
812
807
  ----------
813
808
  item : object
814
809
  Object to campare the array with.
815
-
810
+
816
811
  Returns
817
812
  -------
818
813
  equal : bool
@@ -824,15 +819,15 @@ class AtomArray(_AtomArrayBase):
824
819
  if not isinstance(item, AtomArray):
825
820
  return False
826
821
  return True
827
-
822
+
828
823
  def __str__(self):
829
824
  """
830
825
  Get a string representation of the array.
831
-
826
+
832
827
  Each line contains the attributes of one atom.
833
828
  """
834
829
  return "\n".join([str(atom) for atom in self])
835
-
830
+
836
831
  def __copy_create__(self):
837
832
  return AtomArray(self.array_length())
838
833
 
@@ -841,7 +836,7 @@ class AtomArrayStack(_AtomArrayBase):
841
836
  """
842
837
  A collection of multiple :class:`AtomArray` instances, where each
843
838
  atom array has equal annotation arrays.
844
-
839
+
845
840
  Effectively, this means that each atom is occuring in every array in
846
841
  the stack at differing coordinates. This situation arises e.g. in
847
842
  NMR-elucidated or simulated structures. Since the annotations are
@@ -849,7 +844,7 @@ class AtomArrayStack(_AtomArrayBase):
849
844
  coordinate array is 3-D (m x n x 3).
850
845
  A detailed description of each annotation category can be viewed
851
846
  :doc:`here </apidoc/biotite.structure>`.
852
-
847
+
853
848
  Indexing works similar to :class:`AtomArray`, with the difference,
854
849
  that two index dimensions are possible:
855
850
  The first index dimension specifies the array(s), the second index
@@ -857,24 +852,24 @@ class AtomArrayStack(_AtomArrayBase):
857
852
  in :class:`AtomArray`).
858
853
  Using a single integer as first dimension index returns a single
859
854
  :class:`AtomArray` instance.
860
-
855
+
861
856
  Concatenation of atoms for each array in the stack is done using the
862
857
  '+' operator. For addition of atom arrays onto the stack use the
863
858
  :func:`stack()` method.
864
859
 
865
860
  The :attr:`box` attribute has the shape *m x 3 x 3*, as the cell
866
861
  might be different for each frame in the atom array stack.
867
-
862
+
868
863
  Parameters
869
864
  ----------
870
865
  depth : int
871
866
  The fixed amount of arrays in the stack. When indexing, this is
872
867
  the length of the first dimension.
873
-
868
+
874
869
  length : int
875
870
  The fixed amount of atoms in each array in the stack. When
876
871
  indexing, this is the length of the second dimension.
877
-
872
+
878
873
  Attributes
879
874
  ----------
880
875
  {annot} : ndarray, shape=(n,)
@@ -892,15 +887,15 @@ class AtomArrayStack(_AtomArrayBase):
892
887
  Shape of the stack.
893
888
  The numbers correspond to the stack depth
894
889
  and array length, respectively.
895
-
890
+
896
891
  See also
897
892
  --------
898
893
  AtomArray
899
-
894
+
900
895
  Examples
901
896
  --------
902
897
  Creating an atom array stack from two arrays:
903
-
898
+
904
899
  >>> atom1 = Atom([1,2,3], chain_id="A")
905
900
  >>> atom2 = Atom([2,3,4], chain_id="A")
906
901
  >>> atom3 = Atom([3,4,5], chain_id="B")
@@ -925,40 +920,40 @@ class AtomArrayStack(_AtomArrayBase):
925
920
  [5. 6. 7.]
926
921
  [6. 7. 8.]]]
927
922
  """
928
-
923
+
929
924
  def __init__(self, depth, length):
930
925
  super().__init__(length)
931
- if depth == None or length == None:
926
+ if depth is None or length is None:
932
927
  self._coord = None
933
928
  else:
934
929
  self._coord = np.full((depth, length, 3), np.nan, dtype=np.float32)
935
930
 
936
931
  def __repr__(self):
937
932
  """Represent AtomArrayStack as a string for debugging."""
938
- arrays = ''
933
+ arrays = ""
939
934
  for i in range(0, self.stack_depth()):
940
935
  if len(arrays) == 0:
941
- arrays = '\n\t' + self.get_array(i).__repr__()
936
+ arrays = "\n\t" + self.get_array(i).__repr__()
942
937
  else:
943
- arrays = arrays + ',\n\t' + self.get_array(i).__repr__()
944
- return f'stack([{arrays}\n])'
938
+ arrays = arrays + ",\n\t" + self.get_array(i).__repr__()
939
+ return f"stack([{arrays}\n])"
945
940
 
946
941
  def get_array(self, index):
947
942
  """
948
943
  Obtain the atom array instance of the stack at the specified
949
944
  index.
950
-
945
+
951
946
  The same as ``stack[index]``, if `index` is an integer.
952
-
947
+
953
948
  Parameters
954
949
  ----------
955
950
  index : int
956
951
  Index of the atom array.
957
-
952
+
958
953
  Returns
959
954
  -------
960
955
  array : AtomArray
961
- AtomArray at position `index`.
956
+ AtomArray at position `index`.
962
957
  """
963
958
  array = AtomArray(self.array_length())
964
959
  for name in self._annot:
@@ -970,14 +965,14 @@ class AtomArrayStack(_AtomArrayBase):
970
965
  array._box = self._box[index]
971
966
 
972
967
  return array
973
-
968
+
974
969
  def stack_depth(self):
975
970
  """
976
971
  Get the depth of the stack.
977
-
972
+
978
973
  This value represents the amount of atom arrays in the stack.
979
974
  It is the same as ``len(array)``.
980
-
975
+
981
976
  Returns
982
977
  -------
983
978
  length : int
@@ -1005,7 +1000,7 @@ class AtomArrayStack(_AtomArrayBase):
1005
1000
  def __iter__(self):
1006
1001
  """
1007
1002
  Iterate through the array.
1008
-
1003
+
1009
1004
  Yields
1010
1005
  ------
1011
1006
  array : AtomArray
@@ -1014,17 +1009,17 @@ class AtomArrayStack(_AtomArrayBase):
1014
1009
  while i < len(self):
1015
1010
  yield self.get_array(i)
1016
1011
  i += 1
1017
-
1012
+
1018
1013
  def __getitem__(self, index):
1019
1014
  """
1020
1015
  Obtain the atom array instance or an substack at the specified
1021
1016
  index.
1022
-
1017
+
1023
1018
  Parameters
1024
1019
  ----------
1025
1020
  index : object
1026
1021
  All index types *NumPy* accepts are valid.
1027
-
1022
+
1028
1023
  Returns
1029
1024
  -------
1030
1025
  sub_array : AtomArray or AtomArrayStack
@@ -1033,7 +1028,7 @@ class AtomArrayStack(_AtomArrayBase):
1033
1028
  Otherwise an :class:`AtomArrayStack` with reduced depth and
1034
1029
  length is returned.
1035
1030
  In case the index is a tuple(int, int) an :class:`Atom`
1036
- instance is returned.
1031
+ instance is returned.
1037
1032
  """
1038
1033
  if isinstance(index, numbers.Integral):
1039
1034
  return self.get_array(index)
@@ -1050,7 +1045,7 @@ class AtomArrayStack(_AtomArrayBase):
1050
1045
  if isinstance(index[1], numbers.Integral):
1051
1046
  # Prevent reduction in dimensionality
1052
1047
  # in second dimension
1053
- new_stack = self._subarray(slice(index[1], index[1]+1))
1048
+ new_stack = self._subarray(slice(index[1], index[1] + 1))
1054
1049
  else:
1055
1050
  new_stack = self._subarray(index[1])
1056
1051
  if index[0] is not Ellipsis:
@@ -1065,14 +1060,13 @@ class AtomArrayStack(_AtomArrayBase):
1065
1060
  if self._box is not None:
1066
1061
  new_stack._box = self._box[index]
1067
1062
  return new_stack
1068
-
1069
-
1063
+
1070
1064
  def __setitem__(self, index, array):
1071
1065
  """
1072
1066
  Set the atom array at the specified stack position.
1073
-
1067
+
1074
1068
  The array and the stack must have equal annotation arrays.
1075
-
1069
+
1076
1070
  Parameters
1077
1071
  ----------
1078
1072
  index : int
@@ -1081,26 +1075,20 @@ class AtomArrayStack(_AtomArrayBase):
1081
1075
  The atom array to be set.
1082
1076
  """
1083
1077
  if not self.equal_annotations(array):
1084
- raise ValueError(
1085
- "The stack and the array have unequal annotations"
1086
- )
1078
+ raise ValueError("The stack and the array have unequal annotations")
1087
1079
  if self.bonds != array.bonds:
1088
- raise ValueError(
1089
- "The stack and the array have unequal bonds"
1090
- )
1080
+ raise ValueError("The stack and the array have unequal bonds")
1091
1081
  if isinstance(index, numbers.Integral):
1092
1082
  self.coord[index] = array.coord
1093
1083
  if self.box is not None:
1094
1084
  self.box[index] = array.box
1095
1085
  else:
1096
- raise TypeError(
1097
- f"Index must be integer, not '{type(index).__name__}'"
1098
- )
1099
-
1086
+ raise TypeError(f"Index must be integer, not '{type(index).__name__}'")
1087
+
1100
1088
  def __delitem__(self, index):
1101
1089
  """
1102
1090
  Deletes the atom array at the specified stack position.
1103
-
1091
+
1104
1092
  Parameters
1105
1093
  ----------
1106
1094
  index : int
@@ -1109,14 +1097,12 @@ class AtomArrayStack(_AtomArrayBase):
1109
1097
  if isinstance(index, numbers.Integral):
1110
1098
  self._coord = np.delete(self._coord, index, axis=0)
1111
1099
  else:
1112
- raise TypeError(
1113
- f"Index must be integer, not '{type(index).__name__}'"
1114
- )
1115
-
1100
+ raise TypeError(f"Index must be integer, not '{type(index).__name__}'")
1101
+
1116
1102
  def __len__(self):
1117
1103
  """
1118
1104
  The depth of the stack, i.e. the amount of models.
1119
-
1105
+
1120
1106
  Returns
1121
1107
  -------
1122
1108
  depth : int
@@ -1124,16 +1110,16 @@ class AtomArrayStack(_AtomArrayBase):
1124
1110
  """
1125
1111
  # length is determined by length of coord attribute
1126
1112
  return self._coord.shape[0]
1127
-
1113
+
1128
1114
  def __eq__(self, item):
1129
1115
  """
1130
1116
  Check if the array equals another :class:`AtomArray`
1131
-
1117
+
1132
1118
  Parameters
1133
1119
  ----------
1134
1120
  item : object
1135
1121
  Object to campare the array with.
1136
-
1122
+
1137
1123
  Returns
1138
1124
  -------
1139
1125
  equal : bool
@@ -1145,20 +1131,20 @@ class AtomArrayStack(_AtomArrayBase):
1145
1131
  if not isinstance(item, AtomArrayStack):
1146
1132
  return False
1147
1133
  return True
1148
-
1134
+
1149
1135
  def __str__(self):
1150
1136
  """
1151
1137
  Get a string representation of the stack.
1152
-
1138
+
1153
1139
  :class:`AtomArray` strings eparated by blank lines
1154
1140
  and a line indicating the index.
1155
1141
  """
1156
1142
  string = ""
1157
1143
  for i, array in enumerate(self):
1158
- string += "Model " + str(i+1) + "\n"
1144
+ string += "Model " + str(i + 1) + "\n"
1159
1145
  string += str(array) + "\n" + "\n"
1160
1146
  return string
1161
-
1147
+
1162
1148
  def __copy_create__(self):
1163
1149
  return AtomArrayStack(self.stack_depth(), self.array_length())
1164
1150
 
@@ -1166,23 +1152,23 @@ class AtomArrayStack(_AtomArrayBase):
1166
1152
  def array(atoms):
1167
1153
  """
1168
1154
  Create an :class:`AtomArray` from a list of :class:`Atom`.
1169
-
1155
+
1170
1156
  Parameters
1171
1157
  ----------
1172
1158
  atoms : iterable object of Atom
1173
1159
  The atoms to be combined in an array.
1174
1160
  All atoms must share the same annotation categories.
1175
-
1161
+
1176
1162
  Returns
1177
1163
  -------
1178
1164
  array : AtomArray
1179
1165
  The listed atoms as array.
1180
-
1166
+
1181
1167
  Examples
1182
1168
  --------
1183
-
1169
+
1184
1170
  Creating an atom array from atoms:
1185
-
1171
+
1186
1172
  >>> atom1 = Atom([1,2,3], chain_id="A")
1187
1173
  >>> atom2 = Atom([2,3,4], chain_id="A")
1188
1174
  >>> atom3 = Atom([3,4,5], chain_id="B")
@@ -1204,7 +1190,7 @@ def array(atoms):
1204
1190
  array = AtomArray(len(atoms))
1205
1191
  # Add all (also optional) annotation categories
1206
1192
  for name in names:
1207
- array.add_annotation(name, dtype=type(atoms[0]._annot[name]))
1193
+ array.add_annotation(name, dtype=type(atoms[0]._annot[name]))
1208
1194
  # Add all atoms to AtomArray
1209
1195
  for i in range(len(atoms)):
1210
1196
  for name in names:
@@ -1216,23 +1202,23 @@ def array(atoms):
1216
1202
  def stack(arrays):
1217
1203
  """
1218
1204
  Create an :class:`AtomArrayStack` from a list of :class:`AtomArray`.
1219
-
1205
+
1220
1206
  Parameters
1221
1207
  ----------
1222
1208
  arrays : iterable object of AtomArray
1223
1209
  The atom arrays to be combined in a stack.
1224
1210
  All atom arrays must have an equal number of atoms and equal
1225
1211
  annotation arrays.
1226
-
1212
+
1227
1213
  Returns
1228
1214
  -------
1229
1215
  stack : AtomArrayStack
1230
1216
  The stacked atom arrays.
1231
-
1217
+
1232
1218
  Examples
1233
1219
  --------
1234
1220
  Creating an atom array stack from two arrays:
1235
-
1221
+
1236
1222
  >>> atom1 = Atom([1,2,3], chain_id="A")
1237
1223
  >>> atom2 = Atom([2,3,4], chain_id="A")
1238
1224
  >>> atom3 = Atom([3,4,5], chain_id="B")
@@ -1272,7 +1258,7 @@ def stack(arrays):
1272
1258
  array_stack = AtomArrayStack(array_count, ref_array.array_length())
1273
1259
  for name, annotation in ref_array._annot.items():
1274
1260
  array_stack._annot[name] = annotation
1275
- coord_list = [array._coord for array in arrays]
1261
+ coord_list = [array._coord for array in arrays]
1276
1262
  array_stack._coord = np.stack(coord_list, axis=0)
1277
1263
  # Take bond list from first array
1278
1264
  array_stack._bonds = ref_array._bonds
@@ -1296,14 +1282,14 @@ def repeat(atoms, coord):
1296
1282
  The length of first dimension determines the number of repeats.
1297
1283
  If `atoms` is an :class:`AtomArray` 3 dimensions, otherwise
1298
1284
  4 dimensions are required.
1299
-
1285
+
1300
1286
  Returns
1301
1287
  -------
1302
1288
  repeated: AtomArray, shape=(n*k,) or AtomArrayStack, shape=(m,n*k)
1303
1289
  The repeated atoms.
1304
1290
  Whether an :class:`AtomArray` or an :class:`AtomArrayStack` is
1305
1291
  returned depends on the input `atoms`.
1306
-
1292
+
1307
1293
  Examples
1308
1294
  --------
1309
1295
 
@@ -1336,7 +1322,7 @@ def repeat(atoms, coord):
1336
1322
  raise ValueError(
1337
1323
  f"Expected 4 dimensions for the coordinate array, got {coord.ndim}"
1338
1324
  )
1339
-
1325
+
1340
1326
  repetitions = len(coord)
1341
1327
  orig_length = atoms.array_length()
1342
1328
  new_length = orig_length * repetitions
@@ -1358,24 +1344,24 @@ def repeat(atoms, coord):
1358
1344
  )
1359
1345
  repeated = AtomArrayStack(atoms.stack_depth(), new_length)
1360
1346
  repeated.coord = coord.reshape((atoms.stack_depth(), new_length, 3))
1361
-
1347
+
1362
1348
  else:
1363
1349
  raise TypeError(
1364
1350
  f"Expected 'AtomArray' or 'AtomArrayStack', "
1365
1351
  f"but got {type(atoms).__name__}"
1366
1352
  )
1367
-
1353
+
1368
1354
  for category in atoms.get_annotation_categories():
1369
1355
  annot = np.tile(atoms.get_annotation(category), repetitions)
1370
1356
  repeated.set_annotation(category, annot)
1371
1357
  if atoms.bonds is not None:
1372
1358
  repeated_bonds = atoms.bonds.copy()
1373
- for _ in range(repetitions-1):
1359
+ for _ in range(repetitions - 1):
1374
1360
  repeated_bonds += atoms.bonds
1375
1361
  repeated.bonds = repeated_bonds
1376
1362
  if atoms.box is not None:
1377
1363
  repeated.box = atoms.box.copy()
1378
-
1364
+
1379
1365
  return repeated
1380
1366
 
1381
1367
 
@@ -1383,7 +1369,7 @@ def from_template(template, coord, box=None):
1383
1369
  """
1384
1370
  Create an :class:`AtomArrayStack` using template atoms and given
1385
1371
  coordinates.
1386
-
1372
+
1387
1373
  Parameters
1388
1374
  ----------
1389
1375
  template : AtomArray, shape=(n,) or AtomArrayStack, shape=(m,n)
@@ -1393,7 +1379,7 @@ def from_template(template, coord, box=None):
1393
1379
  The coordinates for each model of the returned stack.
1394
1380
  box : ndarray, optional, dtype=float, shape=(l,3,3)
1395
1381
  The box for each model of the returned stack.
1396
-
1382
+
1397
1383
  Returns
1398
1384
  -------
1399
1385
  array_stack : AtomArrayStack
@@ -1409,7 +1395,7 @@ def from_template(template, coord, box=None):
1409
1395
 
1410
1396
  # Create empty stack with no models
1411
1397
  new_stack = AtomArrayStack(0, template.array_length())
1412
-
1398
+
1413
1399
  for category in template.get_annotation_categories():
1414
1400
  annot = template.get_annotation(category)
1415
1401
  new_stack.set_annotation(category, annot)
@@ -1417,30 +1403,30 @@ def from_template(template, coord, box=None):
1417
1403
  new_stack.bonds = template.bonds.copy()
1418
1404
  if box is not None:
1419
1405
  new_stack.box = box.copy()
1420
-
1406
+
1421
1407
  # After setting the coordinates the number of models is the number
1422
1408
  # of models in the new coordinates
1423
1409
  new_stack.coord = coord
1424
-
1410
+
1425
1411
  return new_stack
1426
1412
 
1427
1413
 
1428
1414
  def coord(item):
1429
1415
  """
1430
1416
  Get the atom coordinates of the given array.
1431
-
1417
+
1432
1418
  This may be directly and :class:`Atom`, :class:`AtomArray` or
1433
1419
  :class:`AtomArrayStack` or
1434
1420
  alternatively an (n x 3) or (m x n x 3) :class:`ndarray`
1435
1421
  containing the coordinates.
1436
-
1422
+
1437
1423
  Parameters
1438
1424
  ----------
1439
1425
  item : Atom or AtomArray or AtomArrayStack or ndarray
1440
1426
  Returns the :attr:`coord` attribute, if `item` is an
1441
1427
  :class:`Atom`, :class:`AtomArray` or :class:`AtomArrayStack`.
1442
1428
  Directly returns the input, if `item` is a :class:`ndarray`.
1443
-
1429
+
1444
1430
  Returns
1445
1431
  -------
1446
1432
  coord : ndarray