biotite 1.0.1__cp312-cp312-win_amd64.whl → 1.2.0__cp312-cp312-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of biotite might be problematic. Click here for more details.

Files changed (177) hide show
  1. biotite/application/application.py +3 -3
  2. biotite/application/autodock/app.py +1 -1
  3. biotite/application/blast/webapp.py +1 -1
  4. biotite/application/clustalo/app.py +1 -1
  5. biotite/application/dssp/app.py +13 -3
  6. biotite/application/localapp.py +36 -2
  7. biotite/application/msaapp.py +10 -10
  8. biotite/application/muscle/app3.py +5 -18
  9. biotite/application/muscle/app5.py +5 -5
  10. biotite/application/sra/app.py +0 -5
  11. biotite/application/util.py +22 -2
  12. biotite/application/viennarna/rnaalifold.py +8 -8
  13. biotite/application/viennarna/rnaplot.py +9 -3
  14. biotite/application/viennarna/util.py +1 -1
  15. biotite/application/webapp.py +1 -1
  16. biotite/database/afdb/__init__.py +12 -0
  17. biotite/database/afdb/download.py +191 -0
  18. biotite/database/entrez/dbnames.py +10 -0
  19. biotite/database/entrez/download.py +9 -10
  20. biotite/database/entrez/key.py +1 -1
  21. biotite/database/entrez/query.py +5 -4
  22. biotite/database/pubchem/download.py +6 -6
  23. biotite/database/pubchem/error.py +10 -0
  24. biotite/database/pubchem/query.py +12 -23
  25. biotite/database/rcsb/download.py +3 -2
  26. biotite/database/rcsb/query.py +8 -9
  27. biotite/database/uniprot/check.py +22 -17
  28. biotite/database/uniprot/download.py +3 -6
  29. biotite/database/uniprot/query.py +4 -5
  30. biotite/file.py +14 -2
  31. biotite/interface/__init__.py +19 -0
  32. biotite/interface/openmm/__init__.py +16 -0
  33. biotite/interface/openmm/state.py +93 -0
  34. biotite/interface/openmm/system.py +227 -0
  35. biotite/interface/pymol/__init__.py +198 -0
  36. biotite/interface/pymol/cgo.py +346 -0
  37. biotite/interface/pymol/convert.py +185 -0
  38. biotite/interface/pymol/display.py +267 -0
  39. biotite/interface/pymol/object.py +1226 -0
  40. biotite/interface/pymol/shapes.py +178 -0
  41. biotite/interface/pymol/startup.py +169 -0
  42. biotite/interface/rdkit/__init__.py +15 -0
  43. biotite/interface/rdkit/mol.py +490 -0
  44. biotite/interface/version.py +71 -0
  45. biotite/interface/warning.py +19 -0
  46. biotite/sequence/align/__init__.py +0 -4
  47. biotite/sequence/align/alignment.py +49 -14
  48. biotite/sequence/align/banded.cp312-win_amd64.pyd +0 -0
  49. biotite/sequence/align/banded.pyx +26 -26
  50. biotite/sequence/align/cigar.py +2 -2
  51. biotite/sequence/align/kmeralphabet.cp312-win_amd64.pyd +0 -0
  52. biotite/sequence/align/kmeralphabet.pyx +19 -2
  53. biotite/sequence/align/kmersimilarity.cp312-win_amd64.pyd +0 -0
  54. biotite/sequence/align/kmertable.cp312-win_amd64.pyd +0 -0
  55. biotite/sequence/align/kmertable.pyx +58 -48
  56. biotite/sequence/align/localgapped.cp312-win_amd64.pyd +0 -0
  57. biotite/sequence/align/localgapped.pyx +47 -47
  58. biotite/sequence/align/localungapped.cp312-win_amd64.pyd +0 -0
  59. biotite/sequence/align/localungapped.pyx +10 -10
  60. biotite/sequence/align/matrix.py +284 -57
  61. biotite/sequence/align/matrix_data/3Di.mat +24 -0
  62. biotite/sequence/align/matrix_data/PB.license +21 -0
  63. biotite/sequence/align/matrix_data/PB.mat +18 -0
  64. biotite/sequence/align/multiple.cp312-win_amd64.pyd +0 -0
  65. biotite/sequence/align/pairwise.cp312-win_amd64.pyd +0 -0
  66. biotite/sequence/align/pairwise.pyx +35 -35
  67. biotite/sequence/align/permutation.cp312-win_amd64.pyd +0 -0
  68. biotite/sequence/align/selector.cp312-win_amd64.pyd +0 -0
  69. biotite/sequence/align/selector.pyx +2 -2
  70. biotite/sequence/align/statistics.py +1 -1
  71. biotite/sequence/align/tracetable.cp312-win_amd64.pyd +0 -0
  72. biotite/sequence/alphabet.py +5 -2
  73. biotite/sequence/annotation.py +19 -13
  74. biotite/sequence/codec.cp312-win_amd64.pyd +0 -0
  75. biotite/sequence/codon.py +1 -2
  76. biotite/sequence/graphics/alignment.py +25 -39
  77. biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
  78. biotite/sequence/graphics/color_schemes/pb_flower.json +2 -1
  79. biotite/sequence/graphics/colorschemes.py +44 -11
  80. biotite/sequence/graphics/dendrogram.py +4 -2
  81. biotite/sequence/graphics/features.py +2 -2
  82. biotite/sequence/graphics/logo.py +10 -12
  83. biotite/sequence/io/fasta/convert.py +1 -2
  84. biotite/sequence/io/fasta/file.py +1 -1
  85. biotite/sequence/io/fastq/file.py +3 -3
  86. biotite/sequence/io/genbank/file.py +3 -3
  87. biotite/sequence/io/genbank/sequence.py +2 -0
  88. biotite/sequence/io/gff/convert.py +1 -1
  89. biotite/sequence/io/gff/file.py +1 -2
  90. biotite/sequence/phylo/nj.cp312-win_amd64.pyd +0 -0
  91. biotite/sequence/phylo/tree.cp312-win_amd64.pyd +0 -0
  92. biotite/sequence/phylo/upgma.cp312-win_amd64.pyd +0 -0
  93. biotite/sequence/profile.py +105 -29
  94. biotite/sequence/search.py +0 -1
  95. biotite/sequence/seqtypes.py +136 -8
  96. biotite/sequence/sequence.py +1 -2
  97. biotite/setup_ccd.py +197 -0
  98. biotite/structure/__init__.py +6 -3
  99. biotite/structure/alphabet/__init__.py +25 -0
  100. biotite/structure/alphabet/encoder.py +332 -0
  101. biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
  102. biotite/structure/alphabet/i3d.py +109 -0
  103. biotite/structure/alphabet/layers.py +86 -0
  104. biotite/structure/alphabet/pb.license +21 -0
  105. biotite/structure/alphabet/pb.py +170 -0
  106. biotite/structure/alphabet/unkerasify.py +128 -0
  107. biotite/structure/atoms.py +163 -66
  108. biotite/structure/basepairs.py +26 -26
  109. biotite/structure/bonds.cp312-win_amd64.pyd +0 -0
  110. biotite/structure/bonds.pyx +79 -25
  111. biotite/structure/box.py +19 -21
  112. biotite/structure/celllist.cp312-win_amd64.pyd +0 -0
  113. biotite/structure/celllist.pyx +83 -67
  114. biotite/structure/chains.py +5 -37
  115. biotite/structure/charges.cp312-win_amd64.pyd +0 -0
  116. biotite/structure/compare.py +420 -13
  117. biotite/structure/density.py +1 -1
  118. biotite/structure/dotbracket.py +27 -28
  119. biotite/structure/filter.py +8 -8
  120. biotite/structure/geometry.py +74 -127
  121. biotite/structure/hbond.py +17 -19
  122. biotite/structure/info/__init__.py +1 -0
  123. biotite/structure/info/atoms.py +24 -15
  124. biotite/structure/info/bonds.py +12 -6
  125. biotite/structure/info/ccd.py +125 -34
  126. biotite/structure/info/{ccd/components.bcif → components.bcif} +0 -0
  127. biotite/structure/info/groups.py +62 -19
  128. biotite/structure/info/masses.py +9 -6
  129. biotite/structure/info/misc.py +15 -22
  130. biotite/structure/info/radii.py +92 -22
  131. biotite/structure/info/standardize.py +4 -4
  132. biotite/structure/integrity.py +4 -6
  133. biotite/structure/io/general.py +2 -2
  134. biotite/structure/io/gro/file.py +8 -9
  135. biotite/structure/io/mol/convert.py +1 -1
  136. biotite/structure/io/mol/ctab.py +33 -28
  137. biotite/structure/io/mol/mol.py +1 -1
  138. biotite/structure/io/mol/sdf.py +80 -53
  139. biotite/structure/io/pdb/convert.py +4 -3
  140. biotite/structure/io/pdb/file.py +85 -25
  141. biotite/structure/io/pdb/hybrid36.cp312-win_amd64.pyd +0 -0
  142. biotite/structure/io/pdbqt/file.py +36 -36
  143. biotite/structure/io/pdbx/__init__.py +1 -0
  144. biotite/structure/io/pdbx/bcif.py +54 -15
  145. biotite/structure/io/pdbx/cif.py +92 -66
  146. biotite/structure/io/pdbx/component.py +15 -4
  147. biotite/structure/io/pdbx/compress.py +321 -0
  148. biotite/structure/io/pdbx/convert.py +410 -75
  149. biotite/structure/io/pdbx/encoding.cp312-win_amd64.pyd +0 -0
  150. biotite/structure/io/pdbx/encoding.pyx +98 -17
  151. biotite/structure/io/trajfile.py +9 -6
  152. biotite/structure/io/util.py +38 -0
  153. biotite/structure/mechanics.py +0 -1
  154. biotite/structure/molecules.py +141 -156
  155. biotite/structure/pseudoknots.py +7 -13
  156. biotite/structure/repair.py +2 -4
  157. biotite/structure/residues.py +13 -24
  158. biotite/structure/rings.py +335 -0
  159. biotite/structure/sasa.cp312-win_amd64.pyd +0 -0
  160. biotite/structure/sasa.pyx +2 -1
  161. biotite/structure/segments.py +69 -11
  162. biotite/structure/sequence.py +0 -1
  163. biotite/structure/sse.py +0 -2
  164. biotite/structure/superimpose.py +74 -62
  165. biotite/structure/tm.py +581 -0
  166. biotite/structure/transform.py +12 -25
  167. biotite/structure/util.py +76 -4
  168. biotite/version.py +9 -4
  169. biotite/visualize.py +111 -1
  170. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/METADATA +6 -2
  171. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/RECORD +173 -143
  172. biotite/structure/info/ccd/README.rst +0 -8
  173. biotite/structure/info/ccd/amino_acids.txt +0 -1663
  174. biotite/structure/info/ccd/carbohydrates.txt +0 -1135
  175. biotite/structure/info/ccd/nucleotides.txt +0 -798
  176. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/WHEEL +0 -0
  177. {biotite-1.0.1.dist-info → biotite-1.2.0.dist-info}/licenses/LICENSE.rst +0 -0
@@ -0,0 +1,346 @@
1
+ __name__ = "biotite.interface.pymol"
2
+ __author__ = "Patrick Kunzmann"
3
+ __all__ = [
4
+ "draw_cgo",
5
+ "get_cylinder_cgo",
6
+ "get_cone_cgo",
7
+ "get_sphere_cgo",
8
+ "get_point_cgo",
9
+ "get_line_cgo",
10
+ "get_multiline_cgo",
11
+ ]
12
+
13
+ import itertools
14
+ from enum import IntEnum
15
+ import numpy as np
16
+ from biotite.interface.pymol.object import PyMOLObject
17
+ from biotite.interface.pymol.startup import get_and_set_pymol_instance
18
+
19
+ _object_counter = 0
20
+
21
+
22
+ class CGO(IntEnum):
23
+ # List compiled from uppercase attributes in 'pymol.cgo'
24
+ ALPHA = 25
25
+ ALPHA_TRIANGLE = 17
26
+ BEGIN = 2
27
+ CHAR = 23
28
+ COLOR = 6
29
+ CONE = 27
30
+ CUSTOM_CYLINDER = 15
31
+ CYLINDER = 9
32
+ DISABLE = 13
33
+ DOTWIDTH = 16
34
+ ELLIPSOID = 18
35
+ ENABLE = 12
36
+ END = 3
37
+ FONT = 19
38
+ FONT_AXES = 22
39
+ FONT_SCALE = 20
40
+ FONT_VERTEX = 21
41
+ LINES = 1
42
+ LINEWIDTH = 10
43
+ LINE_LOOP = 2
44
+ LINE_STRIP = 3
45
+ NORMAL = 5
46
+ NULL = 1
47
+ PICK_COLOR = 31
48
+ POINTS = 0
49
+ QUADRIC = 26
50
+ SAUSAGE = 14
51
+ SPHERE = 7
52
+ STOP = 0
53
+ TRIANGLE = 8
54
+ TRIANGLES = 4
55
+ TRIANGLE_FAN = 6
56
+ TRIANGLE_STRIP = 5
57
+ VERTEX = 4
58
+ WIDTHSCALE = 11
59
+
60
+
61
+ def draw_cgo(cgo_list, name=None, pymol_instance=None, delete=True):
62
+ """
63
+ Draw geometric shapes using *Compiled Graphics Objects* (CGOs).
64
+
65
+ Each CGO is represented by a list of floats, which can be obtained
66
+ via the ``get_xxx_cgo()`` functions.
67
+
68
+ Parameters
69
+ ----------
70
+ cgo_list : list of list of float
71
+ The CGOs to draw.
72
+ It is recommended to use a ``get_xxx_cgo()`` function to obtain
73
+ the elements for this list, if possible.
74
+ Otherwise, shapes may be drawn incorrectly or omitted entirely,
75
+ if a CGO is incorrectly formatted.
76
+ name : str, optional
77
+ The name of the newly created CGO object.
78
+ If omitted, a unique name is generated.
79
+ pymol_instance : module or SingletonPyMOL or PyMOL, optional
80
+ If *PyMOL* is used in library mode, the :class:`PyMOL`
81
+ or :class:`SingletonPyMOL` object is given here.
82
+ If otherwise *PyMOL* is used in GUI mode, the :mod:`pymol`
83
+ module is given.
84
+ By default the currently active *PyMOL* instance is used.
85
+ If no *PyMOL* instance is currently running,
86
+ *PyMOL* is started in library mode.
87
+ delete : bool, optional
88
+ If set to true, the underlying *PyMOL* object will be removed from the *PyMOL*
89
+ session, when the returned :class:`PyMOLObject` is garbage collected.
90
+
91
+ Returns
92
+ -------
93
+ pymol_object : PyMOLObject
94
+ The created :class:`PyMOLObject` representing the drawn CGOs.
95
+ """
96
+ global _object_counter
97
+ if name is None:
98
+ name = f"biotite_cgo_{_object_counter}"
99
+ _object_counter += 1
100
+ pymol_instance = get_and_set_pymol_instance(pymol_instance)
101
+ pymol_instance.cmd.load_cgo(
102
+ # If CGO values are integers instead of floats
103
+ # the rendering may fail
104
+ [float(value) for value in list(itertools.chain(*cgo_list))],
105
+ name,
106
+ )
107
+ return PyMOLObject(name, pymol_instance, delete)
108
+
109
+
110
+ def get_cylinder_cgo(start, end, radius, start_color, end_color):
111
+ """
112
+ Get the CGO for a cylinder.
113
+
114
+ Parameters
115
+ ----------
116
+ start, end : array-like, shape=(3,)
117
+ The start and end position of the cylinder.
118
+ radius : float
119
+ The radius of the cylinder.
120
+ start_color, end_color : array-like, shape=(3,)
121
+ The color at the start and end of the cylinder given as RGB
122
+ values in the range *(0, 1)*.
123
+
124
+ Returns
125
+ -------
126
+ cgo : list of float
127
+ The CGO representation.
128
+ """
129
+ _expect_length(start, "start", 3)
130
+ _expect_length(end, "end", 3)
131
+ _expect_length(start_color, "start_color", 3)
132
+ _expect_length(end_color, "end_color", 3)
133
+ _check_color(start_color)
134
+ _check_color(end_color)
135
+ return [CGO.CYLINDER, *start, *end, radius, *start_color, *end_color]
136
+
137
+
138
+ def get_cone_cgo(
139
+ start, end, start_radius, end_radius, start_color, end_color, start_cap, end_cap
140
+ ):
141
+ """
142
+ Get the CGO for a cone.
143
+
144
+ Parameters
145
+ ----------
146
+ start, end : array-like, shape=(3,)
147
+ The start and end position of the cone.
148
+ start_radius, end_radius : float
149
+ The radius of the cone at the start and end.
150
+ start_color, end_color : array-like, shape=(3,)
151
+ The color at the start and end of the cone given as RGB
152
+ values in the range *(0, 1)*.
153
+ start_cap, end_cap : bool
154
+ If true, a cap is drawn at the start or end of the cone.
155
+ Otherwise the cone is displayed as *open*.
156
+
157
+ Returns
158
+ -------
159
+ cgo : list of float
160
+ The CGO representation.
161
+ """
162
+ _expect_length(start, "start", 3)
163
+ _expect_length(end, "end", 3)
164
+ _expect_length(start_color, "start_color", 3)
165
+ _expect_length(end_color, "end_color", 3)
166
+ _check_color(start_color)
167
+ _check_color(end_color)
168
+ return [
169
+ CGO.CONE,
170
+ *start,
171
+ *end,
172
+ start_radius,
173
+ end_radius,
174
+ *start_color,
175
+ *end_color,
176
+ start_cap,
177
+ end_cap,
178
+ ]
179
+
180
+
181
+ def get_sphere_cgo(pos, radius, color):
182
+ """
183
+ Get the CGO for a sphere.
184
+
185
+ Parameters
186
+ ----------
187
+ pos : array-like, shape=(3,)
188
+ The position of the sphere.
189
+ radius : float
190
+ The radius of the sphere.
191
+ color : array-like, shape=(3,)
192
+ The color of the sphere given as RGB values in the range
193
+ *(0, 1)*.
194
+
195
+ Returns
196
+ -------
197
+ cgo : list of float
198
+ The CGO representation.
199
+ """
200
+ _expect_length(pos, "pos", 3)
201
+ _expect_length(color, "color", 3)
202
+ _check_color(color)
203
+ return [CGO.COLOR, *color, CGO.SPHERE, *pos, radius]
204
+
205
+
206
+ def get_point_cgo(pos, color):
207
+ """
208
+ Get the CGO for one or multiple points.
209
+
210
+ Parameters
211
+ ----------
212
+ pos : array-like, shape=(3,), shape=(n,3)
213
+ The position(s) of the points.
214
+ color : array-like, shape=(3,) or shape=(n,3)
215
+ The color of the point(s) given as RGB values in the range
216
+ *(0, 1)*.
217
+ Either one color can be given that is used for all points or
218
+ an individual color for each point can be supplied.
219
+
220
+ Returns
221
+ -------
222
+ cgo : list of float
223
+ The CGO representation.
224
+ """
225
+ pos = np.atleast_2d(pos)
226
+ color = _arrayfy(color, len(pos), 2)
227
+
228
+ for p in pos:
229
+ _expect_length(p, "pos", 3)
230
+ for c in color:
231
+ _expect_length(c, "color", 3)
232
+ _check_color(c)
233
+
234
+ vertices = []
235
+ for p, c in zip(pos, color):
236
+ vertices += [CGO.COLOR, *c, CGO.VERTEX, *p]
237
+
238
+ return [CGO.BEGIN, CGO.POINTS] + vertices + [CGO.END]
239
+
240
+
241
+ def get_line_cgo(pos, color, width=1.0):
242
+ """
243
+ Get the CGO for a line following the given positions.
244
+
245
+ Parameters
246
+ ----------
247
+ pos : array-like, shape=(n,3)
248
+ The line follows these positions.
249
+ color : array-like, shape=(3,) or shape=(n,3)
250
+ The color of the line given as RGB values in the range
251
+ *(0, 1)*.
252
+ Either one color can be given that is used for all positions or
253
+ an individual color for each position can be supplied.
254
+ width : float, optional
255
+ The rendered width of the line.
256
+ The width is only visible after calling :func:`ray()`.
257
+
258
+ Returns
259
+ -------
260
+ cgo : list of float
261
+ The CGO representation.
262
+ """
263
+ color = _arrayfy(color, len(pos), 2)
264
+
265
+ for p in pos:
266
+ _expect_length(p, "pos", 3)
267
+ for c in color:
268
+ _expect_length(c, "color", 3)
269
+ _check_color(c)
270
+
271
+ vertices = []
272
+ for p, c in zip(pos, color):
273
+ vertices += [CGO.COLOR, *c, CGO.VERTEX, *p]
274
+
275
+ return [CGO.LINEWIDTH, width, CGO.BEGIN, CGO.LINE_STRIP] + vertices + [CGO.END]
276
+
277
+
278
+ def get_multiline_cgo(start, end, color, width=1.0):
279
+ """
280
+ Get the CGO for one or multiple straight lines drawn from given
281
+ start to end positions.
282
+
283
+ Parameters
284
+ ----------
285
+ start, end : array-like, shape=(3,) or shape=(n,3)
286
+ The *n* lines are drawn from the `start` to the `end` positions.
287
+ color : array-like, shape=(3,) or shape=(n,3)
288
+ The color of the lines given as RGB values in the range
289
+ *(0, 1)*.
290
+ Either one color can be given that is used for all lines or
291
+ an individual color for each line can be supplied.
292
+ width : float, optional
293
+ The rendered width of the lines.
294
+ The width is only visible after calling :func:`ray()`.
295
+
296
+ Returns
297
+ -------
298
+ cgo : list of float
299
+ The CGO representation.
300
+ """
301
+ start = np.atleast_2d(start)
302
+ end = np.atleast_2d(end)
303
+ color = _arrayfy(color, len(start), 2)
304
+
305
+ if len(start) != len(end):
306
+ raise IndexError(
307
+ f"{len(start)} start positions are given, but {len(end)} end positions"
308
+ )
309
+ for p in start:
310
+ _expect_length(p, "start", 3)
311
+ for p in end:
312
+ _expect_length(p, "end", 3)
313
+ for c in color:
314
+ _expect_length(c, "color", 3)
315
+ _check_color(c)
316
+
317
+ vertices = []
318
+ for p1, p2, c in zip(start, end, color):
319
+ vertices += [CGO.COLOR, *c, CGO.VERTEX, *p1, CGO.VERTEX, *p2]
320
+
321
+ return [CGO.LINEWIDTH, width, CGO.BEGIN, CGO.LINES] + vertices + [CGO.END]
322
+
323
+
324
+ def _expect_length(values, name, length):
325
+ if len(values) != length:
326
+ raise IndexError(
327
+ f"'{name}' has {len(values)} values, but {length} were expected"
328
+ )
329
+
330
+
331
+ def _check_color(color):
332
+ if np.any(color) < 0 or np.any(color) > 1:
333
+ raise ValueError("Colors must be in range (0, 1)")
334
+
335
+
336
+ def _arrayfy(value, length, min_dim):
337
+ """
338
+ Expand value(s) to the given number of dimensions and repeat value
339
+ `length` number of times if only a single value is given.
340
+ """
341
+ value = np.array(value, ndmin=min_dim)
342
+ if len(value) == 1 and length > 1:
343
+ value = np.repeat(value, length, axis=0)
344
+ elif len(value) != length:
345
+ raise IndexError(f"Expected {length} values, but got {len(value)}")
346
+ return value
@@ -0,0 +1,185 @@
1
+ __name__ = "biotite.interface.pymol"
2
+ __author__ = "Patrick Kunzmann"
3
+ __all__ = ["to_model", "from_model"]
4
+
5
+ import warnings
6
+ import numpy as np
7
+ from chempy import Atom, Bond
8
+ from chempy.models import Indexed as IndexedModel
9
+ import biotite.structure as struc
10
+ from biotite.interface import LossyConversionWarning
11
+ from biotite.sequence import ProteinSequence
12
+
13
+ # Bond orders in PyMOL (https://pymolwiki.org/index.php/Valence):
14
+ # 1: single bond, 2: double bond, 3:triple bond, 4:delocalized
15
+ _FORMAL_BOND_ORDER = {
16
+ struc.BondType.SINGLE: 1,
17
+ struc.BondType.DOUBLE: 2,
18
+ struc.BondType.TRIPLE: 3,
19
+ struc.BondType.AROMATIC_SINGLE: 1,
20
+ struc.BondType.AROMATIC_DOUBLE: 2,
21
+ }
22
+ _DELOKALIZED_BOND_ORDER = {
23
+ struc.BondType.SINGLE: 1,
24
+ struc.BondType.DOUBLE: 2,
25
+ struc.BondType.TRIPLE: 3,
26
+ struc.BondType.AROMATIC_SINGLE: 4,
27
+ struc.BondType.AROMATIC_DOUBLE: 4,
28
+ struc.BondType.AROMATIC: 4,
29
+ }
30
+ _BIOTITE_BOND_TYPES = {
31
+ 1: struc.BondType.SINGLE,
32
+ 2: struc.BondType.DOUBLE,
33
+ 3: struc.BondType.TRIPLE,
34
+ 4: struc.BondType.AROMATIC,
35
+ }
36
+
37
+
38
+ def to_model(atom_array, delocalize_bonds=False):
39
+ """
40
+ Convert an :class:`AtomArray` into a :class:`chempy.models.Indexed`
41
+ object.
42
+
43
+ Parameters
44
+ ----------
45
+ atom_array : AtomArray
46
+ The structure to be converted.
47
+ delocalize_bonds : bool, optional
48
+ If set to true, use *PyMOL*'s delocalized bond order for aromatic bonds.
49
+ Otherwise, always use formal bond orders.
50
+
51
+ Returns
52
+ -------
53
+ chempy_model : Indexed
54
+ The converted structure.
55
+ """
56
+ if not np.isfinite(atom_array.coord).all():
57
+ raise ValueError("PyMOL does not support infinite or NaN coordinates")
58
+
59
+ model = IndexedModel()
60
+
61
+ annot_cat = atom_array.get_annotation_categories()
62
+ for i in range(atom_array.array_length()):
63
+ atom = Atom()
64
+ atom.segi = atom_array.chain_id[i]
65
+ atom.chain = atom_array.chain_id[i]
66
+ atom.resi_number = atom_array.res_id[i]
67
+ atom.ins_code = atom_array.ins_code[i]
68
+ res_name = atom_array.res_name[i]
69
+ atom.resn = res_name
70
+ if len(res_name) == 1:
71
+ atom.resn_code = res_name
72
+ else:
73
+ try:
74
+ atom.resn_code = ProteinSequence.convert_letter_3to1(res_name)
75
+ except KeyError:
76
+ atom.resn_code = "X"
77
+ atom.hetatm = 1 if atom_array.hetero[i] else 0
78
+ atom.name = atom_array.atom_name[i]
79
+ atom.symbol = atom_array.element[i]
80
+ if "b_factor" in annot_cat:
81
+ atom.b = atom_array.b_factor[i]
82
+ if "occupancy" in annot_cat:
83
+ atom.q = atom_array.occupancy[i]
84
+ if "charge" in annot_cat:
85
+ atom.formal_charge = atom_array.charge[i]
86
+ atom.coord = tuple(atom_array.coord[..., i, :])
87
+ atom.index = i + 1
88
+ model.add_atom(atom)
89
+
90
+ bond_order_mapping = (
91
+ _DELOKALIZED_BOND_ORDER if delocalize_bonds else _FORMAL_BOND_ORDER
92
+ )
93
+ unmappable_bond_types = []
94
+ if atom_array.bonds is not None:
95
+ for i, j, bond_type in atom_array.bonds.as_array():
96
+ bond = Bond()
97
+ order = bond_order_mapping.get(bond_type)
98
+ if order is None:
99
+ unmappable_bond_types.append(bond_type)
100
+ order = 1
101
+ bond.order = order
102
+ bond.index = [i, j]
103
+ model.add_bond(bond)
104
+ else:
105
+ warnings.warn("The given atom array (stack) has no associated bond information")
106
+ if unmappable_bond_types:
107
+ warnings.warn(
108
+ "The following bond types could not be mapped to PyMOL: "
109
+ + ", ".join([struc.BondType(bt).name for bt in set(unmappable_bond_types)]),
110
+ LossyConversionWarning,
111
+ )
112
+
113
+ return model
114
+
115
+
116
+ def from_model(chempy_model, include_bonds=False):
117
+ """
118
+ Convert a :class:`chempy.models.Indexed`
119
+ object into an :class:`AtomArray`.
120
+
121
+ The returned :class:`AtomArray` contains the optional annotation
122
+ categories ``b_factor``, ``occupancy``, ``charge`` and
123
+ ``altloc_id``.
124
+ No *altloc* ID filtering is performed.
125
+
126
+ Parameters
127
+ ----------
128
+ chempy_model : Indexed
129
+ The ``chempy`` model.
130
+ include_bonds : bool, optional
131
+ If set to true, an associated :class:`BondList` will be created
132
+ for the returned atom array.
133
+
134
+ Returns
135
+ -------
136
+ atom_array : AtomArray
137
+ The converted structure.
138
+ """
139
+ atoms = chempy_model.atom
140
+
141
+ bonds = chempy_model.bond
142
+
143
+ atom_array = struc.AtomArray(len(atoms))
144
+
145
+ # Add annotation arrays
146
+ atom_array.chain_id = np.array([a.chain for a in atoms], dtype="U3")
147
+ atom_array.res_id = np.array([a.resi_number for a in atoms], dtype=int)
148
+ atom_array.ins_code = np.array([a.ins_code for a in atoms], dtype="U1")
149
+ atom_array.res_name = np.array([a.resn for a in atoms], dtype="U3")
150
+ atom_array.hetero = np.array([a.hetatm for a in atoms], dtype=bool)
151
+ atom_array.atom_name = np.array([a.name for a in atoms], dtype="U6")
152
+ atom_array.element = np.array([a.symbol for a in atoms], dtype="U2")
153
+
154
+ atom_array.set_annotation(
155
+ "b_factor",
156
+ np.array([a.b if hasattr(a, "b") else 0 for a in atoms], dtype=float),
157
+ )
158
+ atom_array.set_annotation(
159
+ "occupancy",
160
+ np.array([a.q if hasattr(a, "q") else 1.0 for a in atoms], dtype=float),
161
+ )
162
+ atom_array.set_annotation(
163
+ "charge",
164
+ np.array(
165
+ [a.formal_charge if hasattr(a, "formal_charge") else 0 for a in atoms],
166
+ dtype=int,
167
+ ),
168
+ )
169
+ atom_array.set_annotation(
170
+ "altloc_id",
171
+ np.array([a.alt if hasattr(a, "alt") else "" for a in atoms], dtype="U1"),
172
+ )
173
+
174
+ # Set coordinates
175
+ atom_array.coord = np.array([a.coord for a in atoms], dtype=np.float32)
176
+
177
+ # Add bonds
178
+ if include_bonds:
179
+ bond_array = np.array(
180
+ [[b.index[0], b.index[1], _BIOTITE_BOND_TYPES[b.order]] for b in bonds],
181
+ dtype=np.uint32,
182
+ )
183
+ atom_array.bonds = struc.BondList(len(atoms), bond_array)
184
+
185
+ return atom_array