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